diff options
Diffstat (limited to 'src/server/net.c')
-rw-r--r-- | src/server/net.c | 193 |
1 files changed, 134 insertions, 59 deletions
diff --git a/src/server/net.c b/src/server/net.c index 1325da0..100ba9c 100644 --- a/src/server/net.c +++ b/src/server/net.c @@ -24,96 +24,177 @@ #include <netinet/udp.h> #include <poll.h> #include <unistd.h> -#include <string.h> +#include <pthread.h> #include <time.h> +#include <string.h> #include <stdlib.h> +#include <limits.h> #include "net.h" -struct netstate_internal { - int (*getlastdata)(char * const data, struct netstate * const state); - unsigned int handle; +struct netstate { struct timespec lastreply; + int nd; int sock; + unsigned short int port; + pthread_t listner; + char *data; + size_t bufsize; + unsigned int available; + int status; + pthread_mutex_t datamutex; }; -static int dolisten(char * const data, struct netstate_internal * const state); +static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER; +static struct netstate *state; +static ssize_t count; +static size_t available_count; + +static void *dolisten(void * state); static int getpacket(char *data, size_t buffsize, ssize_t *recvbufsize, int sock, struct sockaddr_in *sender); -static int getlastdata_internal(char * const data, struct netstate * const state); -struct netstate *net_init(const unsigned int port) +int net_init(const unsigned short int port) { - struct netstate_internal *ret; struct sockaddr_in bindaddress = {0}; + int ret; + ssize_t i; + int sizechanged = 0; + + pthread_mutex_lock(&initmutex); + if (available_count) { + for (i = 0; !state[i].available; ++i) { + if (i == count) { + ret = NET_ERROR; + goto out; + } + } + } else { + if (++count == INT_MAX) { + ret = NET_ERROR; + goto out; + } - ret = malloc(sizeof(struct netstate_internal)); + i = count - 1; + state = realloc(state, sizeof(struct netstate) * count); + sizechanged = 1; + } + state[i].available = 0; bindaddress.sin_family = AF_INET; bindaddress.sin_port = htons(port); - ret->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (bind(ret->sock, (struct sockaddr*) &bindaddress, sizeof(bindaddress))) { - free(ret); - return NULL; + state[i].sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (bind(state[i].sock, (struct sockaddr*) &bindaddress, sizeof(bindaddress))) { + ret = NET_ERROR; + goto out; + } + + clock_gettime(CLOCK_MONOTONIC_RAW, &state[i].lastreply); + state[i].lastreply.tv_sec -= 5; + state[i].nd = i + 1; + state[i].port = port; + state[i].data = malloc(dgsize); + memset(state[i].data, 0, dgsize); + state[i].bufsize = dgsize; + state[i].status = NET_NONEWDATA; + pthread_mutex_init(&state[i].datamutex, NULL); + + if (pthread_create(&state[i].listner, NULL, dolisten, state + i)) { + ret = NET_ERROR; + goto out; } - clock_gettime(CLOCK_MONOTONIC_RAW, &ret->lastreply); - ret->lastreply.tv_sec -= 5; - ret->handle = 0; /* currently unused */ - ret->getlastdata = &getlastdata_internal; + ret = count; +out: + if (ret == NET_ERROR && sizechanged) { + state = realloc(state, sizeof(struct netstate) * --count); + } - return (struct netstate *) ret; + pthread_mutex_unlock(&initmutex); + return ret; } -int net_close(struct netstate **state) { - close((*(struct netstate_internal **)state)->sock); - free(*state); - *state = NULL; - return 0; +int net_close(int nd) +{ + int ret; + + pthread_mutex_lock(&initmutex); + if (nd > count || nd < 1 || state[nd - 1].available) { + ret = NET_ERROR; + } else { + --nd; + pthread_cancel(state[nd].listner); + pthread_join(state[nd].listner, NULL); + close(state[nd].sock); + free(state[nd].data); + state[nd].available = 1; + ret = NET_OK; + } + + pthread_mutex_unlock(&initmutex); + return ret; +} + +int net_getlastdata(int nd, char * const data) +{ + int ret; + + if (nd > count || nd < 1 || state[--nd].available) { + ret = NET_ERROR; + } else if (!(ret = state[nd].status)) { + memcpy(data, state[nd].data, dgsize); + } + + return ret; } -static int dolisten(char * const data, struct netstate_internal * const state) +static void *dolisten(void * state) { - char buff[9001] = {0}; static const char servermagic[] = "I love coffee!"; static const char clientmagic[] = "I love tea!"; struct timespec now; - struct timespec wait = {0, 25 * 1000 * 1000}; + struct timespec wait = {0, 10 * 1000 * 1000}; /* 10 ms */ struct sockaddr_in clientaddr; - size_t i = 10; + struct netstate *st; ssize_t recvbufsize; - int ret; + int cancelstate; + + st = state; do { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); + pthread_mutex_lock(&st->datamutex); clock_gettime(CLOCK_MONOTONIC_RAW, &now); - ret = getpacket(buff, sizeof(buff), &recvbufsize, state->sock, &clientaddr); - - switch (ret) { - case NET_OK: - state->lastreply = now; - if (buff[0] == 'I') { - if (!(strcmp(buff, servermagic))) { - sendto(state->sock, clientmagic, sizeof(clientmagic), - MSG_DONTWAIT, (struct sockaddr *) &clientaddr, sizeof(clientaddr)); - } - ret = NET_NONEWDATA; /* consume packet and lie about it */ - continue; - } else { - memcpy(data, buff, recvbufsize); + st->status = getpacket(st->data, st->bufsize, &recvbufsize, st->sock, &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)); + st->status = NET_NONEWDATA; /* consume packet and lie about it */ } - break; - default: - ; /* noop */ } - if (!ret) { - nanosleep(&wait, NULL); + /* no packets in five seconds */ + if ((now.tv_sec - st->lastreply.tv_sec) >= 5) { + st->status = NET_DEAD; + } else if (st->data[0] != 'I') { + /* we don't actually want to have NONEWDATA set from this loop, + * barring the one exeption that is after arrival of the beacon + * packet, as it'd keep the value at NONEWDATA almost constantly + * due to polling being generally much more frequent than the + * actual packet rate. + */ + st->status = NET_OK; } - } while (--i && ret != 0); - /* no packets in five seconds */ - if ((now.tv_sec - state->lastreply.tv_sec) >= 5) { - ret = NET_DEAD; - } + pthread_mutex_unlock(&st->datamutex); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); + pthread_testcancel(); - return ret; + nanosleep(&wait, NULL); + + } while (1); + + return NULL; } static int getpacket(char *data, size_t buffsize, ssize_t *recvbufsize, int sock, struct sockaddr_in *sender) @@ -142,9 +223,3 @@ static int getpacket(char *data, size_t buffsize, ssize_t *recvbufsize, int sock return ret; } - - -static int getlastdata_internal(char * const data, struct netstate * const state) -{ - return dolisten(data, (struct netstate_internal *) state); -} |