diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/main.c | 91 | ||||
-rw-r--r-- | src/server/net.c | 149 | ||||
-rw-r--r-- | src/server/net.h | 36 |
3 files changed, 208 insertions, 68 deletions
diff --git a/src/server/main.c b/src/server/main.c index 8e4f413..1b36c2f 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -31,99 +31,54 @@ #include <stddef.h> #include <stdlib.h> #include <time.h> +#include "net.h" -static void init(const unsigned int port, int *sock); -static int getpacket(char *data, size_t buffsize, int *sock, struct sockaddr_in *sender); +static struct netstate *init(const unsigned 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) { - static const char servermagic[] = "I love coffee!"; - static const char clientmagic[] = "I love tea!"; - struct sockaddr_in srvaddr = {0}; - char buff[9001] = {0}; - int sock; - int pstatus; - struct timespec lastreply; - struct timespec now; + struct netstate *state; + char data[8] = {0}; + int status; + struct timespec wait = {0, 500 * 1000 * 1000}; - init(2191, &sock); - - clock_gettime(CLOCK_MONOTONIC_RAW, &now); - lastreply = now; - lastreply.tv_sec -= 5; + state = init(2191); do { - clock_gettime(CLOCK_MONOTONIC_RAW, &now); - pstatus = getpacket(buff, sizeof(buff), &sock, &srvaddr); - - switch (pstatus) { - case 0: - if ((now.tv_sec - lastreply.tv_sec) >= 5) { - draw_idle(); - } - break; - case 1: - lastreply = now; - if (buff[0] == 'I') { - if (!(strcmp(buff, servermagic))) { - sendto(sock, clientmagic, sizeof(clientmagic), - MSG_DONTWAIT, (struct sockaddr *) &srvaddr, sizeof(srvaddr)); - } - draw_idle(); - continue; - } - draw_busy(buff); + status = state->getlastdata(data, state); + switch (status) { + case NET_OK: + /*fall-through */ + case NET_NONEWDATA: + draw_busy(data); break; + case NET_ERROR: + goto fail; default: + draw_idle(); ; /* noop */ } - } while (getch() != 'q' && pstatus >= 0); + nanosleep(&wait, NULL); + } while (getch() != 'q'); - close(sock); +fail: + net_close(&state); endwin(); return 0; } -static void init(const unsigned int port, int *sock) +static struct netstate *init(const unsigned int port) { - struct sockaddr_in bindaddress = {0}; - - bindaddress.sin_family = AF_INET; - bindaddress.sin_port = htons(port); - *sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - bind(*sock, (struct sockaddr*) &bindaddress, sizeof(bindaddress)); + struct netstate *ret; + ret = net_init(port); initscr(); nodelay(stdscr, 1); noecho(); -} - -static int getpacket(char *data, size_t buffsize, 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, 25); - if (ret <= 0) { - return ret; - } - if (pfd.revents & POLLIN) { - recvfrom(*sock, data, buffsize, MSG_DONTWAIT, (struct sockaddr *) sender, &sender_len); - ret = 1; - } else { - ret = 0; - } return ret; } diff --git a/src/server/net.c b/src/server/net.c new file mode 100644 index 0000000..cecf10c --- /dev/null +++ b/src/server/net.c @@ -0,0 +1,149 @@ +/* + * Hot Beverage Companion – desktop app network module + * + * Copyright (C) 2017 Gediminas Jakutis + * + * This library 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 library; 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 <string.h> +#include <time.h> +#include <stdlib.h> +#include "net.h" + +struct netstate_internal { + int (*getlastdata)(char * const data, struct netstate * const state); + unsigned int handle; + struct timespec lastreply; + int sock; +}; + +static int dolisten(char * const data, struct netstate_internal * const state); +static int getpacket(char *data, size_t buffsize, 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) +{ + struct netstate_internal *ret; + struct sockaddr_in bindaddress = {0}; + + ret = malloc(sizeof(struct netstate_internal)); + 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; + } + + clock_gettime(CLOCK_MONOTONIC_RAW, &ret->lastreply); + ret->lastreply.tv_sec -= 5; + ret->handle = 0; /* currently unused */ + ret->getlastdata = &getlastdata_internal; + + return (struct netstate *) ret; +} + +int net_close(struct netstate **state) { + close((*(struct netstate_internal **)state)->sock); + free(*state); + *state = NULL; + return 0; +} + +static int dolisten(char * const data, struct netstate_internal * const 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 sockaddr_in clientaddr; + size_t i = 10; + int ret; + + do { + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + ret = getpacket(buff, sizeof(buff), 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, 8ul); + } + break; + default: + ; /* noop */ + } + + if (!ret) { + nanosleep(&wait, NULL); + } + } while (--i && ret != 0); + + /* no packets in five seconds */ + if ((now.tv_sec - state->lastreply.tv_sec) >= 5) { + ret = NET_DEAD; + } + + return ret; +} + +static int getpacket(char *data, size_t buffsize, 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 = NET_NONEWDATA; + } else if (pfd.revents & POLLIN) { + recvfrom(sock, data, buffsize, MSG_DONTWAIT, (struct sockaddr *) sender, &sender_len); + ret = NET_OK; + } else { + ret = NET_NONEWDATA; + } + + 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 new file mode 100644 index 0000000..57c17f6 --- /dev/null +++ b/src/server/net.h @@ -0,0 +1,36 @@ +/* + * Hot Beverage Companion – desktop app network module + * + * Copyright (C) 2017 Gediminas Jakutis + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef NET_H_INCLUDED +#define NET_H_INCLUDED + +#define NET_ERROR -1 +#define NET_OK 0 +#define NET_NONEWDATA 1 +#define NET_DEAD 2 + +struct netstate { + int (*getlastdata)(char * const data, struct netstate * const state); +}; + +struct netstate *net_init(const unsigned int port); +int net_close(struct netstate **state); + +#endif /* NET_H_INCLUDED */ |