diff options
author | Anton Luka Šijanec <anton@sijanec.eu> | 2021-09-17 14:36:09 +0200 |
---|---|---|
committer | Anton Luka Šijanec <anton@sijanec.eu> | 2021-09-17 14:36:09 +0200 |
commit | 876b012e1aae1cfc9687536edc302987ce899963 (patch) | |
tree | 8ac295bc789cf7eafacd52b9cc45bc433906fe99 /src | |
parent | not tested yet, but added parsing users: myself and friends (diff) | |
download | discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.gz discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.bz2 discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.lz discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.xz discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.zst discord.c-876b012e1aae1cfc9687536edc302987ce899963.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/api.c | 109 | ||||
-rw-r--r-- | src/h.c | 84 | ||||
-rw-r--r-- | src/lib.c | 3 |
3 files changed, 117 insertions, 79 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 */ @@ -4,8 +4,10 @@ #define DC_ALLOC_CHUNK 1 #define DC_REALLOC_K 1.5 #define DC_BIGGER_ARRAY(name) do { /* unlike in previous programs, _BIGGER_ARRAY */ \ - name##_sizeof = ceil(name##_sizeof*DC_REALLOC_K); /* no longer initializes-that'd */ \ - name = realloc(name, sizeof(name[0])*name##_sizeof); /* prevent inserting noninited */ \ + name = realloc(name, sizeof(name[0])*ceil(name##_sizeof*DC_REALLOC_K)); \ + for (int DC_BIGGER_ARRAY_i = name##_sizeof; DC_BIGGER_ARRAY_i < ceil(name##_sizeof*DC_REALLOC_K); DC_BIGGER_ARRAY_i++) \ + name[DC_BIGGER_ARRAY_i] = NULL; \ + name##_sizeof = ceil(name##_sizeof*DC_REALLOC_K); /* no longer initializes */ \ } while (0) /* note that sizeof(name[0]) does not dereferencec name */ #define DC_MR(n) if (n##_sizeof <= n##_length) /* make room */ \ DC_BIGGER_ARRAY(n) @@ -30,14 +32,14 @@ enum dc_status { /* theese are flags and should be and-checked */ DC_RETRY = 1 << 9, /* attached timeout handlers return this so that ->last is not updated */ DC_FROM_LWS = 1 << 10, /* LWS cb is the caller, so do not attempt to do lws_service (loop) */ DC_FROM_API = 1 << 11, /* call originates from API function */ - DC_MUST_FREE = 1 << 12, /* cb pass: body must be freed when request is done with user_data */ - DC_REQUEST_FAILED = 1 << 13, /* http request failed, reported to ui */ - DC_ERROR = 1 << 14, /* unknown error, non implemented non expected response */ - DC_NET_ERROR = 1 << 15, /* network failed or ws closed */ - DC_LEJP_CONSTRUCTED = 1 << 16, /* json parser was constructed */ - DC_SET_PASS = 1 << 17, /* whether _CREATE _cb shall set client->passs. api sets on _WS create */ - DC_IN_PROGRESS = 1 << 18, /* object is in parsing (by json_cb) */ - DC_INTERNAL = DC_FROM_LWS | DC_FROM_API /* call originates from an internal function */ + DC_REQUEST_FAILED = 1 << 12, /* http request failed, reported to ui */ + DC_ERROR = 1 << 13, /* unknown error, non implemented non expected response */ + DC_NET_ERROR = 1 << 14, /* network failed or ws closed */ + DC_LEJP_CONSTRUCTED = 1 << 15, /* json parser was constructed */ + DC_SET_PASS = 1 << 16, /* whether _CREATE _cb shall set client->passs. api sets on _WS create */ + DC_IN_PROGRESS = 1 << 17, /* object is in parsing (by json_cb) */ + DC_DESTROY_CB = 1 << 18, /* wether cb shall call api on DESTROY (used for http responses) */ + DC_INTERNAL = DC_FROM_LWS | DC_FROM_API, /* call originates from an internal function */ }; /* note: when checking status, first check for DC_OK, if it's set then disregard errors! */ enum dc_permissions { /* other permissions exist, but are not implemented/understood */ DC_ALL_PERMISSIONS = 1 << 3, /* this is incredibly retarded, why is this SEPARATE?!? - admins */ @@ -70,7 +72,7 @@ enum dc_api_io_type { /* network requests are sent to the event-based network library immediatley on input. network library is polled for incoming network traffic on each _event call. not totally filled structs in cache are checked and if one is/becomes filled, it will be output. if a role is requested when this role already exists and is searched for (not filled), for example because a channel needs the role to be output or the user created another search for this role before, this search will be dropped and the passed struct will be freed. */ /* this library has internally attached functions for handling many io types so that the library nicely detects when for example a new role is received. the on-role-received function for example checks cache and updates structs that need this role */ /* struct dc_program * serves as a handle for the API. create it with dc_program_init (may return NULL which indicates a LWS init failure) and destroy it with dc_program_free. pass it to every call inside struct dc_api_io.program */ - DC_API_NONE, /* i: N/A */ + DC_API_NONE, /* i: do nothing */ /* o: nothing to output */ DC_API_MESSAGE, /* i: send a message-tr0 or edit a message that was already sent-trp */ /* o: message notification: GUI spawn or respawn if edited. */ @@ -94,7 +96,7 @@ enum dc_api_io_type { /* o: prev passed dc_user but filled (or not: ->status may indicate error) */ DC_API_ROLE, /* i: query for role by id, pass dc_role-tr1 */ /* o: prev passed dc_role but filled (or not: ->status may indicate error) */ - DC_API_ATTACH /* i: attaches function to handle output types */ + DC_API_ATTACH, /* i: attaches function to handle output types */ /* o: N/A */ }; /* do not confuse yourself, when for example login response is checked for errors, check client->status and not struct dc_api_io's member named status. that member is mostly only used internally. */ #define DC_API_TIMEOUT DC_API_NONE /* attached functions with type DC_API_TIMEOUT are called ->every seconds */ @@ -164,14 +166,14 @@ char * dc_json_paths[] = { /* array of paths we are interested in */ "op", "s", "d.heartbeat_interval", - "d.user", + "d.user", /* NOTE: presence updates have same format, so only set own user once */ "d.relationships[].user", "d.private_channels[]" }; struct dc_lws_pass { /* struct that is allocated for in dc_lws_cb unique per connection in void * us */ DC_STRUCT_PREFIX - char * body; /* this contains post body and when _CB is called, it contains response */ - size_t body_length; /* body is NULL terminated or NULL in case of failure */ + char * body; /* this contains post body and when _CB is called, it contains response, HTTP*/ + size_t body_length; /* body is NULL terminated or NULL in case of failure. WS doesn't use this */ char headers[DC_LWS_HEADERS_LENGTH][DC_LWS_MAX_HEADER_LENGTH]; /* nofree, a static 2d array */ int status; /* HTTP response code /\ headers contain request headers, then resp. */ struct dc_api_io api_io; /* so dc_api_io can decide what shall be passed into _CB */ @@ -180,10 +182,32 @@ struct dc_lws_pass { /* struct that is allocated for in dc_lws_cb unique per con struct lws * wsi; /* set on ESTABLISHED and NULLed on CLOSED or ERROR */ enum dc_ws_packet packet; /* what type of packet are we currently handling in lejp */ enum dc_status * parsing_status; /* to remove DC_IN_PROGRESS & signal if call api on COMPL */ + uint16_t reason; /* reason for closing connection */ /* temporary debug things */ char * cp; int len; }; +struct dc_payload { + DC_STRUCT_PREFIX + size_t length; + char * body; /* yesfree - null terminated heap alocated string of strlen length, may contain 0 */ +}; +struct dc_payload * dc_payload_init () { + struct dc_payload * s = calloc(1, sizeof(struct dc_payload)); + return s; +} +void dc_payload_free (struct dc_payload * s) { + free(s->body-LWS_PRE); + free(s); + return; +} +#define DC_ISASQ(shortname) DC_ISA(struct dc_##shortname, shortname##s) /* in struct array of structs quick */ +#define DC_ISAS_INIT(type/* w/o struct */, name) do { name##_sizeof = DC_ALLOC_CHUNK; /* structs ISA */ \ + name = calloc(name##_sizeof, sizeof(struct type *)); } while (0) /* prep arr, NO INIT membrs */ +#define DC_ISASIQ(shortname) DC_ISAS_INIT(dc_##shortname, s->shortname##s) /* ISAS init quick */ +#define DC_ISAF(shortname) for (size_t i = 0; i < s->shortname##s_sizeof; i++) /* ISA free */ \ + dc_##shortname##_free(s->shortname##s[i]); \ + free(s->shortname##s); /* no problem if we free past _lenght, as uninited are NULL */ struct dc_client { DC_STRUCT_PREFIX char * authorization; /* yesfree - authorization header value */ @@ -196,9 +220,11 @@ struct dc_client { unsigned long long int last_packet; /* last packet sequence number for ping */ time_t ping_interval; time_t last_ping; + DC_ISASQ(payload); /* array of payloads we must send over ws */ }; struct dc_client * dc_client_init () { struct dc_client * s = calloc(1, sizeof(*s)); + DC_ISASIQ(payload); return s; } void dc_client_free (struct dc_client * s) { @@ -207,8 +233,19 @@ void dc_client_free (struct dc_client * s) { free(s->authorization); free(s->email); free(s->password); + DC_ISAF(payload); free(s); } +void dc_ws_stack(struct dc_client * c, struct dc_payload * p) { /* we could just use pass->body and */ + DC_MR(c->payloads); /* just append to it, but the server closes if we send two objects in one */ + c->payloads[c->payloads_length++] = p; /* packet, like so: {"packet":1}{"packet":2}, so this. */ + p->body = realloc(p->body, p->length+LWS_PRE+1); /* when freeing, free p->body-LWS_PRE */ + memmove(p->body+LWS_PRE, p->body, p->length+1); /* body is no longer pointer we have to free */ + p->body += LWS_PRE; + if (c->pass && c->pass->wsi) + lws_callback_on_writable(c->pass->wsi); + return; +} struct dc_guild { DC_STRUCT_PREFIX char * name; /* yesfree */ @@ -385,7 +422,6 @@ static const struct lws_protocols dc_lws_protocols[] = { {"dc", dc_lws_cb, /* sizeof(struct dc_lws_pass) */ 0 /* lws naj NE ALOCIRA */, DC_LWS_MAX_RX, 0, NULL, 0}, {NULL, NULL, 0, 0, 0, NULL, 0} }; -#define DC_ISASQ(shortname) DC_ISA(struct dc_##shortname, shortname##s) /* in struct array of structs quick */ struct dc_program { /* data storage and token used for communication with the library */ DC_STRUCT_PREFIX /* this is the only struct that contains DC_ISAs */ DC_ISASQ(client); /* yesfree */ @@ -416,18 +452,13 @@ enum dc_status dc_handle_ping (struct dc_api_io io, void * userdata) { /* tries else continue; } - if (pass->api_io.status & DC_MUST_FREE) - free(pass->body); - pass->api_io.status |= DC_MUST_FREE; - pass->body_length = smprintf(&pass->body, DC_WS_PING_FORMAT, client->last_packet); fprintf(stderr, "dc_handle_ping: handling ping for client %d\n", i); - lws_callback_on_writable(pass->wsi); + struct dc_payload * payload = calloc(1, sizeof(struct dc_payload)); + payload->length = smprintf(&payload->body, DC_WS_PING_FORMAT, client->last_packet); + dc_ws_stack(client, payload); /* send a payload */ } return DC_OK; } -#define DC_ISAS_INIT(type/* w/o struct */, name) do { name##_sizeof = DC_ALLOC_CHUNK; /* structs ISA */ \ - name = calloc(name##_sizeof, sizeof(struct type *)); } while (0) /* prep arr, NO INIT membrs */ -#define DC_ISASIQ(shortname) DC_ISAS_INIT(dc_##shortname, s->shortname##s) /* ISAS init quick */ struct dc_program * dc_program_init () { struct dc_program * s = calloc(1, sizeof(struct dc_program)); DC_ISASIQ(client); @@ -462,9 +493,6 @@ struct dc_program * dc_program_init () { dc_api_i(io); return s; } -#define DC_ISAF(shortname) for (size_t i = 0; i < s->shortname##s_sizeof; i++) /* ISA free */ \ - dc_##shortname##_free(s->shortname##s[i]); \ - free(s->shortname##s); /* no problem if we free past _lenght, as uninited are NULL */ void dc_program_free (struct dc_program * s) { if (!s) return; @@ -478,6 +506,6 @@ void dc_program_free (struct dc_program * s) { DC_ISAF(permission); DC_ISAF(attached_function); DC_ISAF(api_io); - lws_context_destroy(s->lws_context); + lws_context_destroy(s->lws_context); /* closes all connections and destroys all wsis */ free(s); } @@ -3,7 +3,8 @@ int smprintf (char ** str, const char * format, ...) { /* allocates automaticall va_start(ap, format); va_copy(aq, ap); int len = vsnprintf(NULL, 0, format, ap); - *str = malloc(len+1); + if (!(*str = realloc(*str, len+1))) + fprintf(stderr, "[BUG] !!! realloc failed\n"); if (len != vsprintf(*str, format, ap)) fprintf(stderr, "[BUG] !!! len1 != len2\n"); va_end(ap); |