From d9e507892700f2bbe570c0a1de6a4c9ae74786c3 Mon Sep 17 00:00:00 2001 From: HimbeerserverDE Date: Sun, 3 Oct 2021 00:14:10 +0200 Subject: [PATCH] Initial listener implementation --- addr.c | 22 +++++++++ addr.h | 11 +++++ listen.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ listen.h | 28 +++++++++++ peer.c | 16 +++++++ peer.h | 25 ++++++++++ 6 files changed, 242 insertions(+) create mode 100644 addr.c create mode 100644 addr.h create mode 100644 listen.c create mode 100644 listen.h create mode 100644 peer.c create mode 100644 peer.h diff --git a/addr.c b/addr.c new file mode 100644 index 0000000..226e0fd --- /dev/null +++ b/addr.c @@ -0,0 +1,22 @@ +#include +#include + +#include "addr.h" + +DragonnetAddr dragonnet_addr_parse(char *addr) +{ + DragonnetAddr net_addr; + + size_t port_i = 0; + for (size_t i = 0; i < strlen(addr); ++i) { + if (!port_i) { + if (addr[i] != ':') + net_addr.ip[i] = addr[i]; + else + port_i = i+1; + } else + net_addr.port[i-port_i] = addr[i]; + } + + return net_addr; +} diff --git a/addr.h b/addr.h new file mode 100644 index 0000000..437e245 --- /dev/null +++ b/addr.h @@ -0,0 +1,11 @@ +#ifndef _DRAGONNET_ADDR_H_ +#define _DRAGONNET_ADDR_H_ + +typedef struct { + char ip[INET6_ADDRSTRLEN]; + char port[5]; +} DragonnetAddr; + +DragonnetAddr dragonnet_addr_parse(char *addr); + +#endif diff --git a/listen.c b/listen.c new file mode 100644 index 0000000..9f25eed --- /dev/null +++ b/listen.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "addr.h" +#include "listen.h" + +// ---- +// Peer +// ---- + +static DragonnetPeer *dragonnet_peer_accept(int sock, struct sockaddr_in6 addr, + DragonnetListener *l) +{ + DragonnetPeer *p = malloc(sizeof *p); + p->mu = malloc(sizeof *p->mu); + pthread_rwlock_init(p->mu, NULL); + pthread_rwlock_wrlock(p->mu); + + p->sock = sock; + p->laddr = l->laddr; + + char ip_addr[INET6_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET6, &addr.sin6_addr, ip_addr, INET6_ADDRSTRLEN); + + char port[6] = {0}; + sprintf(port, "%d", ntohs(addr.sin6_port)); + + int err = getaddrinfo(ip_addr, port, NULL, &p->raddr); + if (err != 0) { + fprintf(stderr, "invalid network address %s:%s\n", ip_addr, port); + dragonnet_peer_delete(p); + p = NULL; + } + + if (p != NULL) + pthread_rwlock_unlock(p->mu); + + return p; +} + +// -------- +// Listener +// -------- + +DragonnetListener *dragonnet_listener_new(char *addr, void (*on_connect)(DragonnetPeer *p)) +{ + DragonnetListener *l = malloc(sizeof *l); + l->mu = malloc(sizeof *l->mu); + pthread_rwlock_init(l->mu, NULL); + pthread_rwlock_wrlock(l->mu); + + l->sock = socket(AF_INET6, SOCK_STREAM, 0); + l->on_connect = on_connect; + + int flag = 1; + if (setsockopt(l->sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof flag) < 0) { + perror("setsockopt"); + dragonnet_listener_delete(l); + return NULL; + } + + DragonnetAddr net_addr = dragonnet_addr_parse(addr); + int err = getaddrinfo(net_addr.ip, net_addr.port, NULL, &l->laddr); + if (err != 0) { + fprintf(stderr, "invalid network address %s\n", addr); + dragonnet_listener_delete(l); + return NULL; + } + + if (bind(l->sock, l->laddr->ai_addr, l->laddr->ai_addrlen) < 0) { + perror("bind"); + dragonnet_listener_delete(l); + return NULL; + } + + if (listen(l->sock, 10) < 0) { + perror("listen"); + dragonnet_listener_delete(l); + return NULL; + } + + pthread_rwlock_unlock(l->mu); + return l; +} + +void dragonnet_listener_run(DragonnetListener *l) +{ + pthread_rwlock_wrlock(l->mu); + + assert(l->state == DRAGONNET_LISTENER_CREATED); + l->state++; + + pthread_rwlock_unlock(l->mu); + + while (l->state == DRAGONNET_LISTENER_ACTIVE) { + struct sockaddr_in6 clt_addr; + socklen_t clt_addrlen = sizeof clt_addr; + + int clt_sock = accept(l->sock, (struct sockaddr *) &clt_addr, &clt_addrlen); + if (clt_sock < 0) { + perror("accept"); + continue; + } + + DragonnetPeer *p = dragonnet_peer_accept(clt_sock, clt_addr, l); + if (p == NULL) + continue; + + if (l->on_connect != NULL) + l->on_connect(p); + } +} + +void dragonnet_listener_close(DragonnetListener *l) +{ + pthread_rwlock_wrlock(l->mu); + + assert(l->state == DRAGONNET_LISTENER_ACTIVE); + close(l->sock); + l->state++; + + pthread_rwlock_unlock(l->mu); +} + +void dragonnet_listener_delete(DragonnetListener *l) +{ + pthread_rwlock_wrlock(l->mu); + + if (l->laddr != NULL) + freeaddrinfo(l->laddr); + + pthread_rwlock_unlock(l->mu); + pthread_rwlock_destroy(l->mu); + free(l); +} diff --git a/listen.h b/listen.h new file mode 100644 index 0000000..249119c --- /dev/null +++ b/listen.h @@ -0,0 +1,28 @@ +#ifndef _DRAGONNET_LISTEN_H_ +#define _DRAGONNET_LISTEN_H_ + +#include + +#include "peer.h" + +typedef enum { + DRAGONNET_LISTENER_CREATED, + DRAGONNET_LISTENER_ACTIVE, + DRAGONNET_LISTENER_CLOSED +} DragonnetListenerState; + +typedef struct { + int sock; + struct addrinfo *laddr; + void (*on_connect)(DragonnetPeer *p); + DragonnetListenerState state; + + pthread_rwlock_t *mu; +} DragonnetListener; + +DragonnetListener *dragonnet_listener_new(char *addr, void (*on_connect)(DragonnetPeer *p)); +void dragonnet_listener_run(DragonnetListener *l); +void dragonnet_listener_close(DragonnetListener *l); +void dragonnet_listener_delete(DragonnetListener *l); + +#endif diff --git a/peer.c b/peer.c new file mode 100644 index 0000000..3506767 --- /dev/null +++ b/peer.c @@ -0,0 +1,16 @@ +#include "peer.h" + +DragonnetPeer *dragonnet_connect(char *addr) +{ + return NULL; +} + +void dragonnet_peer_close(DragonnetPeer *p) +{ + +} + +void dragonnet_peer_delete(DragonnetPeer *p) +{ + +} diff --git a/peer.h b/peer.h new file mode 100644 index 0000000..2f4ec6a --- /dev/null +++ b/peer.h @@ -0,0 +1,25 @@ +#ifndef _DRAGONNET_PEER_H_ +#define _DRAGONNET_PEER_H_ + +#include + +typedef enum { + DRAGONNET_PEER_CREATED, + DRAGONNET_PEER_ACTIVE, + DRAGONNET_PEER_CLOSED +} DragonnetPeerState; + +typedef struct { + int sock; + struct addrinfo *laddr; + struct addrinfo *raddr; + DragonnetPeerState state; + + pthread_rwlock_t *mu; +} DragonnetPeer; + +DragonnetPeer *dragonnet_connect(char *addr); +void dragonnet_peer_close(DragonnetPeer *p); +void dragonnet_peer_delete(DragonnetPeer *p); + +#endif -- 2.44.0