libdiscord

libdiscord.git
git clone git://git.lenczewski.org/libdiscord.git
Log | Files | Refs | README | LICENSE

libdiscord.c (3151B)


      1 #include "internal.h"
      2 
      3 size_t
      4 discord_sizeof(void)
      5 {
      6 	return sizeof(struct discord);
      7 }
      8 
      9 static SSL_CTX *
     10 create_ssl_ctx(void)
     11 {
     12 	SSL_CTX *ctx;
     13 	if (!(ctx = SSL_CTX_new(TLS_method())))
     14 		return NULL;
     15 
     16 	SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
     17 	SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
     18 
     19 	if (!SSL_CTX_set_default_verify_paths(ctx))
     20 		goto error;
     21 
     22 	return ctx;
     23 
     24 error:
     25 	SSL_CTX_free(ctx);
     26 
     27 	return NULL;
     28 }
     29 
     30 int
     31 discord_init(struct discord *ctx, void *mem, size_t cap)
     32 {
     33 	memset(ctx, 0, discord_sizeof());
     34 
     35 	ctx->arena.ptr = mem;
     36 	ctx->arena.cap = cap;
     37 	arena_reset(&ctx->arena);
     38 
     39 	unsigned entries = 32, flags = 0;
     40 	if (io_uring_queue_init(entries, &ctx->io_uring, flags) < 0)
     41 		return -1;
     42 
     43 	if (!(ctx->ssl_ctx = create_ssl_ctx())) {
     44 		io_uring_queue_exit(&ctx->io_uring);
     45 		return -1;
     46 	}
     47 
     48 	return 0;
     49 }
     50 
     51 void
     52 discord_free(struct discord *ctx)
     53 {
     54 	SSL_shutdown(ctx->gateway.conn.ssl);
     55 	SSL_free(ctx->gateway.conn.ssl);
     56 	BIO_free(ctx->gateway.conn.net_bio);
     57 
     58 	SSL_shutdown(ctx->voice.conn.ssl);
     59 	SSL_free(ctx->voice.conn.ssl);
     60 	BIO_free(ctx->voice.conn.net_bio);
     61 
     62 	io_uring_queue_exit(&ctx->io_uring);
     63 
     64 	SSL_CTX_free(ctx->ssl_ctx);
     65 }
     66 
     67 static SSL *
     68 create_ssl(SSL_CTX *ctx, BIO **ssl_bio, BIO **net_bio, size_t bufsz,
     69 	   char const *host)
     70 {
     71 	SSL *ssl;
     72 	if (!(ssl = SSL_new(ctx)))
     73 		return NULL;
     74 
     75 	SSL_set_connect_state(ssl);
     76 	SSL_set_tlsext_host_name(ssl, host);
     77 	SSL_set1_host(ssl, host);
     78 
     79 	if (BIO_new_bio_pair(ssl_bio, bufsz, net_bio, bufsz) < 0)
     80 		goto error;
     81 
     82 	SSL_set_bio(ssl, *ssl_bio, *ssl_bio);
     83 
     84 	return ssl;
     85 
     86 error:
     87 	SSL_free(ssl);
     88 
     89 	return NULL;
     90 }
     91 
     92 int
     93 discord_connect_gateway(struct discord *ctx)
     94 {
     95 	static struct conn_ops gateway_ops = {
     96 		.on_connect = gateway_on_connect,
     97 		.on_tls_handshake = gateway_on_tls_handshake,
     98 		.on_close = gateway_on_close,
     99 		.on_recv = gateway_on_recv,
    100 		.on_send = gateway_on_send,
    101 	};
    102 
    103 	struct conn *conn = &ctx->gateway.conn;
    104 
    105 	conn->ssl = create_ssl(ctx->ssl_ctx,
    106 			       &conn->ssl_bio, &conn->net_bio, conn->cap,
    107 			       GATEWAY_HOST);
    108 
    109 	if (!conn->ssl)
    110 		return -1;
    111 
    112 	conn->buf = ctx->gateway.buf;
    113 	conn->cap = sizeof ctx->gateway.buf;
    114 
    115 	conn->ops = &gateway_ops;
    116 
    117 	return gateway_connect(conn, &ctx->io_uring,
    118 			       GATEWAY_HOST, GATEWAY_PORT);
    119 }
    120 
    121 int
    122 discord_connect_voice(struct discord *ctx)
    123 {
    124 	return -1;
    125 }
    126 
    127 int
    128 discord_poll_events(struct discord *ctx,
    129 		    struct discord_event *evs, size_t cap)
    130 {
    131 	assert(evs);
    132 	assert(cap);
    133 
    134 	int ret = 0, have_ev = 0;
    135 	while (ret >= 0 && !have_ev) {
    136 		io_uring_submit_and_wait(&ctx->io_uring, 1);
    137 
    138 		unsigned head, seen = 0;
    139 		struct io_uring_cqe *cqe;
    140 		io_uring_for_each_cqe(&ctx->io_uring, head, cqe) {
    141 			struct ioreq *ioreq = io_uring_cqe_get_data(cqe);
    142 			assert(ioreq);
    143 
    144 			struct conn *conn = TO_PARENT_PTR(ioreq,
    145 							  struct conn,
    146 							  ioreq);
    147 
    148 			ret = conn_do_io(conn, &ctx->io_uring, cqe->res, evs);
    149 
    150 			seen++;
    151 
    152 			if (ret < 0) /* error */
    153 				break;
    154 
    155 			if (ret == 0) /* more io needed */
    156 				continue;
    157 
    158 			/* have event */
    159 			have_ev = 1;
    160 			evs++;
    161 			cap--;
    162 
    163 			if (!cap)
    164 				break;
    165 		}
    166 
    167 		io_uring_cq_advance(&ctx->io_uring, seen);
    168 	}
    169 
    170 	return ret;
    171 }
    172 
    173 #include "internal.c"
    174 #include "gateway.c"
    175 #include "voice.c"