diff options
author | 2019-06-07 17:13:13 +0300 | |
---|---|---|
committer | 2019-06-07 17:13:13 +0300 | |
commit | 30513e7a89cc2f9283458100dea298770c7d18de (patch) | |
tree | 244ce464f2f8a363418c4e9f256f7958f771a979 | |
parent | 75c92f6776a69c1dddee3ee63af5d59e89184828 (diff) | |
download | usurpation-30513e7a89cc2f9283458100dea298770c7d18de.tar.gz usurpation-30513e7a89cc2f9283458100dea298770c7d18de.tar.bz2 usurpation-30513e7a89cc2f9283458100dea298770c7d18de.zip |
refactor server/client discovery to use TLVs.
Signed-off-by: Gediminas Jakutis <gediminas@varciai.lt>
-rw-r--r-- | include/net.h | 17 | ||||
-rw-r--r-- | include/tlv.h | 153 | ||||
-rw-r--r-- | include/utils.h | 17 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rwxr-xr-x | src/common/tlv.c | 209 | ||||
-rw-r--r-- | src/daemon/main.c | 37 | ||||
-rw-r--r-- | src/daemon/net.c | 120 | ||||
-rw-r--r-- | src/device/device_network.cpp | 29 | ||||
-rw-r--r-- | src/device/device_network.h | 3 | ||||
-rw-r--r-- | src/device/main.ino | 65 |
10 files changed, 324 insertions, 328 deletions
diff --git a/include/net.h b/include/net.h index 8385943..3fbaf5c 100644 --- a/include/net.h +++ b/include/net.h @@ -22,22 +22,11 @@ #ifndef USURPATION_NET_H_INCLUDED #define USURPATION_NET_H_INCLUDED -#ifdef unix #include <sys/socket.h> #include <netinet/in.h> -#endif #include <stddef.h> -#define MTU 1500 - -enum response { - ERROR = -1, - A_OK = 0, /* would be "OK", but clashes with some lib definitions */ - NONEWDATA, - DEAD, -}; - /** * Initialises a listening socket and returns the associated network descriptor. */ @@ -52,12 +41,12 @@ int net_close(int nd); * Get last data received from connection associated with network descriptor. * If the pointer pointed by data is NULL, a buffer is allocated by the function * and needs to be free()'d later. Otherwise, the supplied buffer is reused. + * Returns the amount of data acually fetched through recvsize pointer. */ -int net_getlastdata(int nd, char ** const data); +int net_getlastdata(int nd, char ** const data, size_t *recvsize); int net_send(int nd, const char * const buf, size_t buf_size); -#ifdef unix int net_send_addr(int nd, const char * const buf, size_t buf_size, const struct sockaddr_in * const addr); -#endif +void net_flush_read_buffer(int nd); #endif /* USURPATION_NET_H_INCLUDED */ diff --git a/include/tlv.h b/include/tlv.h index 75aa133..43b7a11 100644 --- a/include/tlv.h +++ b/include/tlv.h @@ -1,7 +1,8 @@ /* - * Usurpataion --- client-server protocol interface. + * Usurpation – clinet-server protocol implementation. * * Copyright (C) 2019 Ramūnas Mažeikis + * Copyright (C) 2019 Gediminas Jakutis * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,55 +22,12 @@ #ifndef USURPATION_PROTOCOL_H_INCLUDED #define USURPATION_PROTOCOL_H_INCLUDED -#if 0 - -How do we use this API(?), I hear you say. Well, here is a self-contained -example complete with tedious comments, allocation of buffers and cleanup: - -------------------------------------------------------------------------------- - 1 | void functy_the_function(void) - 2 | { - 3 | struct tlv tlv_packet; /* A packet made of tlv's */ - 4 | struct tlv text; /* Actually useful data */ - 5 | char *packet; /* Raw bytes to be pushed via UDP */ - 6 | size_t packet_size; /* Raw packet size */ - 7 | char message[] = "Get jacked!"; /* Duh! */ - 9 | - 10 | tlv_init(&tlv_packet, REGURAL); /* Initialise tlv_packet to regular */ - 11 | tlv_init(&text, TEXT); /* Initialise text packet */ - 12 | tlv_push_data(&text, message, sizeof(message)); /* Push text to appropriate tlv */ - 13 | tlv_push_tlv(&tlv_packet, &text); /* Push the tlv into tlv packet */ - 14 | - 15 | packet_size = tlv_raw_size(&tlv_packet); /* Get raw size required to push entire tlv_packet as bytes */ - 16 | packet = (char *)malloc(packet_size); /* Allocate buffer for outgoing packet */ - 17 | tlv_get_raw(&tlv_packet, packet); /* Flash tlv_packet to buffer */ - 19 | udp_push(packet, packet_size); /* Push packet via UDP */ - 20 | udp_flush(); /* Flush to the other side*/ - 21 | - 22 | tlv_destroy(&tlv_packet); /* Free tlv_packet */ - 23 | free(packet); /* Free packet itself */ - 24 | return; /* GTFO and save stack space */ - 25 | } -------------------------------------------------------------------------------- - -A few things to note: - * Calling tlv_destroy() on a tlv of type REGURAL or HEARTBEAT destorys - all sub-tlv's too. - * Tlv's get copies of data, which means the original buffer can be - freed immediately. - -#endif - - #include <errno.h> #include <stdint.h> +#include <stddef.h> #include <limits.h> -#define E_TLV_OVERFLOW (1 << 0) -#define E_UNKNOWN_TYPE (1 << 1) -#define END_OF_PACKET (1 << 2) - -#define TLV_SZ_MAX_RAW (MTU - 64) +#define TLV_SZ_MAX (MTU - 64) #ifdef __cplusplus extern "C" { @@ -81,12 +39,6 @@ extern "C" { */ typedef unsigned int msg_idx_t; -#if INT32_MAX == INT_MAX -#define READ_ENUM(data) htonl((data)) -#else INT_MAX == INT16_MAX -#define READ_ENUM(data) htons((data)) -#endif - enum tlv_type { /** * Explicitly states that this tlv is no longer valid for reading. @@ -122,93 +74,66 @@ enum tlv_type { */ UUID, -/* Data of the following types are other tlv's! */ - - /** - * Just a TLV container. - */ - REGURAL, - /** * Says "I'm not dead yet.". */ HEARTBEAT, +}; - /** - * Says "Bring out yer dead!". - */ - DISCOVERY +struct tlv_header { + int32_t type; + uint32_t size; }; -/** - * Literally type-length-value - * */ struct tlv { - enum tlv_type type; - uint16_t length; - const void *data; + struct tlv_header head; + char *data; }; -/** - * Keeps state of the parsing process. - * - * Related functions return one tlv at a time. - */ -struct tlv_parser { - const char *data; - uint16_t offset; +/* for tlv to "raw" conversion */ +struct tlv_packet { + size_t size; + ptrdiff_t cursor; + char *data; }; -/** - * Initialises parser to begin parsing the data. - * - * Returns the first tlv which should be a meta-tlv. If it is not --- you got - * problems. - */ -int tlv_parser_init(struct tlv_parser *parser, char *data, struct tlv *ret); +/* used as a termninator */ +#define tlv_none ((struct tlv) {{INVALID, 0}, NULL}) /** * Fills tlv structure to represent the next tlv in the packet. + * If saveptr is non-NULL, saves the offset to the next field in saveptr. + * Returns NONEWDATA if once all tlvs were read. * - * Returns END_OF_PACKET if all tlv's were read or E_TLV_OVERFLOW, if the last - * tlv, according to its declared size should not fit in a packet. + * tlv data fields obtained through this function MUST NOT be given + * to free(), as they point to the offsets in the "in" buffer. */ -int tlv_get(struct tlv_parser *parser, struct tlv *ret); +int tlv_get(char *in, struct tlv *tlv, char **saveptr); -/** - * Initialises tlv to sane values. - */ -void tlv_init(struct tlv *t, enum tlv_type type); +/* host<->network endianess conversion for the header */ +struct tlv_header ntoh_tlvh(const struct tlv_header * const in); +struct tlv_header hton_tlvh(const struct tlv_header * const in); /** - * Frees data held in the tlv structure. The structure itself shall be freed as - * needed by calling code. + * Forms (packs up) a raw data packet from the given tlv by appending it to the + * packet. Returns E_TLV_OVERFLOW if pushing data would cause the final size + * (including the terminator tlv) to be greater than TLV_SZ_MAX_RAW. In case of + * such error the data is left untouched. */ -void tlv_destroy(struct tlv *t); +int tlv_pack(struct tlv_packet *pack, struct tlv *tlv); -/** - * Tells amount of bytes needed to push tlv to a buffer - */ -size_t tlv_raw_size(const struct tlv *t); +/* finalized the packet by placing tlv_none at the end */ +int tlv_packet_finalize(struct tlv_packet *pack); -/** - * Pushes tlv to buffer as contiguous data. Check tlv size with tlv_raw_size - * beforehand. If you don't do that and overflow --- tough tiddy. - */ -int tlv_get_raw(const struct tlv *t, char *buf); +struct tlv *tlv_init(struct tlv *in, enum tlv_type type); +void tlv_destroy(struct tlv *in); -/** - * Pushes data to tlv. Returns E_TLV_OVERFLOW if pushing data would cause the - * final size to be greater than TLV_SZ_MAX_RAW. In case of such error the data is left - * untouched. - */ -int tlv_push_data(struct tlv *t, const char *data, uint16_t size); +struct tlv_packet *tlv_packet_init(struct tlv_packet *in); +void tlv_packet_destroy(struct tlv_packet *in); + +/* resets the packet to form a new one, without deallocating buffers */ +struct tlv_packet *tlv_packet_reset(struct tlv_packet *in); -/** - * Pushes a sub-tlv into the packet. 't' can only be REGURAL, HEARTBEAT or - * DISCOVERY. - */ -int tlv_push_tlv(struct tlv *t, const struct tlv *other); #ifdef __cplusplus } diff --git a/include/utils.h b/include/utils.h index ba726ec..e1364c5 100644 --- a/include/utils.h +++ b/include/utils.h @@ -2,6 +2,7 @@ * Usurpation – utility functions. * * Copyright (C) 2019 Ramūnas Mažeikis + * Copyright (C) 2019 Gediminas Jakutis * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,8 +24,22 @@ #include <stdint.h> +#define MTU 1500 + +static const char heartbeat_device[] = "hey, hey!"; +static const char heartbeat_server[] = "cover this area."; + +/* standard status responses */ +enum response { + ERROR = -1, + A_OK = 0, /* would be "OK", but clashes with some lib definitions */ + NONEWDATA, + DEAD, + EMPTY, +}; + typedef struct uuid_s { - char bytes[16]; + char bytes[16]; } uuid_t; int cmp_uuid(uuid_t *first, uuid_t *second); diff --git a/meson.build b/meson.build index 4efb996..035f7a4 100644 --- a/meson.build +++ b/meson.build @@ -24,7 +24,7 @@ elif get_option('buildtype') == 'debugoptimized' verb = '3' endif -daemon = executable(progname, d_sources, version, include_directories : inc, install : true, dependencies : deps, extra_files : d_conf, c_args : ['-DUSURP_VERBOSITY=' + verb, '-DSYSCONFDIR=' + get_option('sysconfdir')]) +daemon = executable(progname, [d_sources, common_sources], version, include_directories : inc, install : true, dependencies : deps, extra_files : d_conf, c_args : ['-DUSURP_VERBOSITY=' + verb, '-DSYSCONFDIR=' + get_option('sysconfdir')]) #install_data(extra, install_dir : resource_dir) install_data(d_conf, install_dir : get_option('sysconfdir')) diff --git a/src/common/tlv.c b/src/common/tlv.c index 72d0399..bf8a99c 100755 --- a/src/common/tlv.c +++ b/src/common/tlv.c @@ -1,7 +1,8 @@ /* - * Usurpataion --- clinet-server protocol implementation. + * Usurpation – clinet-server protocol implementation. * * Copyright (C) 2019 Ramūnas Mažeikis + * Copyright (C) 2019 Gediminas Jakutis * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,7 +29,6 @@ #include <string.h> #include <time.h> #include "tlv.h" -#include "net.h" #include "utils.h" #ifdef unix @@ -37,156 +37,125 @@ #include <lwip/def.h> #endif -struct tlv_header { - enum tlv_type type; - uint16_t size; -}; - -/** - * Returns tlv_size from packet - */ -uint16_t tlv_size(char *buf); - -/** - * Returns tlv_type from packet. - */ -enum tlv_type tlv_get_type(char *buf); - -/* Changes to be made: - * * Trust tlv size from raw data - * * Don't fail on 0 length. In that case data points to NULL - * * tlv_parser should be opaque. - * * Make a constructor that takes a user-supplied buffer. - */ -int tlv_get(struct tlv_parser *parser, struct tlv *ret) +int tlv_get(char *in, struct tlv *tlv, char **saveptr) { - int retval = 0; + struct tlv_header head; + int ret = A_OK; - size_t packet_size; - size_t final_size; - struct tlv *crr_tlv = parser->data + parser->offset; + memcpy(&head, in, sizeof(head)); + head = ntoh_tlvh(&head); - packet_size = tlv_size(parser->data); - final_size = parser->offset + crr_tlv->length + sizeof(struct tlv_header); - if (final_size >= packet_size) { - return retval = E_TLV_OVERFLOW; - } else { - if (crr_tlv->length != 0) { - ret->data = parser->data + parser->offset + sizeof(struct tlv_header); - } else { - ret->data = NULL; - } - ret->type = crr_tlv->type; - ret->length = crr_tlv->length; - parser->offset += sizeof(struct tlv_header) + ret->length; - if (final_size == packet_size) { - retval = END_OF_PACKET; - } + if (head.type == INVALID || !head.size) { + ret = NONEWDATA; + goto out; } - return retval; + tlv->head = head; + tlv->data = in + sizeof(head); + if (saveptr) { + *saveptr = in + sizeof(head) + head.size; + } +out: + return ret; } -int tlv_parser_init(struct tlv_parser *parser, char *buf, struct tlv *ret) +struct tlv_header ntoh_tlvh(const struct tlv_header * const in) { - /* Data points to the beggining of the buffer for size and - * type acquisition purposes. - * */ - struct tlv_header *data = buf; - /* It is known that the first tlv will be of the meta kind. - * We can safely skip the header. - * */ - parser->data = buf + sizeof(struct tlv_header); - ret->type = READ_ENUM(data->type); - ret->length = ntohs(data->size); -} + struct tlv_header ret; -uint16_t tlv_size(char *buf) -{ - struct tlv_header *data = buf; - return ntohs(data->size); + ret.type = ntohl(in->type); + ret.size = ntohl(in->size); + + return ret; } -enum tlv_type tlv_get_type(char *buf) +struct tlv_header hton_tlvh(const struct tlv_header * const in) { - struct tlv_header *data = buf; - return READ_ENUM(data->type); + struct tlv_header ret; + + ret.type = htonl(in->type); + ret.size = htonl(in->size); + + return ret; } -size_t tlv_data_size(struct tlv_parser *parser) +int tlv_pack(struct tlv_packet *pack, struct tlv *tlv) { - size_t size; + struct tlv_header head; + size_t raw_size; + int ret = A_OK; + + /* packed tlv loses the pointer, so only take the header part into account */ + raw_size = sizeof(tlv->head) + tlv->head.size; - if (parser->offset + sizeof(enum tlv_type) + sizeof(size_t) >= tlv_size(parser)) { - size = 0; + if ((raw_size + pack->cursor + sizeof(tlv->head)) >= TLV_SZ_MAX) { + ret = ERROR; } else { - memcpy(&size, parser->data + parser->offset + sizeof(enum tlv_type), sizeof(size_t)); + if (pack->size < pack->cursor + raw_size) { + pack->data = realloc(pack->data, pack->size + raw_size); + pack->size += raw_size; + } + + head = tlv->head; + head = hton_tlvh(&head); + memcpy(pack->data + pack->cursor, &head, sizeof(head)); + pack->cursor += sizeof(tlv->head); + if (tlv->head.size && tlv->data) { + memcpy(pack->data + pack->cursor, tlv->data, tlv->head.size); + pack->cursor += tlv->head.size; + } } - return size; + return ret; } -void tlv_destroy(struct tlv *t) +int tlv_packet_finalize(struct tlv_packet *pack) { - size_t i = 0; - size_t tlv_count; - struct tlv *arr; - switch (t->type) - { - case REGURAL: - case HEARTBEAT: - case DISCOVERY: - tlv_count = t->length / sizeof(struct tlv); - arr = t->data; - for (i = 0; i < tlv_count; i++) { - tlv_destroy(&arr[i]); - } - default: - free(t->data); - t->length = 0; - break; - } + struct tlv terminator; + int ret = A_OK; + + terminator = tlv_none; + + tlv_pack(pack, &terminator); + + return ret; } -size_t tlv_raw_size(const struct tlv *t) +struct tlv *tlv_init(struct tlv *in, enum tlv_type type) { - return sizeof(*t) + t->length; + in->head.type = type; + in->head.size = 0; + in->data = NULL; + + return in; } -int tlv_push_data(struct tlv *t, const char *data, uint16_t size) +void tlv_destroy(struct tlv *in) { - int ret = 0; - size_t final_size = tlv_raw_size(t) + size; - if (final_size > TLV_SZ_MAX_RAW) { - ret = E_TLV_OVERFLOW; - } else { - t->data = realloc(t->data, final_size); - memcpy(t->data + t->length, data, size); - t->length = final_size; - } - return ret; + free(in->data); + *in = tlv_none; } -void tlv_init(struct tlv *t, enum tlv_type type) +struct tlv_packet *tlv_packet_init(struct tlv_packet *in) { - t->type = type; - t->length = 0; - t->data = NULL; + in->size = 0; + in->cursor = 0; + in->data = NULL; + + return in; } -int tlv_push_tlv(struct tlv *t, const struct tlv *other) +struct tlv_packet *tlv_packet_reset(struct tlv_packet *in) { - int ret = 0; - size_t other_size; - size_t final_size; - - other_size = tlv_raw_size(other); - final_size = tlv_raw_size(t) + other_size; - if (final_size > TLV_SZ_MAX_RAW) { - ret = E_TLV_OVERFLOW; - } else { - tlv_get_raw(other, t->data + t->length); - t->length = final_size; - } + memset(in->data, 0, in->cursor); + in->cursor = 0; - return ret; + return in; +} + +void tlv_packet_destroy(struct tlv_packet *in) +{ + free(in->data); + in->size = 0; + in->cursor = 0; + in->data = NULL; } diff --git a/src/daemon/main.c b/src/daemon/main.c index 37b1a51..07da36d 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -28,6 +28,8 @@ #include "net.h" #include "purple.h" #include "proto_stdio.h" +#include "tlv.h" +#include "utils.h" static struct _state { int nd; @@ -56,7 +58,7 @@ int main(int argc, char **argv) } } else { if (proto_stdio_init() && setting_verbose()) { - fprintf(stderr, "libpurple initialization failed\n"); + fprintf(stderr, "stdio interface initialization failed\n"); } } @@ -77,15 +79,45 @@ int main(int argc, char **argv) /* TODO: semi-stub */ static int __main_loop(const struct timespec * const iter_len) { + struct tlv field; + struct tlv_packet pack; struct timespec t; + char *buf = NULL; + size_t recvsize; int ret = A_OK; t = *iter_len; + tlv_init(&field, HEARTBEAT); + field.data = strdup(heartbeat_server); + field.head.size = sizeof(heartbeat_server); + tlv_packet_init(&pack); + tlv_pack(&pack, &field); + tlv_packet_finalize(&pack); + tlv_destroy(&field); + + /* flush any pending discovery packets from the socker, + * as those can be quite numerous on startup. + */ + net_flush_read_buffer(__progstate.nd); - while (!ret) { + while (ret != ERROR) { + ret = net_getlastdata(__progstate.nd, &buf, &recvsize); + + if (ret == A_OK) { + /* we're only sending one TLV per packet as of now, + * so no need to save the pointer for further parsing + */ + ret = tlv_get(buf, &field, NULL); + if (ret == A_OK && field.head.type == HEARTBEAT && !(strcmp(field.data, heartbeat_device))) { + /* error checking? what error checking? */ + ret = net_send(__progstate.nd, pack.data, pack.cursor + 1); + } + } nanosleep(&t, NULL); } + tlv_packet_destroy(&pack); + return ret; } @@ -94,5 +126,6 @@ static void cleanup(void) purple_close(); proto_stdio_close(); net_close(__progstate.nd); + __progstate.nd = 0; settings_cleanup(); } diff --git a/src/daemon/net.c b/src/daemon/net.c index 62172fe..640bd28 100644 --- a/src/daemon/net.c +++ b/src/daemon/net.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include <rin/time.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> @@ -34,6 +35,7 @@ #include <limits.h> #include "settings.h" #include "net.h" +#include "utils.h" struct netstate { struct timespec lastreply; @@ -43,8 +45,10 @@ struct netstate { pthread_t listner; char *data; size_t bufsize; + ssize_t recvsize; unsigned int available; - int status; + int sock_status; + int buffer_status; pthread_mutex_t mutex; struct sockaddr_in clientaddr; }; @@ -98,7 +102,8 @@ int net_init(const unsigned short int port) state[i].data = malloc(MTU); memset(state[i].data, 0, MTU); state[i].bufsize = MTU; - state[i].status = NONEWDATA; + state[i].sock_status = NONEWDATA; + state[i].buffer_status = NONEWDATA; pthread_mutex_init(&state[i].mutex, NULL); if (pthread_create(&state[i].listner, NULL, dolisten, state + i)) { @@ -137,13 +142,14 @@ int net_close(int nd) return ret; } -int net_getlastdata(int nd, char ** const data) +int net_getlastdata(int nd, char ** const data, size_t *recvsize) { + size_t size; int ret; if (nd > count || nd < 1 || state[--nd].available) { ret = ERROR; - } else if (!(ret = state[nd].status)) { + } else if (!(ret = state[nd].buffer_status)) { if (!data) { ret = ERROR; goto out; @@ -151,10 +157,13 @@ int net_getlastdata(int nd, char ** const data) *data = malloc(MTU); } + size = state[nd].recvsize; memset(*data, 0, MTU); - memcpy(*data, state[nd].data, MTU); + memcpy(*data, state[nd].data, size); + *recvsize = size; } + state[nd].buffer_status = NONEWDATA; out: return ret; } @@ -162,27 +171,11 @@ out: int net_send(int nd, const char * const buf, size_t buf_size) { int ret = A_OK; - ssize_t sent; - struct timespec now; - if (nd > count || nd < 1 || state[--nd].available || state[nd].status != A_OK) { + if (nd > count || nd < 1 || state[nd - 1].available) { ret = ERROR; } else { - if (setting_verbose() >= INFO) { - clock_gettime(CLOCK_MONOTONIC_RAW, &now); - fprintf(stderr, "Sending DATA, timestap: %li \n", now.tv_sec); - } - - sent = sendto( state[nd].sock, buf, buf_size, MSG_DONTWAIT, - (struct sockaddr *) &state[nd].clientaddr, - sizeof(state[nd].clientaddr)); - - if (sent == -1) { - ret = DEAD; - if (setting_verbose() >= ERR) { - fprintf(stderr, "Sending packet to %s failed.\n", inet_ntoa(state[nd].clientaddr.sin_addr)); - } - } + ret = net_send_addr(nd, buf, buf_size, &state[nd - 1].clientaddr); } return ret; @@ -194,13 +187,12 @@ int net_send_addr(int nd, const char * const buf, size_t buf_size, const struct ssize_t sent; struct timespec now; - if (nd > count || nd < 1 || state[--nd].available) { ret = ERROR; } else { if (setting_verbose() >= INFO) { clock_gettime(CLOCK_MONOTONIC_RAW, &now); - fprintf(stderr, "Sending DATA, timestap: %li \n", now.tv_sec); + fprintf(stderr, "Sending packet to %s, timestap: %li \n", inet_ntoa(state[nd].clientaddr.sin_addr), now.tv_sec); } sent = sendto( state[nd].sock, buf, buf_size, MSG_DONTWAIT, @@ -218,46 +210,78 @@ int net_send_addr(int nd, const char * const buf, size_t buf_size, const struct return ret; } +void net_flush_read_buffer(int nd) +{ + struct netstate *st; + int cancelstate; + struct timespec now; + struct timespec later; + struct timespec delta; + + if (setting_verbose() >= INFO) { + fprintf(stderr, "acquiring net mutex\n"); + } + + if (!(nd > count || nd < 1 || state[--nd].available || state[nd].sock_status != A_OK)) { + st = state + nd; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); + pthread_mutex_lock(&st->mutex); + + if (setting_verbose() >= INFO) { + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + fprintf(stderr, "flushing netsocket\n"); + } + + do { + st->sock_status = getpacket(st->data, st->bufsize, &st->recvsize, st->sock, &st->clientaddr); + } while(st->sock_status); + + if (setting_verbose() >= INFO) { + clock_gettime(CLOCK_MONOTONIC_RAW, &later); + delta = rin_time_sub(&later, &now); + fprintf(stderr, "finished flushing netsocket in %lis%lins\n", delta.tv_sec, delta.tv_nsec); + } + + pthread_mutex_unlock(&st->mutex); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); + pthread_testcancel(); + } +} + static void *dolisten(void * state) { struct timespec now; - struct timespec wait = {0, 10 * 1000 * 1000}; /* 10 ms */ + struct timespec wait = {0, 1 * 1000 * 1000}; /* 1 ms */ struct netstate *st; - ssize_t recvbufsize; int cancelstate; int oldstatus = DEAD; - char *ipstring; st = state; do { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); pthread_mutex_lock(&st->mutex); - clock_gettime(CLOCK_MONOTONIC_RAW, &now); - st->status = getpacket(st->data, st->bufsize, &recvbufsize, st->sock, &st->clientaddr); + st->sock_status = getpacket(st->data, st->bufsize, &st->recvsize, st->sock, &st->clientaddr); - if (!st->status) { + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + if (!st->sock_status) { st->lastreply = now; + st->buffer_status = A_OK; } /* no packets in five seconds */ - if ((now.tv_sec - st->lastreply.tv_sec) >= 5) { - st->status = DEAD; - } else { - st->status = A_OK; - } + if ((now.tv_sec - st->lastreply.tv_sec) >= 20) { + st->sock_status = DEAD; + }; - if (oldstatus != st->status) - { - oldstatus = st->status; - if (st->status == DEAD) { + if (oldstatus != st->sock_status && st->sock_status != NONEWDATA) { + oldstatus = st->sock_status; + if (st->sock_status == DEAD) { /* this timestamp is arbitraty */ setting_verbose() >= INFO ? fprintf(stderr, "Connection with the client has been lost. Last reply since: %li \n", st->lastreply.tv_sec) : 0; - } else if (st->status == A_OK) { - ipstring = inet_ntoa(st->clientaddr.sin_addr); - setting_verbose() >= INFO ? fprintf(stderr, "Successful incoming connection from %s\n", ipstring) : 0; } } + pthread_mutex_unlock(&st->mutex); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); pthread_testcancel(); @@ -273,6 +297,7 @@ static int getpacket(char *data, size_t buffsize, ssize_t *recvbufsize, int sock { static struct pollfd pfd = {0}; int ret; + char *ipstring; socklen_t sender_len = sizeof(*sender); if (!pfd.fd) { @@ -288,10 +313,15 @@ static int getpacket(char *data, size_t buffsize, ssize_t *recvbufsize, int sock ret = NONEWDATA; } else if (pfd.revents & POLLIN) { *recvbufsize = recvfrom(sock, data, buffsize, MSG_DONTWAIT, (struct sockaddr *) sender, &sender_len); - ret = A_OK; + if (*recvbufsize < 0) { + ret = ERR; + } else { + ipstring = inet_ntoa(sender->sin_addr); + setting_verbose() >= INFO ? fprintf(stderr, "packet from %s received\n", ipstring) : 0; + ret = A_OK; + } } else { ret = NONEWDATA; } - return ret; } diff --git a/src/device/device_network.cpp b/src/device/device_network.cpp index f2456d9..1810852 100644 --- a/src/device/device_network.cpp +++ b/src/device/device_network.cpp @@ -22,7 +22,8 @@ #include <ESP8266WiFi.h> #include <WiFiUdp.h> #include "device_network.h" -#include "net.h" +#include "utils.h" +#include "tlv.h" static struct netstate { WiFiUDP udp; @@ -73,17 +74,31 @@ size_t udp_get_data(char *buf, size_t size) void discover_client(const int port) { IPAddress bcastip(255, 255, 255, 255); - char buffer[32] = {0}; + char buffer[128] = {0}; + struct tlv field; + struct tlv_packet pack; + size_t expected_s; + + tlv_init(&field, HEARTBEAT); + field.data = strdup(heartbeat_device); + field.head.size = sizeof(heartbeat_device); + tlv_packet_init(&pack); + tlv_pack(&pack, &field); + tlv_packet_finalize(&pack); + tlv_destroy(&field); do { udp_init_packet_expaddr(bcastip, port); - udp_push(servermagic, sizeof(servermagic)); + udp_push(pack.data, pack.cursor + 1); udp_flush(); delay(5); + + expected_s = sizeof(field.head) + sizeof(heartbeat_server); while (state.udp.parsePacket()) { - if (state.udp.available() >= sizeof(clientmagic)) { - state.udp.read(buffer, sizeof(clientmagic)); - if (!(strcmp(clientmagic, buffer))) { + if (state.udp.available() >= expected_s) { + state.udp.read(buffer, sizeof(buffer)); + tlv_get(buffer, &field, NULL); + if (field.head.type == HEARTBEAT && !(strcmp(heartbeat_server, field.data))) { state.daemon_ip = state.udp.remoteIP(); ++state.acquired; } @@ -91,6 +106,8 @@ void discover_client(const int port) } delay(95); } while (!state.acquired); + + tlv_packet_destroy(&pack); } IPAddress *get_daemon_address(void) diff --git a/src/device/device_network.h b/src/device/device_network.h index 92af429..ae719f0 100644 --- a/src/device/device_network.h +++ b/src/device/device_network.h @@ -35,7 +35,4 @@ size_t udp_get_data(char *buf, size_t size); void discover_client(const int port); IPAddress *get_daemon_address(void); -static const char servermagic[] = "I love coffee!"; -static const char clientmagic[] = "I love tea!"; - #endif /* DEVICE_UDP_H */ diff --git a/src/device/main.ino b/src/device/main.ino index 4376346..0835906 100644 --- a/src/device/main.ino +++ b/src/device/main.ino @@ -28,7 +28,7 @@ #include "DejaVu_Sans_Mono_13.h" #include "device_network.h" #include "screen.h" -#include "net.h" +#include "utils.h" #include "tlv.h" static const unsigned int internal_led = 2; @@ -42,20 +42,22 @@ static void blink_led(const int pin, const int ontime, const int offtime); void handle_tlv(const struct tlv *data); static struct progstate_t { - int ip_print_count = 5; - struct display_status ds = {0}; - struct tlv_parser parser = {0}; - struct tlv crr_data; - size_t bytes_read = 0; - char in_packet_buf[MTU]; + int ip_print_count; + struct display_status ds; + struct tlv field; + struct tlv_packet heartbeat; + size_t bytes_read; + char buf[MTU]; + char hbcounter; } progstate; void setup(void) { extern const char * const ssid; extern const char * const password; - pinMode(internal_led, OUTPUT); + struct tlv field; + pinMode(internal_led, OUTPUT); toggle_led(internal_led); init_OLED(); display.fillCircle(32, 16, 12); @@ -67,9 +69,16 @@ void setup(void) discover_client(com_port); display.fillCircle(92, 16, 12); display.display(); + progstate.ip_print_count = 5; + tlv_init(&field, HEARTBEAT); + field.data = strdup(heartbeat_device); + field.head.size = sizeof(heartbeat_device); + tlv_packet_init(&progstate.heartbeat); + tlv_pack(&progstate.heartbeat, &field); + tlv_packet_finalize(&progstate.heartbeat); + tlv_destroy(&field); } -/* the logic is a placeholder right now */ void loop(void) { static const String devstr = "Device IP:"; @@ -77,16 +86,22 @@ void loop(void) static String prefix; static IPAddress ip_to_print; static IPAddress *daemon_ip = NULL; +#if 0 + char *saveptr; +#endif static unsigned int delta = 2000; /* sleep length to use (ms) */ delay(delta); - /* Initial display of ip's. */ - if (progstate.ip_print_count > 0) { + if (!progstate.hbcounter) { udp_init_packet(com_port); - udp_push(clientmagic, sizeof(clientmagic)); + udp_push(progstate.heartbeat.data, progstate.heartbeat.cursor + 1); udp_flush(); + progstate.hbcounter = 2; + } + if (progstate.ip_print_count) { + /* Initial display of ip's. */ if (!daemon_ip) { daemon_ip = get_daemon_address(); } @@ -98,27 +113,33 @@ void loop(void) display.drawString(0, 16, ip_to_print.toString()); display.display(); progstate.ip_print_count--; - } else { /* Dealing with tlv's one at a time. */ - progstate.bytes_read = udp_get_data(progstate.in_packet_buf, sizeof(progstate.in_packet_buf)); + } else { + progstate.bytes_read = udp_get_data(progstate.buf, sizeof(progstate.buf)); if (progstate.bytes_read > 0) { - progstate.parser.data = progstate.in_packet_buf; - progstate.parser.offset = 0; - /* Ignore errors for now. */ - while (tlv_get(&progstate.parser, &progstate.crr_data) == 0) { - handle_tlv(&progstate.crr_data); + tlv_get(progstate.buf, &progstate.field, NULL); + handle_tlv(&progstate.field); +#if 0 + /* Dealing with tlv's one at a time. */ + saveptr = progstate.buf; + while (!(tlv_get(saveptr, &progstate.field, &saveptr))) { + handle_tlv(&progstate.field); } +#endif } + display_update_scroll(&progstate.ds); } + + --progstate.hbcounter; } -void handle_tlv(const struct tlv *t) +void handle_tlv(const struct tlv *in) { /* Currently just dealing with text. * */ - switch (t->type) { + switch (in->head.type) { case TEXT: - display_status_init(&display, &progstate.ds, (char *)t->data); + display_status_init(&display, &progstate.ds, in->data); break; default: display.clear(); |