summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-17 14:36:09 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-17 14:36:09 +0200
commit876b012e1aae1cfc9687536edc302987ce899963 (patch)
tree8ac295bc789cf7eafacd52b9cc45bc433906fe99
parentnot tested yet, but added parsing users: myself and friends (diff)
downloaddiscord.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
-rw-r--r--src/api.c109
-rw-r--r--src/h.c84
-rw-r--r--src/lib.c3
3 files changed, 117 insertions, 79 deletions
diff --git a/src/api.c b/src/api.c
index 850ae30..1107d53 100644
--- a/src/api.c
+++ b/src/api.c
@@ -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 */
diff --git a/src/h.c b/src/h.c
index 4463f01..8e6a56c 100644
--- a/src/h.c
+++ b/src/h.c
@@ -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);
}
diff --git a/src/lib.c b/src/lib.c
index 07d339d..de78be0 100644
--- a/src/lib.c
+++ b/src/lib.c
@@ -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);