diff options
-rw-r--r-- | include/net.h | 14 | ||||
-rw-r--r-- | include/settings.h | 2 | ||||
-rw-r--r-- | include/utils.h | 20 | ||||
-rw-r--r-- | meson_options.txt | 3 | ||||
-rw-r--r-- | src/common/utils.c | 2 | ||||
-rw-r--r-- | src/daemon/main.c | 48 | ||||
-rw-r--r-- | src/daemon/net.c | 99 | ||||
-rw-r--r-- | src/daemon/proto_stdio.c | 43 | ||||
-rw-r--r-- | src/daemon/purple.c | 14 | ||||
-rw-r--r-- | src/device/meson.build | 32 |
10 files changed, 214 insertions, 63 deletions
diff --git a/include/net.h b/include/net.h index e4ca0a6..8385943 100644 --- a/include/net.h +++ b/include/net.h @@ -22,6 +22,13 @@ #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 { @@ -29,8 +36,6 @@ enum response { A_OK = 0, /* would be "OK", but clashes with some lib definitions */ NONEWDATA, DEAD, - NO_ESPTOOL, - TMPFILE, }; /** @@ -49,5 +54,10 @@ int net_close(int nd); * and needs to be free()'d later. Otherwise, the supplied buffer is reused. */ int net_getlastdata(int nd, char ** const data); +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 #endif /* USURPATION_NET_H_INCLUDED */ diff --git a/include/settings.h b/include/settings.h index e2e9644..538c7fd 100644 --- a/include/settings.h +++ b/include/settings.h @@ -26,7 +26,7 @@ enum verbosity { SILENT = 0, ERR = 1, WARN, - DEBUG, + INFO, ALL }; diff --git a/include/utils.h b/include/utils.h index 95b553d..ba726ec 100644 --- a/include/utils.h +++ b/include/utils.h @@ -1,3 +1,23 @@ +/* + * Usurpation – utility functions. + * + * Copyright (C) 2019 Ramūnas Mažeikis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + #ifndef USURPATION_UTILS_H #define USURPATION_UTILS_H diff --git a/meson_options.txt b/meson_options.txt index 3181893..e4ac698 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,3 +4,6 @@ option('fwflash', type : 'boolean', value : false, description : 'Automatically option('ssid', type : 'string', value : 'ssid', description : 'wireless ssid to compile into the firmware (no effect without fwbuild') option('password', type : 'string', value : 'password', description : 'wireless password to compile into the firmware (no effect without fwbuild') option('oledlib', type : 'string', description : 'path containing the SSD1306Spi.h file (required if fwbuild is true') +option('makeesparduino', type : 'string', description : 'path to the directory containing the makeEspArduino.mk file (required if fwbuild is true') +option('esplib', type : 'string', description : 'path to the esp8266lib (required if fwbuild is true') +option('board', type : 'string', value : 'd1_mini', description : 'board name identifier to provide to makeEspArduino') diff --git a/src/common/utils.c b/src/common/utils.c index 7522404..79ff4ea 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -1,5 +1,5 @@ /* - * Usurpataion --- utility functions. + * Usurpation – utility functions. * * Copyright (C) 2019 Ramūnas Mažeikis * diff --git a/src/daemon/main.c b/src/daemon/main.c index 94e59fd..37b1a51 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -23,31 +23,46 @@ #include <time.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "settings.h" #include "net.h" #include "purple.h" +#include "proto_stdio.h" static struct _state { int nd; -} _progstate; +} __progstate; -void cleanup(void); +static void cleanup(void); +static int __main_loop(const struct timespec * const iter_len); /* the logic is a placeholder right now */ int main(int argc, char **argv) { extern const char * const version; - struct timespec t = {3600, 0}; /* one hour */ + static const struct timespec t = {0, 250 * 1000 * 1000}; /* 250ms */ + char *proto; printf("Usurpation daemon version %s starting\n", version); atexit(cleanup); settings_init(); - _progstate.nd = net_init(setting_port()); - if (purple_init() && setting_verbose()) { - fprintf(stderr, "libpurple initialization failed\n"); + __progstate.nd = net_init(setting_port()); + proto = setting_im_proto(); + + if (strcmp(proto, "null")) { + if (purple_init() && setting_verbose()) { + fprintf(stderr, "libpurple initialization failed\n"); + } + } else { + if (proto_stdio_init() && setting_verbose()) { + fprintf(stderr, "libpurple initialization failed\n"); + } } + free(proto); + proto = NULL; + /* by default and if running by as a system service, the init system * needs to keep control of the process and thus only detach if * requested when ran manually by a user. @@ -56,17 +71,28 @@ int main(int argc, char **argv) daemon(0, 0); } - while(!(nanosleep(&t, NULL))) { - /* noop */ + return __main_loop(&t); +} + +/* TODO: semi-stub */ +static int __main_loop(const struct timespec * const iter_len) +{ + struct timespec t; + int ret = A_OK; + + t = *iter_len; + while (!ret) { + nanosleep(&t, NULL); } - return 0; + return ret; } -void cleanup(void) +static void cleanup(void) { purple_close(); - net_close(_progstate.nd); + proto_stdio_close(); + net_close(__progstate.nd); settings_cleanup(); } diff --git a/src/daemon/net.c b/src/daemon/net.c index 9180344..62172fe 100644 --- a/src/daemon/net.c +++ b/src/daemon/net.c @@ -45,10 +45,11 @@ struct netstate { size_t bufsize; unsigned int available; int status; - pthread_mutex_t datamutex; + pthread_mutex_t mutex; + struct sockaddr_in clientaddr; }; -static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static struct netstate *state; static ssize_t count; static size_t available_count; @@ -63,7 +64,7 @@ int net_init(const unsigned short int port) ssize_t i; int sizechanged = 0; - pthread_mutex_lock(&initmutex); + pthread_mutex_lock(&mutex); if (available_count) { for (i = 0; !state[i].available; ++i) { if (i == count) { @@ -98,7 +99,7 @@ int net_init(const unsigned short int port) memset(state[i].data, 0, MTU); state[i].bufsize = MTU; state[i].status = NONEWDATA; - pthread_mutex_init(&state[i].datamutex, NULL); + pthread_mutex_init(&state[i].mutex, NULL); if (pthread_create(&state[i].listner, NULL, dolisten, state + i)) { ret = ERROR; @@ -111,7 +112,7 @@ out: state = realloc(state, sizeof(struct netstate) * --count); } - pthread_mutex_unlock(&initmutex); + pthread_mutex_unlock(&mutex); return ret; } @@ -119,7 +120,7 @@ int net_close(int nd) { int ret; - pthread_mutex_lock(&initmutex); + pthread_mutex_lock(&mutex); if (nd > count || nd < 1 || state[nd - 1].available) { ret = ERROR; } else { @@ -132,7 +133,7 @@ int net_close(int nd) ret = A_OK; } - pthread_mutex_unlock(&initmutex); + pthread_mutex_unlock(&mutex); return ret; } @@ -158,14 +159,69 @@ out: return ret; } -static void *dolisten(void * state) +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) { + 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)); + } + } + } + + return ret; +} + +int net_send_addr(int nd, const char * const buf, size_t buf_size, const struct sockaddr_in * const addr) { + int ret = A_OK; + ssize_t sent; + struct timespec now; - static const char servermagic[] = "I love coffee!"; - static const char clientmagic[] = "I love tea!"; + + 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); + } + + sent = sendto( state[nd].sock, buf, buf_size, MSG_DONTWAIT, + (struct sockaddr *) addr, + sizeof(*addr)); + + if (sent == -1) { + ret = DEAD; + if (setting_verbose() >= ERR) { + fprintf(stderr, "Sending packet to %s failed.\n", inet_ntoa(addr->sin_addr)); + } + } + } + + return ret; +} + +static void *dolisten(void * state) +{ struct timespec now; struct timespec wait = {0, 10 * 1000 * 1000}; /* 10 ms */ - struct sockaddr_in clientaddr; struct netstate *st; ssize_t recvbufsize; int cancelstate; @@ -176,17 +232,12 @@ static void *dolisten(void * state) do { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); - pthread_mutex_lock(&st->datamutex); + pthread_mutex_lock(&st->mutex); clock_gettime(CLOCK_MONOTONIC_RAW, &now); - st->status = getpacket(st->data, st->bufsize, &recvbufsize, st->sock, &clientaddr); + st->status = getpacket(st->data, st->bufsize, &recvbufsize, st->sock, &st->clientaddr); if (!st->status) { st->lastreply = now; - if (st->data[0] == 'I' && !(strcmp(st->data, servermagic))) { - sendto(st->sock, clientmagic, sizeof(clientmagic), - MSG_DONTWAIT, (struct sockaddr *) &clientaddr, sizeof(clientaddr)); - setting_verbose() ? fprintf(stderr, "Sending DATA, timestap: %li \n", st->lastreply.tv_sec) : 0; - } } /* no packets in five seconds */ @@ -199,15 +250,15 @@ static void *dolisten(void * state) if (oldstatus != st->status) { oldstatus = st->status; - if(st->status == DEAD) { + if (st->status == DEAD) { /* this timestamp is arbitraty */ - setting_verbose() ? fprintf(stderr, "Connection with the client has been lost. Last reply since: %li \n", st->lastreply.tv_sec) : 0; - } else { - ipstring = inet_ntoa(clientaddr.sin_addr); - setting_verbose() ? fprintf(stderr, "Successful incoming connection from %s\n", ipstring) : 0; + 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->datamutex); + pthread_mutex_unlock(&st->mutex); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); pthread_testcancel(); diff --git a/src/daemon/proto_stdio.c b/src/daemon/proto_stdio.c index f0a22a6..9aecdf0 100644 --- a/src/daemon/proto_stdio.c +++ b/src/daemon/proto_stdio.c @@ -27,32 +27,31 @@ void message_receive(char *arg) { int cancelstate; - int done = 0; - while (!done) { - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); - pthread_mutex_lock(&state.out_m); - if (!state.writebuf) { - state.writebuf = strdup(arg); - done = 1; - } - pthread_mutex_unlock(&state.out_m); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); - pthread_testcancel(); - } + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); + pthread_mutex_lock(&state.out_m); + state.writebuf = strdup(arg); + pthread_mutex_unlock(&state.out_m); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); + pthread_testcancel(); + nanosleep(&respite, NULL); } char *message_send(void) { - char *ret; + char *ret = NULL; int cancelstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); pthread_mutex_lock(&state.out_m); - ret = strdup(state.readbuf); - free(state.readbuf); - state.readbuf = NULL; - state.readbufsize = 0; + + if (state.readbuf) { + ret = strdup(state.readbuf); + free(state.readbuf); + state.readbuf = NULL; + state.readbufsize = 0; + } + pthread_mutex_unlock(&state.out_m); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); pthread_testcancel(); @@ -140,12 +139,16 @@ int proto_stdio_init(void) void proto_stdio_close(void) { - if (pthread_mutex_trylock(&state.mutex) == EBUSY) { + int status; + + status = pthread_mutex_trylock(&state.mutex); + + if (status == EBUSY) { pthread_cancel(state.stdio_in); pthread_cancel(state.stdio_out); pthread_join(state.stdio_in, NULL); pthread_join(state.stdio_out, NULL); + } else if (!status) { + pthread_mutex_unlock(&state.mutex); } - - pthread_mutex_unlock(&state.mutex); } diff --git a/src/daemon/purple.c b/src/daemon/purple.c index 882ea61..fc4f49f 100644 --- a/src/daemon/purple.c +++ b/src/daemon/purple.c @@ -156,9 +156,11 @@ static void *purple_spawn(void *disregard) char *user = NULL; char *password = NULL; char *proto = NULL; + int cancelstate; (void) disregard; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); pthread_cleanup_push(pthread_mutex_unlock_thunk, &state.mutex); progname = setting_progname(); @@ -203,8 +205,11 @@ static void *purple_spawn(void *disregard) pthread_cleanup_push(purple_account_destroy_thunk, state.account); - g_main_loop_run(loop); pthread_cleanup_push(g_main_loop_quit_thunk, loop); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); + pthread_testcancel(); + + g_main_loop_run(loop); pthread_cleanup_pop(1); pthread_cleanup_pop(1); @@ -246,9 +251,14 @@ int purple_init(void) void purple_close(void) { + int status; + + status = pthread_mutex_trylock(&state.mutex); - if (pthread_mutex_trylock(&state.mutex) == EBUSY) { + if (status == EBUSY) { pthread_cancel(state.purple); pthread_join(state.purple, NULL); + } else if (!status) { + pthread_mutex_unlock(&state.mutex); } } diff --git a/src/device/meson.build b/src/device/meson.build index 8e4aa90..7a0665c 100644 --- a/src/device/meson.build +++ b/src/device/meson.build @@ -5,17 +5,35 @@ if get_option('fwbuild') libpath = get_option('oledlib') assert((libpath != ''), 'path to oled lib is empty') + mkesppath = get_option('makeesparduino') + assert((mkesppath != ''), 'path to directory with makeEspArduino.mk is empty') + + esplib = get_option('esplib') + assert((esplib != ''), 'path esplib is empty') + + board = get_option('board') + oledlib = [] foreach i : oledlibnames oledlib += files(libpath + '/' + i) endforeach + mkespard = files(mkesppath + '/makeEspArduino.mk') + assert((oledlib != []), 'oled lib not found in the supplied lib directory') - espmake = find_program('espmake') printf = find_program('printf') cat = find_program('cat') cp = find_program('cp') + make = find_program('make') + nproc = find_program('nproc', disabler : true) + + if nproc.found() + nproc_out = run_command(nproc) + cpus = nproc_out.stdout().strip() + else + cpus = '2' + endif fw_filenames = [ 'main.ino', @@ -55,7 +73,17 @@ if get_option('fwbuild') fw = custom_target('fw', output : fw_image, input : [fw_sources, fw_conf], - command : [espmake, '-C', builddir, '&&', cp, '/tmp/mkESP/main_d1_mini/main.bin', '@OUTDIR@/' + fw_image], + command : [make, + '-f', + mkespard, + 'ESP_ROOT=' + esplib, + 'BOARD=' + board, '-j' + cpus, + '-C', + builddir, + '&&', + cp, + '/tmp/mkESP/main_d1_mini/main.bin', + '@OUTDIR@/' + fw_image], install : true, install_dir : resource_dir) |