diff options
author | 2018-04-17 13:04:42 +0300 | |
---|---|---|
committer | 2018-04-17 13:04:42 +0300 | |
commit | 955c96410a10cbba1999df658404fcdbcdee0ee3 (patch) | |
tree | 67e666dfc530d501866f0771d4558561ab89aa5b /src/server/net.c | |
parent | 051b90d9555360bccf754e084219e31294b420ca (diff) | |
download | coffeetemp-955c96410a10cbba1999df658404fcdbcdee0ee3.tar.gz coffeetemp-955c96410a10cbba1999df658404fcdbcdee0ee3.tar.bz2 coffeetemp-955c96410a10cbba1999df658404fcdbcdee0ee3.zip |
server: split away networking code.
Diffstat (limited to 'src/server/net.c')
-rw-r--r-- | src/server/net.c | 149 |
1 files changed, 149 insertions, 0 deletions
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); +} |