summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/daemon/main.c4
-rw-r--r--src/daemon/meson.build1
-rw-r--r--src/daemon/net.c229
3 files changed, 234 insertions, 0 deletions
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 9ecdd4d..a729f84 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -2,6 +2,7 @@
* Usurpation – server daemon main logic
*
* Copyright (C) 2019 Gediminas Jakutis
+ * Copyright (C) 2019 Paulius Ratkevičius
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,6 +23,7 @@
#include <time.h>
#include <stdio.h>
#include "settings.h"
+#include "net.h"
/* the logic is a placeholder right now */
int main(int argc, char **argv)
@@ -31,6 +33,7 @@ int main(int argc, char **argv)
printf("Usurpation daemon version %s starting\n", version);
+ net_init(6996); // To do: get port from settings.
/* 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.
@@ -41,5 +44,6 @@ int main(int argc, char **argv)
while(!(nanosleep(&t, NULL))) {
/* noop */
+
}
}
diff --git a/src/daemon/meson.build b/src/daemon/meson.build
index 48190c8..f83613c 100644
--- a/src/daemon/meson.build
+++ b/src/daemon/meson.build
@@ -1,6 +1,7 @@
d_filenames = [
'main.c',
'settings.c',
+ 'net.c',
]
d_conf_filenames = [
diff --git a/src/daemon/net.c b/src/daemon/net.c
new file mode 100644
index 0000000..225d6d9
--- /dev/null
+++ b/src/daemon/net.c
@@ -0,0 +1,229 @@
+/*
+ * Usurpation – newtwork logic
+ *
+ * Copyright (C) 2019 Gediminas Jakutis
+ * Copyright (C) 2019 Paulius Ratkevičius
+ *
+ * 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
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/udp.h>
+#include <poll.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "net.h"
+
+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 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);
+
+int net_init(const unsigned short int port)
+{
+ 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 = ERROR;
+ goto out;
+ }
+ }
+ } else {
+ if (++count == INT_MAX) {
+ ret = ERROR;
+ goto out;
+ }
+
+ 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);
+ state[i].sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (bind(state[i].sock, (struct sockaddr*) &bindaddress, sizeof(bindaddress))) {
+ ret = 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 = NONEWDATA;
+ pthread_mutex_init(&state[i].datamutex, NULL);
+
+ if (pthread_create(&state[i].listner, NULL, dolisten, state + i)) {
+ ret = ERROR;
+ goto out;
+ }
+
+ ret = count;
+out:
+ if (ret == ERROR && sizechanged) {
+ state = realloc(state, sizeof(struct netstate) * --count);
+ }
+
+ pthread_mutex_unlock(&initmutex);
+ return ret;
+}
+
+int net_close(int nd)
+{
+ int ret;
+
+ pthread_mutex_lock(&initmutex);
+ if (nd > count || nd < 1 || state[nd - 1].available) {
+ ret = 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 = A_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 = ERROR;
+ } else if (!(ret = state[nd].status)) {
+ memcpy(data, state[nd].data, dgsize);
+ }
+
+ return ret;
+}
+
+static void *dolisten(void * state)
+{
+
+ static const char servermagic[] = "I love coffee!";
+ static const char clientmagic[] = "I love tea!";
+ struct timespec now;
+ struct timespec wait = {0, 10 * 1000 * 1000}; /* 10 ms */
+ struct sockaddr_in clientaddr;
+ struct netstate *st;
+ ssize_t recvbufsize;
+ int cancelstate;
+
+ st = state;
+
+ do {
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate);
+ pthread_mutex_lock(&st->datamutex);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &now);
+ 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 = NONEWDATA; /* consume packet and lie about it */
+ fprintf(stderr, "Sending DATA, timestap: %li \n", st->lastreply.tv_sec);
+ }
+ }
+
+ /* no packets in five seconds */
+ if ((now.tv_sec - st->lastreply.tv_sec) >= 5) {
+ st->status = 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 = A_OK;
+ }
+
+ pthread_mutex_unlock(&st->datamutex);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate);
+ pthread_testcancel();
+
+ nanosleep(&wait, NULL);
+
+ } while (1);
+
+ return NULL;
+}
+
+static int getpacket(char *data, size_t buffsize, ssize_t *recvbufsize, int sock, struct sockaddr_in *sender)
+{
+ static struct pollfd pfd = {0};
+ int ret;
+ socklen_t sender_len = sizeof(*sender);
+
+ if (!pfd.fd) {
+ pfd.fd = sock;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ }
+
+ ret = poll(&pfd, 1, 0);
+ if (ret < 0) {
+ /* NOOP */
+ } else if (!ret) {
+ ret = NONEWDATA;
+ } else if (pfd.revents & POLLIN) {
+ *recvbufsize = recvfrom(sock, data, buffsize, MSG_DONTWAIT, (struct sockaddr *) sender, &sender_len);
+ ret = A_OK;
+ } else {
+ ret = NONEWDATA;
+ }
+
+ return ret;
+}