]> git.lizzy.rs Git - dragonnet.git/commitdiff
Initial listener implementation
authorHimbeerserverDE <himbeerserverde@gmail.com>
Sat, 2 Oct 2021 22:14:10 +0000 (00:14 +0200)
committerHimbeerserverDE <himbeerserverde@gmail.com>
Sat, 2 Oct 2021 22:14:10 +0000 (00:14 +0200)
addr.c [new file with mode: 0644]
addr.h [new file with mode: 0644]
listen.c [new file with mode: 0644]
listen.h [new file with mode: 0644]
peer.c [new file with mode: 0644]
peer.h [new file with mode: 0644]

diff --git a/addr.c b/addr.c
new file mode 100644 (file)
index 0000000..226e0fd
--- /dev/null
+++ b/addr.c
@@ -0,0 +1,22 @@
+#include <arpa/inet.h>
+#include <string.h>
+
+#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 (file)
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 (file)
index 0000000..9f25eed
--- /dev/null
+++ b/listen.c
@@ -0,0 +1,140 @@
+#include <arpa/inet.h>
+#include <assert.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..249119c
--- /dev/null
+++ b/listen.h
@@ -0,0 +1,28 @@
+#ifndef _DRAGONNET_LISTEN_H_
+#define _DRAGONNET_LISTEN_H_
+
+#include <stdbool.h>
+
+#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 (file)
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 (file)
index 0000000..2f4ec6a
--- /dev/null
+++ b/peer.h
@@ -0,0 +1,25 @@
+#ifndef _DRAGONNET_PEER_H_
+#define _DRAGONNET_PEER_H_
+
+#include <pthread.h>
+
+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