From b2fc9cbb62c2306b77829f8780088e056036669f Mon Sep 17 00:00:00 2001 From: Florian Stinglmayr Date: Tue, 9 Jul 2019 21:44:23 +0200 Subject: [PATCH] semi working gateway implementation --- libdc/CMakeLists.txt | 2 +- libdc/include/dc/api.h | 5 - libdc/include/dc/gateway.h | 34 +++-- libdc/src/api.c | 97 +------------ libdc/src/gateway.c | 291 ++++++++++++++++++++++++------------- libdc/src/internal.h | 9 +- libdc/src/loop.c | 53 +++++-- ncdc/src/login.c | 3 +- 8 files changed, 261 insertions(+), 233 deletions(-) diff --git a/libdc/CMakeLists.txt b/libdc/CMakeLists.txt index b1dd184..ecee617 100644 --- a/libdc/CMakeLists.txt +++ b/libdc/CMakeLists.txt @@ -29,10 +29,10 @@ SET(SOURCES "src/gateway.c" "src/guild.c" "src/loop.c" - "src/masking.c" "src/message.c" "src/refable.c" "src/util.c" + "src/ws-frames.c" ) INCLUDE_DIRECTORIES("include" diff --git a/libdc/include/dc/api.h b/libdc/include/dc/api.h index b9d9518..5a90fd9 100644 --- a/libdc/include/dc/api.h +++ b/libdc/include/dc/api.h @@ -36,11 +36,6 @@ json_t *dc_api_call_sync(dc_api_t api, char const *token, char const *verb, char const *method, json_t *j); -/** - * Establish a GATEWAY to the discord servers. - */ -dc_gateway_t dc_api_establish_gateway(dc_api_t api, dc_account_t login); - /** * Authenticate a given user account. The user account should have * email, and password set. If the auth succeeds the account will have diff --git a/libdc/include/dc/gateway.h b/libdc/include/dc/gateway.h index b6ad9b9..ae18e16 100644 --- a/libdc/include/dc/gateway.h +++ b/libdc/include/dc/gateway.h @@ -12,34 +12,36 @@ struct dc_gateway_; typedef struct dc_gateway_ *dc_gateway_t; typedef enum { - GATEWAY_OPCODE_HEARTBEAT = 1, + GATEWAY_OPCODE_PING = 1, GATEWAY_OPCODE_IDENTIFY = 2, + GATEWAY_OPCODE_UPDATE = 3, GATEWAY_OPCODE_HELLO = 10, + GATEWAY_OPCODE_PONG = 11, } dc_gateway_opcode_t; +typedef enum { + GATEWAY_FRAME_TEXT_DATA = 129, + GATEWAY_FRAME_DISCONNECT = 136, + GATEWAY_FRAME_PING = 137, + GATEWAY_FRAME_PONG = 138, +} dc_gateway_frames_t; + dc_gateway_t dc_gateway_new(void); void dc_gateway_set_login(dc_gateway_t gw, dc_account_t login); -/** - * Set all required CURL handles. The object will delete the easy handle - * and make sure it is removed from the multi handle upon unref. Do not - * free the multi handle before you remove the gateway. - */ -void dc_gateway_set_curl(dc_gateway_t gw, CURLM *multi, CURL *easy); - -CURL *dc_gateway_curl(dc_gateway_t gw); +bool dc_gateway_connect(dc_gateway_t gw); /** - * Returns a CURL slist that lasts as long as the handle itself lasts + * Cleans up the easy handle, and thus disconnects from the socket handle + * immediately. After this call dc_gateway_connected() will return false. */ -struct curl_slist * dc_gateway_slist(dc_gateway_t gw); +void dc_gateway_disconnect(dc_gateway_t gw); /** - * To be used as a WRITEFUNCTION for a curl handle. Don't forget to set the - * gateway handle as a WRITEDATA too, otherwise this will have no effect. + * Returns true if the gateway is still connected. */ -size_t dc_gateway_writefunc(char *ptr, size_t sz, size_t nmemb, void *data); +bool dc_gateway_connected(dc_gateway_t gw); /** * Process the queue of data that came from the websocket. @@ -53,4 +55,8 @@ uint8_t * dc_gateway_makeframe(uint8_t const *d, size_t data_len, uint8_t type, size_t *outlen); +size_t +dc_gateway_parseframe(uint8_t const *data, size_t datalen, + uint8_t *type, uint8_t **outdata, size_t *outlen); + #endif diff --git a/libdc/src/api.c b/libdc/src/api.c index c7b094b..937f11c 100644 --- a/libdc/src/api.c +++ b/libdc/src/api.c @@ -2,11 +2,6 @@ #include #include "internal.h" -#define DISCORD_URL "https://discordapp.com/api/v6" -#define DISCORD_GATEWAY "https://gateway.discord.gg/?encoding=json&v=6" - -#define DISCORD_USERAGENT "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0" - struct dc_api_ { dc_refable_t ref; @@ -79,6 +74,7 @@ void dc_api_signal(dc_api_t api, CURL *easy, int code) } } +#ifdef DEBUG int debug_callback(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr) @@ -100,6 +96,7 @@ int debug_callback(CURL *handle, curl_infotype type, return 0; } +#endif static dc_api_sync_t dc_api_do(dc_api_t api, char const *verb, @@ -235,10 +232,6 @@ json_t *dc_api_call_sync(dc_api_t api, char const *token, goto cleanup; } -#ifdef DEBUG - printf("api_call_sync: %d\n", dc_api_sync_code(s)); -#endif - reply = json_loadb(dc_api_sync_data(s), dc_api_sync_datalen(s), 0, NULL @@ -277,89 +270,3 @@ bool dc_api_error(json_t *j, int *code, char const **message) return error; } - -static size_t stall_connection(char *buffer, size_t size, size_t nitems, - void *userdata) -{ - CURL *easy = (CURL *)userdata; - - if (strncmp(buffer, "\r\n", size) == 0) { - curl_easy_setopt(easy, CURLOPT_CONNECT_ONLY, 1); - //curl_easy_pause(easy, CURLPAUSE_ALL); - curl_easy_setopt(easy, CURLOPT_FORBID_REUSE, 1); - } - - return size * nitems; -} - -dc_gateway_t dc_api_establish_gateway(dc_api_t api, dc_account_t login) -{ - return_if_true(api == NULL, NULL); - return_if_true(api->curl == NULL, NULL); - return_if_true(login == NULL || !dc_account_has_token(login), NULL); - - CURL *c = NULL; - struct curl_slist *list = NULL; - /* BE THE BROKEN OR THE BREAKER - */ - dc_gateway_t gw = NULL; - dc_gateway_t ret = NULL; - - c = curl_easy_init(); - goto_if_true(c == NULL, cleanup); - - gw = dc_gateway_new(); - goto_if_true(gw == NULL, cleanup); - - curl_easy_setopt(c, CURLOPT_URL, DISCORD_GATEWAY); - - list = dc_gateway_slist(gw); - curl_slist_append(list, "Content-Type: application/json"); - curl_slist_append(list, "Accept: application/json"); - curl_slist_append(list, "User-Agent: " DISCORD_USERAGENT); - curl_slist_append(list, "Pragma: no-cache"); - curl_slist_append(list, "Cache-Control: no-cache"); - curl_slist_append(list, "Sec-WebSocket-Key: cbYK1Jm6cpk3Rua"); - curl_slist_append(list, "Sec-WebSocket-Version: 13"); - curl_slist_append(list, "Upgrade: websocket"); - - curl_easy_setopt(c, CURLOPT_HEADERFUNCTION, stall_connection); - curl_easy_setopt(c, CURLOPT_HEADERDATA, c); - - curl_easy_setopt(c, CURLOPT_HTTPHEADER, list); - - curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1L); - curl_easy_setopt(c, CURLOPT_TCP_KEEPIDLE, 120L); - curl_easy_setopt(c, CURLOPT_TCP_KEEPINTVL, 60L); - - curl_easy_setopt(c, CURLOPT_FORBID_REUSE, 1L); - curl_easy_setopt(c, CURLOPT_FRESH_CONNECT, 1L); - - curl_easy_setopt(c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); - - curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, dc_gateway_writefunc); - curl_easy_setopt(c, CURLOPT_WRITEDATA, gw); - - dc_gateway_set_login(gw, login); - dc_gateway_set_curl(gw, api->curl, c); - - if (curl_multi_add_handle(api->curl, c) != CURLM_OK) { - goto cleanup; - } - - c = NULL; - - ret = gw; - gw = NULL; - -cleanup: - - if (c != NULL) { - curl_easy_cleanup(c); - } - - dc_unref(gw); - - return ret; -} diff --git a/libdc/src/gateway.c b/libdc/src/gateway.c index 8faef00..39aafa8 100644 --- a/libdc/src/gateway.c +++ b/libdc/src/gateway.c @@ -10,9 +10,7 @@ struct dc_gateway_ GPtrArray *out; GByteArray *buffer; - CURLM *multi; CURL *easy; - struct curl_slist *slist; dc_account_t login; @@ -24,11 +22,6 @@ static void dc_gateway_free(dc_gateway_t g) { return_if_true(g == NULL,); - if (g->buffer != NULL) { - g_byte_array_unref(g->buffer); - g->buffer = NULL; - } - if (g->ops != NULL) { g_ptr_array_unref(g->ops); g->ops = NULL; @@ -39,15 +32,9 @@ static void dc_gateway_free(dc_gateway_t g) g->out = NULL; } - if (g->easy != NULL) { - curl_multi_remove_handle(g->multi, g->easy); - curl_easy_cleanup(g->easy); - g->easy = NULL; - } - - if (g->slist != NULL) { - curl_slist_free_all(g->slist); - g->slist = NULL; + if (g->buffer != NULL) { + g_byte_array_unref(g->buffer); + g->buffer = NULL; } dc_unref(g->login); @@ -62,17 +49,14 @@ dc_gateway_t dc_gateway_new(void) g->ref.cleanup = (dc_cleanup_t)dc_gateway_free; - g->buffer = g_byte_array_new(); - goto_if_true(g->buffer == NULL, error); - g->ops = g_ptr_array_new_with_free_func((GDestroyNotify)json_decref); goto_if_true(g->ops == NULL, error); g->out = g_ptr_array_new_with_free_func((GDestroyNotify)json_decref); goto_if_true(g->out == NULL, error); - g->slist = curl_slist_append(NULL, ""); - goto_if_true(g->slist == NULL, error); + g->buffer = g_byte_array_new(); + goto_if_true(g->buffer == NULL, error); return dc_ref(g); @@ -88,48 +72,76 @@ void dc_gateway_set_login(dc_gateway_t gw, dc_account_t login) gw->login = dc_ref(login); } -void dc_gateway_set_curl(dc_gateway_t gw, CURLM *multi, CURL *easy) +bool dc_gateway_connect(dc_gateway_t gw) { - return_if_true(gw == NULL,); - gw->multi = multi; - gw->easy = easy; -} + return_if_true(gw == NULL || gw->easy != NULL, true); -CURL *dc_gateway_curl(dc_gateway_t gw) -{ - return_if_true(gw == NULL, NULL); - return gw->easy; -} + char header[1000] = {0}; + size_t outlen = 0; + int r = 0; -struct curl_slist * dc_gateway_slist(dc_gateway_t gw) -{ - return_if_true(gw == NULL, NULL); - return gw->slist; -} + gw->easy = curl_easy_init(); + goto_if_true(gw->easy == NULL, error); -size_t dc_gateway_writefunc(char *ptr, size_t sz, size_t nmemb, void *data) -{ - dc_gateway_t g = (dc_gateway_t)data; - json_t *j = NULL; - size_t i = 0; + curl_easy_setopt(gw->easy, CURLOPT_URL, DISCORD_GATEWAY); + curl_easy_setopt(gw->easy, CURLOPT_FRESH_CONNECT, 1L); + curl_easy_setopt(gw->easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt(gw->easy, CURLOPT_CONNECT_ONLY, 1L); - FILE *f = fopen("websocket.txt", "a+"); - fprintf(f, ">> "); - fwrite(ptr, sz, nmemb, f); - fprintf(f, "\n"); - fclose(f); + goto_if_true(curl_easy_perform(gw->easy) != CURLE_OK, error); - for (i = 0; *ptr != '{' && i < (sz *nmemb); ptr++, i++) - ; + snprintf(header, sizeof(header)-1, + "GET %s HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: %s\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n" + "Sec-WebSocket-Key: cbYK1Jm6cpk3Rua\r\n" + "Sec-WebSocket-Version: 13\r\n" + "Upgrade: websocket\r\n" + "\r\n", + DISCORD_GATEWAY_URL, + DISCORD_GATEWAY_HOST, + DISCORD_USERAGENT + ); - if (i < (sz * nmemb)) { - j = json_loadb(ptr, (sz*nmemb) - i, JSON_DISABLE_EOF_CHECK, NULL); - if (j != NULL) { - g_ptr_array_add(g->ops, j); + r = curl_easy_send(gw->easy, header, strlen(header), &outlen); + goto_if_true(r != CURLE_OK || outlen != strlen(header), error); + + do { + r = curl_easy_recv(gw->easy, header, sizeof(header), &outlen); + if (r == CURLE_OK && outlen > 0) { + break; } - } + if (r != CURLE_AGAIN) { + goto error; + } + } while (true); - return sz * nmemb; + goto_if_true(strstr(header, "HTTP/1.1 101") == NULL, error); + + return true; + +error: + + curl_easy_cleanup(gw->easy); + gw->easy = NULL; + + return false; +} + +void dc_gateway_disconnect(dc_gateway_t gw) +{ + return_if_true(gw == NULL || gw->easy == NULL,); + + curl_easy_cleanup(gw->easy); + gw->easy = NULL; +} + +bool dc_gateway_connected(dc_gateway_t gw) +{ + return_if_true(gw == NULL || gw->easy == NULL, false); + return true; } static json_t *dc_gateway_answer(dc_gateway_t gw) @@ -169,10 +181,31 @@ static void dc_gateway_queue(dc_gateway_t gw, int code, json_t *d) static void dc_gateway_queue_heartbeat(dc_gateway_t gw) { - dc_gateway_queue(gw, GATEWAY_OPCODE_HEARTBEAT, NULL); + dc_gateway_queue(gw, GATEWAY_OPCODE_PING, NULL); gw->last_heartbeat = time(NULL); } +static void dc_gateway_queue_identify(dc_gateway_t gw) +{ + json_t *j = json_object(), *dev = json_object(); + char const *token = dc_account_token(gw->login); + + if (j == NULL || dev == NULL) { + json_decref(j); + json_decref(dev); + return; + } + + json_object_set_new(dev, "$os", json_string("linux")); + json_object_set_new(dev, "$browser", json_string("libdc")); + json_object_set_new(dev, "$device", json_string("libdc")); + + json_object_set_new(j, "token", json_string(token)); + json_object_set_new(j, "properties", dev); + + dc_gateway_queue(gw, GATEWAY_OPCODE_IDENTIFY, j); +} + static bool dc_gateway_handle_hello(dc_gateway_t gw, json_t *d) { json_t *val = NULL; @@ -182,7 +215,7 @@ static bool dc_gateway_handle_hello(dc_gateway_t gw, json_t *d) /* send an identify first */ - dc_gateway_queue(gw, GATEWAY_OPCODE_IDENTIFY, NULL); + dc_gateway_queue_identify(gw); gw->heartbeat_interval = json_integer_value(val); dc_gateway_queue_heartbeat(gw); @@ -190,6 +223,11 @@ static bool dc_gateway_handle_hello(dc_gateway_t gw, json_t *d) return true; } +static bool dc_gateway_handle_update(dc_gateway_t gw, json_t *d) +{ + return true; +} + static bool dc_gateway_handle_op(dc_gateway_t gw, json_t *j) { json_t *val = NULL; @@ -204,42 +242,71 @@ static bool dc_gateway_handle_op(dc_gateway_t gw, json_t *j) switch (op) { case GATEWAY_OPCODE_HELLO: dc_gateway_handle_hello(gw, val); break; + case GATEWAY_OPCODE_UPDATE: dc_gateway_handle_update(gw, val); break; + case GATEWAY_OPCODE_PONG: break; default: break; } return true; } -#if 0 static void dc_gateway_process_read(dc_gateway_t gw) { - char buf[100] = {0}; - size_t read = 0; int ret = 0; - FILE *f = NULL; - json_t *j = NULL; - size_t where = 0; + char buf[100] = {0}; + size_t outlen = 0; - ret = curl_easy_recv(gw->easy, &buf, sizeof(buf), &read); - return_if_true(ret != CURLE_OK,); + return_if_true(gw->easy == NULL,); - g_byte_array_append(gw->buffer, (uint8_t const*)buf, read); - - f = fmemopen(gw->buffer->data, gw->buffer->len, "r"); - return_if_true(f == NULL,); - - j = json_loadf(f, JSON_DISABLE_EOF_CHECK, NULL); - where = ftell(f); - - fclose(f); - f = NULL; - - if (j != NULL) { - g_ptr_array_add(gw->ops, j); - g_byte_array_remove_range(gw->buffer, 0, where); - } + do { + ret = curl_easy_recv(gw->easy, buf, sizeof(buf), &outlen); + if (ret == CURLE_OK && outlen > 0) { + FILE *f = fopen("output.txt", "a+"); + fwrite(buf, outlen, sizeof(char), f); + fputc('\n', f); + fclose(f); + g_byte_array_append(gw->buffer, (uint8_t const*)buf, outlen); + } + } while (ret == CURLE_OK && outlen > 0); +} + +static void dc_gateway_process_frame(dc_gateway_t gw) +{ + size_t ret = 0; + uint8_t *data = NULL; + size_t datalen = 0; + uint8_t type = 0; + + ret = dc_gateway_parseframe(gw->buffer->data, gw->buffer->len, + &type, &data, &datalen + ); + return_if_true(ret == 0,); + + g_byte_array_remove_range(gw->buffer, 0, ret); + + switch (type) { + case GATEWAY_FRAME_TEXT_DATA: + { + json_t *j = NULL; + + j = json_loadb((char const*)data, datalen, + JSON_DISABLE_EOF_CHECK, NULL); + if (j != NULL) { + g_ptr_array_add(gw->ops, j); + } + } break; + + case GATEWAY_FRAME_DISCONNECT: + { + dc_gateway_disconnect(gw); + } break; + + } + + free(data); + data = NULL; + datalen = 0; } -#endif static void dc_gateway_process_in(dc_gateway_t gw) { @@ -250,38 +317,47 @@ static void dc_gateway_process_in(dc_gateway_t gw) } } -static void dc_gateway_process_out(dc_gateway_t gw) +static bool dc_gateway_process_out(dc_gateway_t gw, json_t *j) { char *str = NULL; - size_t slen = 0, outlen = 0, sent = 0; uint8_t *mask = NULL; + size_t outlen = 0, outlen2 = 0; + int ret = 0; + bool r = false; - while (gw->out->len > 0) { - json_t *j = g_ptr_array_index(gw->out, 0); + str = json_dumps(j, JSON_COMPACT); + goto_if_true(str == NULL, cleanup); - str = json_dumps(j, JSON_COMPACT); + mask = dc_gateway_makeframe((uint8_t const *)str, strlen(str), + GATEWAY_FRAME_TEXT_DATA, + &outlen + ); + goto_if_true(mask == NULL, cleanup); - if (str != NULL) { - slen = strlen(str); - mask = dc_gateway_makeframe((uint8_t const *)str, slen, 0, &outlen); - curl_easy_send(gw->easy, mask, outlen, &sent); + ret = curl_easy_send(gw->easy, mask, outlen, &outlen2); + goto_if_true(ret != CURLE_OK || outlen2 != outlen, cleanup); - FILE *f = fopen("websocket.txt", "a+"); - fprintf(f, "<< %s\n", str); - fclose(f); - } + r = true; - free(str); - free(mask); +cleanup: - g_ptr_array_remove_index(gw->out, 0); - } + free(str); + str = NULL; + + free(mask); + mask = NULL; + + return r; } void dc_gateway_process(dc_gateway_t gw) { time_t diff = 0; + if (!dc_gateway_connected(gw)) { + return; + } + if (gw->heartbeat_interval > 0) { diff = time(NULL) - gw->last_heartbeat; if (diff >= (gw->heartbeat_interval / 1000)) { @@ -289,7 +365,22 @@ void dc_gateway_process(dc_gateway_t gw) } } - //dc_gateway_process_read(gw); - dc_gateway_process_in(gw); - dc_gateway_process_out(gw); + dc_gateway_process_read(gw); + + if (gw->buffer->len > 0) { + dc_gateway_process_frame(gw); + if (!dc_gateway_connected(gw)) { + return; + } + } + + if (gw->ops->len > 0) { + dc_gateway_process_in(gw); + } + + while (gw->out->len > 0) { + json_t *j = g_ptr_array_index(gw->out, 0); + dc_gateway_process_out(gw, j); + g_ptr_array_remove_index(gw->out, 0); + } } diff --git a/libdc/src/internal.h b/libdc/src/internal.h index 8cc5e7e..8ce5ca2 100644 --- a/libdc/src/internal.h +++ b/libdc/src/internal.h @@ -25,11 +25,18 @@ #include #include -//#define DEBUG +#define DEBUG #define return_if_true(v,r) do { if (v) return r; } while(0) #define goto_if_true(v,l) do { if (v) goto l; } while(0) #define TOKEN(l) (dc_account_token(l)) +#define DISCORD_URL "https://discordapp.com/api/v6" +#define DISCORD_GATEWAY_URL "/?encoding=json&v=6" +#define DISCORD_GATEWAY_HOST "gateway.discord.gg" +#define DISCORD_GATEWAY "https://" DISCORD_GATEWAY_HOST DISCORD_GATEWAY_URL + +#define DISCORD_USERAGENT "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0" + #endif diff --git a/libdc/src/loop.c b/libdc/src/loop.c index 742c2b0..4df2eae 100644 --- a/libdc/src/loop.c +++ b/libdc/src/loop.c @@ -18,6 +18,24 @@ struct dc_loop_ GPtrArray *gateways; }; +typedef struct { + dc_gateway_t gateway; + struct event *event; +} dc_loop_gateway_t; + +static void dc_loop_gateway_free(dc_loop_gateway_t *p) +{ + return_if_true(p == NULL,); + + if (p->event != NULL) { + event_del(p->event); + event_free(p->event); + } + + dc_unref(p->gateway); + free(p); +} + static void dc_loop_free(dc_loop_t p) { return_if_true(p == NULL,); @@ -69,18 +87,6 @@ mcurl_handler(CURL *easy, curl_socket_t s, int what, void *userp, void *socketp) struct event *event = (struct event *)socketp; dc_loop_t loop = (dc_loop_t)userp; - for (size_t i = 0; i < loop->gateways->len; i++) { - dc_gateway_t gw = g_ptr_array_index(loop->gateways, i); - - if (dc_gateway_curl(gw) == easy) { - printf("gateway event: %s: %s%s\n", - (what == CURL_POLL_REMOVE ? "remove" : "add"), - ((what & CURL_POLL_IN) ? "r" : ""), - ((what & CURL_POLL_OUT) ? "w": "") - ); - } - } - if (what == CURL_POLL_REMOVE) { if (event != NULL) { event_del(event); @@ -169,7 +175,9 @@ dc_loop_t dc_loop_new_full(struct event_base *base, CURLM *multi) ptr->apis = g_ptr_array_new_with_free_func((GDestroyNotify)dc_unref); goto_if_true(ptr->apis == NULL, fail); - ptr->gateways = g_ptr_array_new_with_free_func((GDestroyNotify)dc_unref); + ptr->gateways = g_ptr_array_new_with_free_func( + (GDestroyNotify)dc_loop_gateway_free + ); goto_if_true(ptr->gateways == NULL, fail); ptr->timer = evtimer_new(ptr->base, timer_handler, ptr); @@ -216,7 +224,13 @@ void dc_loop_add_gateway(dc_loop_t l, dc_gateway_t gw) { return_if_true(l == NULL || gw == NULL,); - g_ptr_array_add(l->gateways, dc_ref(gw)); + dc_loop_gateway_t *ptr = calloc(1, sizeof(dc_loop_gateway_t)); + return_if_true(ptr == NULL,); + + ptr->gateway = dc_ref(gw); + ptr->event = NULL; + + g_ptr_array_add(l->gateways, ptr); } void dc_loop_abort(dc_loop_t l) @@ -254,8 +268,15 @@ bool dc_loop_once(dc_loop_t l) } for (i = 0; i < l->gateways->len; i++) { - dc_gateway_t gw = g_ptr_array_index(l->gateways, i); - dc_gateway_process(gw); + dc_loop_gateway_t *ptr = g_ptr_array_index(l->gateways, i); + + if (!dc_gateway_connected(ptr->gateway)) { + if (!dc_gateway_connect(ptr->gateway)) { + continue; + } + } + + dc_gateway_process(ptr->gateway); } return true; diff --git a/ncdc/src/login.c b/ncdc/src/login.c index 22dcfde..a40b999 100644 --- a/ncdc/src/login.c +++ b/ncdc/src/login.c @@ -35,12 +35,13 @@ bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av) goto cleanup; } - gw = dc_api_establish_gateway(api, acc); + gw = dc_gateway_new(); if (gw == NULL) { LOG(n, L"login: %ls: failed to establish gateway", av[1]); goto cleanup; } + dc_gateway_set_login(gw, acc); dc_loop_add_gateway(loop, gw); dc_unref(current_account);