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"