summaryrefslogtreecommitdiffstats
path: root/src/h.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/h.c')
-rw-r--r--src/h.c84
1 files changed, 56 insertions, 28 deletions
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);
}