diff options
Diffstat (limited to 'src/h.c')
-rw-r--r-- | src/h.c | 84 |
1 files changed, 56 insertions, 28 deletions
@@ -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); } |