summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/main.c22
-rw-r--r--src/server/net.c193
-rw-r--r--src/server/net.h9
3 files changed, 151 insertions, 73 deletions
diff --git a/src/server/main.c b/src/server/main.c
index 5c0628a..f4d9fdc 100644
--- a/src/server/main.c
+++ b/src/server/main.c
@@ -33,22 +33,26 @@
#include <time.h>
#include "net.h"
-static struct netstate *init(const unsigned int port);
+int init(const unsigned short int port);
static void draw_idle(void);
static void draw_busy(const char * const data);
static float digest_temp(const short int rawdata);
int main(void)
{
- struct netstate *state;
- char data[32] = {0};
+ static const struct timespec wait = {0, 200 * 1000 * 1000}; /* 200 ms */
+ char data[dgsize] = {0};
int status;
- struct timespec wait = {0, 100 * 1000 * 1000};
+ int nd;
- state = init(2191);
+ nd = init(2191);
+
+ if (nd == NET_ERROR) {
+ goto fail;
+ }
do {
- status = state->getlastdata(data, state);
+ status = net_getlastdata(nd, data);
switch (status) {
case NET_OK:
/*fall-through */
@@ -65,15 +69,15 @@ int main(void)
} while (getch() != 'q');
fail:
- net_close(&state);
+ net_close(nd);
endwin();
return 0;
}
-static struct netstate *init(const unsigned int port)
+int init(const unsigned short int port)
{
- struct netstate *ret;
+ int ret;
ret = net_init(port);
initscr();
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);
-}
diff --git a/src/server/net.h b/src/server/net.h
index 57c17f6..92ba962 100644
--- a/src/server/net.h
+++ b/src/server/net.h
@@ -26,11 +26,10 @@
#define NET_NONEWDATA 1
#define NET_DEAD 2
-struct netstate {
- int (*getlastdata)(char * const data, struct netstate * const state);
-};
+#define dgsize 512
-struct netstate *net_init(const unsigned int port);
-int net_close(struct netstate **state);
+int net_init(const unsigned short int port);
+int net_close(int nd);
+int net_getlastdata(int nd, char * const data);
#endif /* NET_H_INCLUDED */