diff options
Diffstat (limited to 'src/api.c')
-rw-r--r-- | src/api.c | 109 |
1 files changed, 59 insertions, 50 deletions
@@ -44,7 +44,8 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re pass->packet = atoi(ctx->buf); break; case DC_JSON_PING: - pass->api_io.client->ping_interval = atoi(ctx->buf); + fprintf(stderr, "found ping interval %d\n", atoi(ctx->buf)/1000-5); + pass->api_io.client->ping_interval = atoi(ctx->buf)/1000-5; break; default: /* to prevent warning: enumeration value DC_JSON_* not handled */ break; @@ -60,43 +61,41 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re pass->api_io.type = DC_API_USER; dc_api_stack(pass->api_io); /* inform api user */ } - if (reason & LEJP_FLAG_CB_IS_VALUE) - switch (cp[0]) { /* email is already set from login */ + if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0]) + switch (cp[1]) { /* email is already set from login */ case 'u': /* sername */ - free(client->user->username); - client->user->username = strdup(ctx->buf); + if (!client->user->username) client->user->username = strdup(ctx->buf); break; case 'i': /* d */ - client->user->id = strtoull(ctx->buf, NULL, 10); + if (!client->user->id) client->user->id = strtoull(ctx->buf, NULL, 10); break; - case 'd': /* iscriminator */ - client->user->discriminator = atoi(ctx->buf); + case 'd': /* iscriminator */ /* check is for id, discriminator may b 0 */ + if (!client->user->id) client->user->discriminator = atoi(ctx->buf); break; } } - if ((cp == startswith(ctx->path, dc_json_paths[DC_JSON_FRIEND]))) { + if ((cp = startswith(ctx->path, dc_json_paths[DC_JSON_FRIEND]))) { if (!client->user) /* for the client user */ client->user = dc_user_init(); - struct dc_user * user = client->user->next; /* client->user->next is 1. friend */ if (reason == LEJPCB_OBJECT_START) { /* DC_JSON_FRIEND may not be an object*/ if (!pass->api_io.user) /* for the newly found friend (-; */ pass->api_io.user = dc_user_init(); pass->api_io.user->status &= ~(DC_IN_PROGRESS); /* if we never get here again */ - } else { - free(pass->api_io.user); /* just in case */ - pass->api_io.user = NULL; } if (reason == LEJPCB_OBJECT_END) { - while (user->next) + fprintf(stderr, "got a new friend (: %s#%d %llu", pass->api_io.user->username ? pass->api_io.user->username : "NULL", pass->api_io.user->discriminator, pass->api_io.user->id); + struct dc_user * user = client->user; /* client->user->next is 1. friend */ + while (user->next) /* traverse to last friend */ user = user->next; DC_MR(program->users); - program->users[program->users_length++] = user = user->next = pass->api_io.user; + program->users[program->users_length++] = user->next = pass->api_io.user; pass->api_io.user->status &= ~(DC_IN_PROGRESS); pass->api_io.type = DC_API_USER; dc_api_stack(pass->api_io); /* inform api user */ + pass->api_io.user = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */ } - if (reason & LEJP_FLAG_CB_IS_VALUE) - switch(cp[0]) { + if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0]) + switch(cp[1]) { case 'u': /* sername */ free(pass->api_io.user->username); /* yup, we don't trust serv */ pass->api_io.user->username = strdup(ctx->buf); @@ -176,9 +175,6 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, return 1; } lws_client_http_body_pending(wsi, 0); - if (pass->api_io.status & DC_MUST_FREE) - free(pass->body); - pass->body = NULL; pass->body_length = 0; break; case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: @@ -200,16 +196,11 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, #endif break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: /* chunked body, without headers */ - fprintf(stderr, "RECEIVE_CLIENT_HTTP_READ: read %d\n", len); - lwsl_hexdump_notice(in, len); /* for debugging purposes, kek */ - if (!(pass->api_io.status & DC_MUST_FREE)) { /* we start filling the ->body */ - pass->api_io.status |= DC_MUST_FREE; /* buffer, on end of wsi session */ - pass->body = NULL; /* dc_api_i is called from DC_CALLBACK_WSI_DESTROY */ - } /* if ->body from input was not freed and it should be, res body is appended */ - pass->body_length += len; /* if ->body was static, pointer is changed to NULL */ - pass->body = realloc(pass->body, pass->body_length + 1); /* normally - no edge */ - memcpy(pass->body+pass->body_length-len, in, len); /* case - resp body will be */ - pass->body[pass->body_length] = '\0'; /* on heap and freed on _DESTROY. */ + fprintf(stderr, "RECEIVE_CLIENT_HTTP_READ: read %d, current pass->body_length %d\n", len, pass->body_length); + pass->body = realloc(pass->body, pass->body_length + len + 1); + memcpy(pass->body+pass->body_length, in, len); + pass->body[(pass->body_length += len)] = '\0'; + fprintf(stderr, "contents of pass->body: %s\n", pass->body); return 0; /* don't pass to lws_callback_http_dummy */ case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: /* uninterpreted http content */ ; @@ -229,12 +220,12 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, case LWS_CALLBACK_WSI_DESTROY: /* if I understand the docs correctly, this is allways */ if (pass->api_io.pass != pass) fprintf(stderr, "[!!!] REPORT THIS BUG: pass->api_io.pass != pass\n"); - pass->api_io.status |= DC_FROM_LWS; - dc_api_i(pass->api_io); - pass->api_io.status &= ~DC_FROM_LWS; - fprintf(stderr, "pass before freed is %p\n", (void *) pass); - if (pass->api_io.status & DC_MUST_FREE) /* we still do this check in case */ - free(pass->body); /* _READ was not called and pointer was static */ + if (pass->api_io.status & DC_DESTROY_CB) { + pass->api_io.status |= DC_FROM_LWS; + dc_api_i(pass->api_io); + pass->api_io.status &= ~DC_FROM_LWS; + } + free(pass->body); /* body is always allocated on heap! */ pass->api_io.client->pass = NULL; free(pass); /* called at the final moment when user pointer and wsi is still */ break; /* accessible - we can free the struct that was passed in as a heap ptr */ @@ -252,6 +243,16 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, dc_api_i(pass->api_io); pass->api_io.status &= ~DC_FROM_LWS; break; + case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: + pass->reason = 0; + if (len < 2) + fprintf(stderr, "SERVER CLOSED CONNECTION WITHOUT PROIVIDING REASON!\n"); + else + pass->reason = ntohs(*(uint16_t *) in /* i sure hope this is legal */); + fprintf(stderr, "SERVER CLOSED CONNECTION WITH REASON %d\n", pass->reason); + if (len > 2) + fprintf(stderr, "with additional message: %.*s\n", len-2, (char *) in+2); + break; case LWS_CALLBACK_CLIENT_CLOSED: /* websocket closed */ DC_API_IO_GC(pass->api_io); /* frees all unfinished parsing objects */ pass->packet = DC_NONE; @@ -262,8 +263,8 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, pass->api_io.status &= ~DC_FROM_LWS; break; case LWS_CALLBACK_CLIENT_RECEIVE: /* websocket receive, pass to json parser ? */ - fprintf(stdout, "%.*s", len, (const unsigned char *) in); - fflush(stdout); + if (getenv("DC_N")) + fprintf(stdout, "%.*s", len, (const unsigned char *) in); if (pass->json_reason == LEJPCB_COMPLETE || pass->json_reason == LEJPCB_FAILED || !(pass->api_io.status & DC_LEJP_CONSTRUCTED)) { /* we regenerate a new context in case we didn't do that yet or in case the previous one finished parsing */ pass->api_io.status |= DC_LEJP_CONSTRUCTED; pass->packet = DC_NONE; @@ -274,13 +275,19 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, lejp_parse(&pass->json_ctx, (const unsigned char *) in, len); break; case LWS_CALLBACK_CLIENT_WRITEABLE: /* invoke with lws_callback_on_writeable(wsi) 4 ws */ - memcpy(buf+LWS_PRE, pass->body, pass->body_length); - (buf+LWS_PRE)[pass->body_length] = '\0'; - lwsl_hexdump_notice(buf+LWS_PRE, pass->body_length); - if (lws_write(wsi, (unsigned char *) buf+LWS_PRE, pass->body_length, LWS_WRITE_BINARY) != (int) pass->body_length) { + if (!pass->api_io.client) + break; + if (!pass->api_io.client->payloads_length) + break; + char * body = pass->api_io.client->payloads[--pass->api_io.client->payloads_length]->body; + size_t length = pass->api_io.client->payloads[pass->api_io.client->payloads_length]->length; + fprintf(stderr, "going to write to ws: %.*s\n", length, body); + if (lws_write(wsi, (unsigned char *) body, length, LWS_WRITE_BINARY) != (int) length) { /* body already has LWS_PRE bytes allocated before it */ fprintf(stderr, "ws lws_write failed!\n"); return -1; } + dc_payload_free(pass->api_io.client->payloads[pass->api_io.client->payloads_length]); + pass->api_io.client->payloads[pass->api_io.client->payloads_length] = NULL; /* dc_ws_pop(); */ break; default: break; @@ -319,7 +326,7 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun info.method = "POST"; pass = calloc(1, sizeof(struct dc_lws_pass)); /* cb frees */ fprintf(stderr, "allocated pass at %p\n", (void *) pass); - i.status |= DC_MUST_FREE; + i.status |= DC_DESTROY_CB; /* so that lws_cb will call api on destroy - fin rq */ pass->body_length = smprintf(&pass->body, DC_LOGIN_FORMAT, i.client->email, i.client->password); fprintf(stderr, "length: %u string: %s\n", pass->body_length, pass->body); i.type = DC_API_LOGIN_CB; @@ -385,6 +392,7 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun pass = calloc(1, sizeof(struct dc_lws_pass)); i.type = DC_API_WS_CB; i.status |= DC_SET_PASS; + i.status &= ~DC_DESTROY_CB; /* this is only for http requests */ memcpy(&pass->api_io, &i, sizeof(i)); pass->api_io.pass = pass; info.userdata = pass; @@ -400,14 +408,13 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun case DC_API_WS_CB: i.client->status &= ~(DC_NET_ERROR | DC_OK); i.client->status |= i.status; - if (i.status & DC_NET_ERROR) + if (i.status & DC_NET_ERROR) { /* pass and pass->body were freed on _DESTROY */ fprintf(stderr, "websocket connection was closed by the remote host\n"); - else { /* commerce identify */ - if (i.pass->api_io.status & DC_MUST_FREE) - free(i.pass->body); - i.pass->api_io.status |= DC_MUST_FREE; - i.pass->body_length = smprintf(&i.pass->body, DC_IDENTIFY_FORMAT, i.client->authorization, DC_INTENTS); - lws_callback_on_writable(i.pass->wsi); + i.pass = NULL; /* pass was/will be freed on _DESTROY, discard it! */ + } else { /* commerce identify */ + struct dc_payload * p = calloc(1, sizeof(struct dc_payload)); + p->length = smprintf(&p->body, DC_IDENTIFY_FORMAT, i.client->authorization, DC_INTENTS); /* body buffer to identify packet */ + dc_ws_stack(i.client, p); } dc_api_stack(i); /* cl.stat is either NET_ERROR 4 closed or error or OK 4 esta */ break; @@ -438,6 +445,8 @@ struct dc_api_io dc_api_o (struct dc_api_io i /* for ->program */) { if (i.program->api_ios_length) { memcpy(&o, (i.program->api_ios[--i.program->api_ios_length]), sizeof(o)); dc_api_io_free(i.program->api_ios[i.program->api_ios_length]); + i.program->api_ios[i.program->api_ios_length] = NULL; + } int is_broken = 0; for (size_t j = 0; j < i.program->attached_functions_length; j++) { /* call attached functions */ |