summaryrefslogtreecommitdiffstats
path: root/src/server/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/net.c')
-rw-r--r--src/server/net.c193
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);
-}