-# Prerequisites
-*.d
-
-# Object files
-*.o
-*.ko
-*.obj
-*.elf
-
-# Linker output
-*.ilk
-*.map
-*.exp
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Libraries
-*.lib
+CMakeLists.txt.user
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Testing
+Makefile
+cmake_install.cmake
+install_manifest.txt
+compile_commands.json
+CTestTestfile.cmake
+_deps
*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
-*.so
-*.so.*
-*.dylib
-
-# Executables
-*.exe
-*.out
-*.app
-*.i*86
-*.x86_64
-*.hex
-
-# Debug files
-*.dSYM/
-*.su
-*.idb
-*.pdb
-
-# Kernel Module Compile Results
-*.mod*
-*.cmd
-.tmp_versions/
-modules.order
-Module.symvers
-Mkfile.old
-dkms.conf
--- /dev/null
+[submodule "endian.h"]
+ path = endian.h
+ url = https://github.com/dragonblocks/endian.h
--- /dev/null
+cmake_minimum_required(VERSION 3.14)
+project(Dragonnet)
+
+add_compile_options(
+ -Wall
+ -Wextra
+ -Werror
+)
+
+add_library(dragonnet
+ dragonnet/addr.c
+ dragonnet/listen.c
+ dragonnet/peer.c
+ dragonnet/recv.c
+ dragonnet/recv_thread.c
+ dragonnet/send.c
+)
+
+target_link_libraries(dragonnet
+ pthread
+)
+
+target_include_directories(dragonnet
+ PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}"
+ PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/endian.h"
+)
+
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
+ target_link_libraries(dragonnet
+ ws2_32
+ )
+endif()
+++ /dev/null
-#include <dragonnet/addr.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-struct addrinfo *dragonnet_str2addr(const char *str)
-{
- const char *port = str + strlen(str) - 1;
- while (port >= str && *port != ':')
- port--;
- port++;
-
- const char *host_begin = str;
- if (*host_begin == '[')
- host_begin++;
-
- const char *host_end = port - 2;
- if (host_end >= str && *host_end == ']')
- host_end--;
-
- ssize_t host_len = host_end - host_begin + 1;
- if (host_len < 0)
- host_len = 0;
-
- char host[host_len + 1];
- host[host_len] = '\0';
- memcpy(host, host_begin, host_len);
-
- struct addrinfo *result, hints = {0};
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-
- int err;
- if ((err = getaddrinfo(host, port, &hints, &result))) {
- fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
- return NULL;
- }
-
- return result;
-}
-
-char *dragonnet_addr2str(struct sockaddr *addr, socklen_t addr_len)
-{
- char host[NI_MAXHOST], port[NI_MAXSERV];
-
- int err;
- if ((err = getnameinfo(addr, addr_len, host, NI_MAXHOST, port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV))) {
- fprintf(stderr, "getnameinfo: %s\n", gai_strerror(err));
- return NULL;
- }
-
- char str[1 + strlen(host) + 1 + 1 + strlen(port) + 1];
- sprintf(str, "[%s]:%s", host, port);
- return strdup(str);
-}
+++ /dev/null
-#ifndef _DRAGONNET_ADDR_H_
-#define _DRAGONNET_ADDR_H_
-
-#include "sock.h"
-
-struct addrinfo *dragonnet_str2addr(const char *str);
-char *dragonnet_addr2str(struct sockaddr *addr, socklen_t addr_len);
-
-#endif
--- /dev/null
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "addr.h"
+
+struct addrinfo *dragonnet_str2addr(const char *str)
+{
+ const char *port = str + strlen(str) - 1;
+ while (port >= str && *port != ':')
+ port--;
+ port++;
+
+ const char *host_begin = str;
+ if (*host_begin == '[')
+ host_begin++;
+
+ const char *host_end = port - 2;
+ if (host_end >= str && *host_end == ']')
+ host_end--;
+
+ ssize_t host_len = host_end - host_begin + 1;
+ if (host_len < 0)
+ host_len = 0;
+
+ char host[host_len + 1];
+ host[host_len] = '\0';
+ memcpy(host, host_begin, host_len);
+
+ struct addrinfo *result, hints = {0};
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ int err;
+ if ((err = getaddrinfo(host, port, &hints, &result))) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
+ return NULL;
+ }
+
+ return result;
+}
+
+char *dragonnet_addr2str(struct sockaddr *addr, socklen_t addr_len)
+{
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+
+ int err;
+ if ((err = getnameinfo(addr, addr_len, host, NI_MAXHOST, port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV))) {
+ fprintf(stderr, "getnameinfo: %s\n", gai_strerror(err));
+ return NULL;
+ }
+
+ char str[1 + strlen(host) + 1 + 1 + strlen(port) + 1];
+ sprintf(str, "[%s]:%s", host, port);
+ return strdup(str);
+}
--- /dev/null
+#ifndef _DRAGONNET_ADDR_H_
+#define _DRAGONNET_ADDR_H_
+
+#include "sock.h"
+
+struct addrinfo *dragonnet_str2addr(const char *str);
+char *dragonnet_addr2str(struct sockaddr *addr, socklen_t addr_len);
+
+#endif
--- /dev/null
+#define _GNU_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "addr.h"
+#include "listen.h"
+#include "recv.h"
+#include "sock.h"
+
+// ----
+// Peer
+// ----
+
+static bool dragonnet_peer_init_accepted(DragonnetPeer *p, int sock,
+ char *addr, DragonnetListener *l)
+{
+ pthread_mutex_init(&p->mtx, NULL);
+
+ p->sock = sock;
+ p->address = addr;
+ p->on_disconnect = l->on_disconnect;
+ p->on_recv = l->on_recv;
+ p->on_recv_type = l->on_recv_type;
+
+ return true;
+}
+
+static DragonnetPeer *dragonnet_peer_accept(int sock, char *addr,
+ DragonnetListener *l)
+{
+ DragonnetPeer *p = malloc(sizeof *p);
+ if (!dragonnet_peer_init_accepted(p, sock, addr, l)) {
+ pthread_mutex_destroy(&p->mtx);
+ free(p);
+ free(addr);
+ return NULL;
+ }
+
+ return p;
+}
+
+// --------
+// Listener
+// --------
+
+DragonnetListener *dragonnet_listener_new(char *addr)
+{
+ struct addrinfo *info = dragonnet_str2addr(addr);
+ if (!info)
+ return NULL;
+
+ DragonnetListener *l = malloc(sizeof *l);
+
+ l->active = true;
+ l->sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+ l->address = dragonnet_addr2str(info->ai_addr, info->ai_addrlen);
+ l->on_connect = NULL;
+ l->on_disconnect = NULL;
+ l->on_recv = NULL;
+ l->on_recv_type = calloc(sizeof *l->on_recv_type, dragonnet_num_types);
+
+ int so_reuseaddr = 1;
+ if (setsockopt(l->sock, SOL_SOCKET, SO_REUSEADDR, (void *) &so_reuseaddr,
+ sizeof so_reuseaddr) < 0) {
+ perror("setsockopt");
+ freeaddrinfo(info);
+ dragonnet_listener_delete(l);
+ return NULL;
+ }
+
+ if (bind(l->sock, info->ai_addr, info->ai_addrlen) < 0) {
+ perror("bind");
+ freeaddrinfo(info);
+ dragonnet_listener_delete(l);
+ return NULL;
+ }
+
+ freeaddrinfo(info);
+
+ if (listen(l->sock, 10) < 0) {
+ perror("listen");
+ dragonnet_listener_delete(l);
+ return NULL;
+ }
+
+ return l;
+}
+
+static void *listener_main(void *g_listener)
+{
+#ifdef __GLIBC__
+ pthread_setname_np(pthread_self(), "listen");
+#endif
+
+ DragonnetListener *l = (DragonnetListener *) g_listener;
+
+ while (l->active) {
+ struct sockaddr_storage 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) {
+ if (errno != EINTR)
+ perror("accept");
+ continue;
+ }
+
+ char *clt_addstr = dragonnet_addr2str((struct sockaddr *) &clt_addr, clt_addrlen);
+ DragonnetPeer *p = dragonnet_peer_accept(clt_sock, clt_addstr, l);
+ if (p == NULL)
+ continue;
+
+ void (*on_connect)(DragonnetPeer *) = l->on_connect;
+
+ if (on_connect != NULL)
+ on_connect(p);
+
+ dragonnet_peer_run(p);
+ }
+
+ return NULL;
+}
+
+void dragonnet_listener_run(DragonnetListener *l)
+{
+ pthread_create(&l->accept_thread, NULL, &listener_main, l);
+}
+
+void dragonnet_listener_close(DragonnetListener *l)
+{
+ l->active = false;
+
+ pthread_kill(l->accept_thread, SIGINT);
+ pthread_join(l->accept_thread, NULL);
+}
+
+void dragonnet_listener_delete(DragonnetListener *l)
+{
+ free(l->on_recv_type);
+ free(l->address);
+ free(l);
+}
--- /dev/null
+#ifndef _DRAGONNET_LISTEN_H_
+#define _DRAGONNET_LISTEN_H_
+
+#include <stdbool.h>
+#include "peer.h"
+
+typedef struct {
+ int sock;
+ char *address;
+
+ pthread_t accept_thread;
+ bool active;
+
+ void (*on_connect)(DragonnetPeer *);
+ void (*on_disconnect)(DragonnetPeer *);
+ bool (*on_recv)(DragonnetPeer *, DragonnetTypeId, void *);
+ void (**on_recv_type)(DragonnetPeer *, void *);
+} DragonnetListener;
+
+DragonnetListener *dragonnet_listener_new(char *addr);
+void dragonnet_listener_run(DragonnetListener *l);
+void dragonnet_listener_close(DragonnetListener *l);
+void dragonnet_listener_delete(DragonnetListener *l);
+
+#endif
--- /dev/null
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "addr.h"
+#include "peer.h"
+#include "recv.h"
+#include "recv_thread.h"
+#include "sock.h"
+
+static bool dragonnet_peer_init(DragonnetPeer *p, char *addr)
+{
+ pthread_mutex_init(&p->mtx, NULL);
+
+ struct addrinfo *info = dragonnet_str2addr(addr);
+ if (!info)
+ return false;
+
+ p->sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+ p->address = dragonnet_addr2str(info->ai_addr, info->ai_addrlen);
+
+ if (connect(p->sock, info->ai_addr, info->ai_addrlen) < 0) {
+ freeaddrinfo(info);
+ perror("connect");
+ return false;
+ }
+
+ freeaddrinfo(info);
+
+ p->on_disconnect = NULL;
+ p->on_recv = NULL;
+ p->on_recv_type = calloc(sizeof *p->on_recv_type, dragonnet_num_types); // fixme: memory leak
+
+ return true;
+}
+
+DragonnetPeer *dragonnet_connect(char *addr)
+{
+ DragonnetPeer *p = malloc(sizeof *p);
+ if (!dragonnet_peer_init(p, addr)) {
+ pthread_mutex_destroy(&p->mtx);
+ free(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+void dragonnet_peer_run(DragonnetPeer *p)
+{
+ pthread_create(&p->recv_thread, NULL, &dragonnet_peer_recv_thread, p);
+}
+
+void dragonnet_peer_shutdown(DragonnetPeer *p)
+{
+ shutdown(p->sock, SHUT_RDWR);
+}
--- /dev/null
+#ifndef _DRAGONNET_PEER_H_
+#define _DRAGONNET_PEER_H_
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef uint16_t DragonnetTypeId;
+
+typedef struct dragonnet_peer {
+ int sock;
+ char *address;
+
+ pthread_t recv_thread;
+ pthread_mutex_t mtx;
+
+ void (*on_disconnect)(struct dragonnet_peer *);
+ bool (*on_recv)(struct dragonnet_peer *, DragonnetTypeId, void *);
+ void (**on_recv_type)(struct dragonnet_peer *, void *);
+
+ void *extra;
+} DragonnetPeer;
+
+DragonnetPeer *dragonnet_connect(char *addr);
+void dragonnet_peer_run(DragonnetPeer *p);
+void dragonnet_peer_shutdown(DragonnetPeer *p);
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "recv.h"
+#include "sock.h"
+
+bool dragonnet_recv_raw(DragonnetPeer *p, void *buf, size_t n)
+{
+ if (n == 0)
+ return true;
+
+ ssize_t len = recv(p->sock, buf, n, MSG_WAITALL);
+ if (len < 0) {
+ perror("recv");
+ abort();
+ }
+
+ return len != 0;
+}
--- /dev/null
+#ifndef _DRAGONNET_RECV_H_
+#define _DRAGONNET_RECV_H_
+
+#include "peer.h"
+
+typedef struct {
+ size_t siz;
+ bool (*deserialize)(DragonnetPeer *, void *);
+ void (*free)(void *);
+} DragonnetType;
+
+extern DragonnetTypeId dragonnet_num_types;
+extern DragonnetType dragonnet_types[];
+
+bool dragonnet_recv_raw(DragonnetPeer *p, void *buf, size_t n);
+
+#endif
--- /dev/null
+#define _GNU_SOURCE
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "peer.h"
+#include "recv.h"
+#include "recv_thread.h"
+#include "sock.h"
+
+void *dragonnet_peer_recv_thread(void *g_peer)
+{
+#ifdef __GLIBC__
+ pthread_setname_np(pthread_self(), "recv");
+#endif
+
+ DragonnetPeer *p = (DragonnetPeer *) g_peer;
+
+ while (true) {
+ DragonnetTypeId type_id;
+
+ bool reset = false;
+
+ ssize_t len = recv(p->sock, (void *) &type_id, sizeof type_id, MSG_WAITALL);
+ if (len < 0) {
+ if (errno == ECONNRESET || errno == EPIPE || errno == ETIMEDOUT) {
+ reset = true;
+ } else {
+ perror("recv");
+ abort();
+ }
+ }
+
+ // Connection closed
+ if (len == 0 || reset) {
+ if (p->on_disconnect)
+ p->on_disconnect(p);
+
+ close(p->sock);
+ free(p->address);
+
+ pthread_mutex_destroy(&p->mtx);
+ free(p);
+ return NULL;
+ }
+
+ type_id = be16toh(type_id);
+
+ if (type_id >= dragonnet_num_types) {
+ fprintf(stderr, "[warning] received invalid type id %d\n", type_id);
+ continue;
+ }
+
+ DragonnetType type = dragonnet_types[type_id];
+
+ unsigned char buf[type.siz];
+ memset(buf, 0, type.siz);
+
+ if (!type.deserialize(p, buf)) {
+ if (type.free != NULL)
+ type.free(buf);
+
+ fprintf(stderr, "[warning] failed to deserialize package of type %d\n", type_id);
+
+ continue;
+ }
+
+ bool (*on_recv)(struct dragonnet_peer *, DragonnetTypeId, void *) = p->on_recv;
+ void (*on_recv_type)(DragonnetPeer *, void *) = p->on_recv_type[type_id];
+
+ if (on_recv != NULL && !on_recv(p, type_id, buf))
+ on_recv_type = NULL;
+
+ if (on_recv_type != NULL)
+ on_recv_type(p, buf);
+
+ if (type.free != NULL)
+ type.free(buf);
+ }
+}
--- /dev/null
+#ifndef _DRAGONNET_RECV_THREAD_H_
+#define _DRAGONNET_RECV_THREAD_H
+
+void *dragonnet_peer_recv_thread(void *g_peer);
+
+#endif
--- /dev/null
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "send.h"
+#include "sock.h"
+
+bool dragonnet_send_raw(DragonnetPeer *p, bool submit, const void *buf, size_t n)
+{
+ ssize_t len = send(p->sock, buf, n, MSG_NOSIGNAL | (submit ? 0 : MSG_MORE));
+
+ if (len < 0) {
+ if (errno == ECONNRESET || errno == EPIPE || errno == ETIMEDOUT) {
+ shutdown(p->sock, SHUT_RDWR);
+ pthread_mutex_unlock(&p->mtx);
+ return false;
+ }
+
+ perror("send");
+ abort();
+ }
+
+ if (submit)
+ pthread_mutex_unlock(&p->mtx);
+
+ return true;
+}
--- /dev/null
+#ifndef _DRAGONNET_SEND_H_
+#define _DRAGONNET_SEND_H_
+
+#include <stdbool.h>
+#include "peer.h"
+
+bool dragonnet_send_raw(DragonnetPeer *p, bool submit, const void *buf, size_t n);
+
+#endif
--- /dev/null
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <iphlpapi.h>
+#include <ws2def.h>
+#include <windows.h>
+#include <io.h>
+#define SHUT_RDWR SD_BOTH
+#define MSG_NOSIGNAL 0
+#define MSG_MORE 0
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
--- /dev/null
+Subproject commit f24960eca3bb806fa72d8de2b9a761a889fdeee3
+++ /dev/null
-#define _GNU_SOURCE
-#include <assert.h>
-#include <dragonnet/addr.h>
-#include <dragonnet/listen.h>
-#include <dragonnet/recv.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "sock.h"
-
-// ----
-// Peer
-// ----
-
-static bool dragonnet_peer_init_accepted(DragonnetPeer *p, int sock,
- char *addr, DragonnetListener *l)
-{
- pthread_mutex_init(&p->mtx, NULL);
-
- p->sock = sock;
- p->address = addr;
- p->on_disconnect = l->on_disconnect;
- p->on_recv = l->on_recv;
- p->on_recv_type = l->on_recv_type;
-
- return true;
-}
-
-static DragonnetPeer *dragonnet_peer_accept(int sock, char *addr,
- DragonnetListener *l)
-{
- DragonnetPeer *p = malloc(sizeof *p);
- if (!dragonnet_peer_init_accepted(p, sock, addr, l)) {
- pthread_mutex_destroy(&p->mtx);
- free(p);
- free(addr);
- return NULL;
- }
-
- return p;
-}
-
-// --------
-// Listener
-// --------
-
-DragonnetListener *dragonnet_listener_new(char *addr)
-{
- struct addrinfo *info = dragonnet_str2addr(addr);
- if (!info)
- return NULL;
-
- DragonnetListener *l = malloc(sizeof *l);
-
- l->active = true;
- l->sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
- l->address = dragonnet_addr2str(info->ai_addr, info->ai_addrlen);
- l->on_connect = NULL;
- l->on_disconnect = NULL;
- l->on_recv = NULL;
- l->on_recv_type = calloc(sizeof *l->on_recv_type, dragonnet_num_types);
-
- int so_reuseaddr = 1;
- if (setsockopt(l->sock, SOL_SOCKET, SO_REUSEADDR, (void *) &so_reuseaddr,
- sizeof so_reuseaddr) < 0) {
- perror("setsockopt");
- freeaddrinfo(info);
- dragonnet_listener_delete(l);
- return NULL;
- }
-
- if (bind(l->sock, info->ai_addr, info->ai_addrlen) < 0) {
- perror("bind");
- freeaddrinfo(info);
- dragonnet_listener_delete(l);
- return NULL;
- }
-
- freeaddrinfo(info);
-
- if (listen(l->sock, 10) < 0) {
- perror("listen");
- dragonnet_listener_delete(l);
- return NULL;
- }
-
- return l;
-}
-
-static void *listener_main(void *g_listener)
-{
-#ifdef __GLIBC__
- pthread_setname_np(pthread_self(), "listen");
-#endif
-
- DragonnetListener *l = (DragonnetListener *) g_listener;
-
- while (l->active) {
- struct sockaddr_storage 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) {
- if (errno != EINTR)
- perror("accept");
- continue;
- }
-
- char *clt_addstr = dragonnet_addr2str((struct sockaddr *) &clt_addr, clt_addrlen);
- DragonnetPeer *p = dragonnet_peer_accept(clt_sock, clt_addstr, l);
- if (p == NULL)
- continue;
-
- void (*on_connect)(DragonnetPeer *) = l->on_connect;
-
- if (on_connect != NULL)
- on_connect(p);
-
- dragonnet_peer_run(p);
- }
-
- return NULL;
-}
-
-void dragonnet_listener_run(DragonnetListener *l)
-{
- pthread_create(&l->accept_thread, NULL, &listener_main, l);
-}
-
-void dragonnet_listener_close(DragonnetListener *l)
-{
- l->active = false;
-
- pthread_kill(l->accept_thread, SIGINT);
- pthread_join(l->accept_thread, NULL);
-}
-
-void dragonnet_listener_delete(DragonnetListener *l)
-{
- free(l->on_recv_type);
- free(l->address);
- free(l);
-}
+++ /dev/null
-#ifndef _DRAGONNET_LISTEN_H_
-#define _DRAGONNET_LISTEN_H_
-
-#include <dragonnet/peer.h>
-#include <stdbool.h>
-
-typedef struct {
- int sock;
- char *address;
-
- pthread_t accept_thread;
- bool active;
-
- void (*on_connect)(DragonnetPeer *);
- void (*on_disconnect)(DragonnetPeer *);
- bool (*on_recv)(DragonnetPeer *, DragonnetTypeId, void *);
- void (**on_recv_type)(DragonnetPeer *, void *);
-} DragonnetListener;
-
-DragonnetListener *dragonnet_listener_new(char *addr);
-void dragonnet_listener_run(DragonnetListener *l);
-void dragonnet_listener_close(DragonnetListener *l);
-void dragonnet_listener_delete(DragonnetListener *l);
-
-#endif
+++ /dev/null
-#include <assert.h>
-#include <dragonnet/addr.h>
-#include <dragonnet/peer.h>
-#include <dragonnet/recv.h>
-#include <dragonnet/recv_thread.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "sock.h"
-
-static bool dragonnet_peer_init(DragonnetPeer *p, char *addr)
-{
- pthread_mutex_init(&p->mtx, NULL);
-
- struct addrinfo *info = dragonnet_str2addr(addr);
- if (!info)
- return false;
-
- p->sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
- p->address = dragonnet_addr2str(info->ai_addr, info->ai_addrlen);
-
- if (connect(p->sock, info->ai_addr, info->ai_addrlen) < 0) {
- freeaddrinfo(info);
- perror("connect");
- return false;
- }
-
- freeaddrinfo(info);
-
- p->on_disconnect = NULL;
- p->on_recv = NULL;
- p->on_recv_type = calloc(sizeof *p->on_recv_type, dragonnet_num_types); // fixme: memory leak
-
- return true;
-}
-
-DragonnetPeer *dragonnet_connect(char *addr)
-{
- DragonnetPeer *p = malloc(sizeof *p);
- if (!dragonnet_peer_init(p, addr)) {
- pthread_mutex_destroy(&p->mtx);
- free(p);
- return NULL;
- }
-
- return p;
-}
-
-void dragonnet_peer_run(DragonnetPeer *p)
-{
- pthread_create(&p->recv_thread, NULL, &dragonnet_peer_recv_thread, p);
-}
-
-void dragonnet_peer_shutdown(DragonnetPeer *p)
-{
- shutdown(p->sock, SHUT_RDWR);
-}
+++ /dev/null
-#ifndef _DRAGONNET_PEER_H_
-#define _DRAGONNET_PEER_H_
-
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef uint16_t DragonnetTypeId;
-
-typedef struct dragonnet_peer {
- int sock;
- char *address;
-
- pthread_t recv_thread;
- pthread_mutex_t mtx;
-
- void (*on_disconnect)(struct dragonnet_peer *);
- bool (*on_recv)(struct dragonnet_peer *, DragonnetTypeId, void *);
- void (**on_recv_type)(struct dragonnet_peer *, void *);
-
- void *extra;
-} DragonnetPeer;
-
-DragonnetPeer *dragonnet_connect(char *addr);
-void dragonnet_peer_run(DragonnetPeer *p);
-void dragonnet_peer_shutdown(DragonnetPeer *p);
-
-#endif
+++ /dev/null
-#include <dragonnet/recv.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "sock.h"
-
-bool dragonnet_recv_raw(DragonnetPeer *p, void *buf, size_t n)
-{
- if (n == 0)
- return true;
-
- ssize_t len = recv(p->sock, buf, n, MSG_WAITALL);
- if (len < 0) {
- perror("recv");
- abort();
- }
-
- return len != 0;
-}
+++ /dev/null
-#ifndef _DRAGONNET_RECV_H_
-#define _DRAGONNET_RECV_H_
-
-#include <dragonnet/peer.h>
-
-typedef struct {
- size_t siz;
- bool (*deserialize)(DragonnetPeer *, void *);
- void (*free)(void *);
-} DragonnetType;
-
-extern DragonnetTypeId dragonnet_num_types;
-extern DragonnetType dragonnet_types[];
-
-bool dragonnet_recv_raw(DragonnetPeer *p, void *buf, size_t n);
-
-#endif
+++ /dev/null
-#define _GNU_SOURCE
-#include <assert.h>
-#include <dragonnet/peer.h>
-#include <dragonnet/recv.h>
-#include <dragonnet/recv_thread.h>
-#include <endian.h/endian.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "sock.h"
-
-void *dragonnet_peer_recv_thread(void *g_peer)
-{
-#ifdef __GLIBC__
- pthread_setname_np(pthread_self(), "recv");
-#endif
-
- DragonnetPeer *p = (DragonnetPeer *) g_peer;
-
- while (true) {
- DragonnetTypeId type_id;
-
- bool reset = false;
-
- ssize_t len = recv(p->sock, (void *) &type_id, sizeof type_id, MSG_WAITALL);
- if (len < 0) {
- if (errno == ECONNRESET || errno == EPIPE || errno == ETIMEDOUT) {
- reset = true;
- } else {
- perror("recv");
- abort();
- }
- }
-
- // Connection closed
- if (len == 0 || reset) {
- if (p->on_disconnect)
- p->on_disconnect(p);
-
- close(p->sock);
- free(p->address);
-
- pthread_mutex_destroy(&p->mtx);
- free(p);
- return NULL;
- }
-
- type_id = be16toh(type_id);
-
- if (type_id >= dragonnet_num_types) {
- fprintf(stderr, "[warning] received invalid type id %d\n", type_id);
- continue;
- }
-
- DragonnetType type = dragonnet_types[type_id];
-
- unsigned char buf[type.siz];
- memset(buf, 0, type.siz);
-
- if (!type.deserialize(p, buf)) {
- if (type.free != NULL)
- type.free(buf);
-
- fprintf(stderr, "[warning] failed to deserialize package of type %d\n", type_id);
-
- continue;
- }
-
- bool (*on_recv)(struct dragonnet_peer *, DragonnetTypeId, void *) = p->on_recv;
- void (*on_recv_type)(DragonnetPeer *, void *) = p->on_recv_type[type_id];
-
- if (on_recv != NULL && !on_recv(p, type_id, buf))
- on_recv_type = NULL;
-
- if (on_recv_type != NULL)
- on_recv_type(p, buf);
-
- if (type.free != NULL)
- type.free(buf);
- }
-}
+++ /dev/null
-#ifndef _DRAGONNET_RECV_THREAD_H_
-#define _DRAGONNET_RECV_THREAD_H
-
-void *dragonnet_peer_recv_thread(void *g_peer);
-
-#endif
+++ /dev/null
-#include <dragonnet/send.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "sock.h"
-
-bool dragonnet_send_raw(DragonnetPeer *p, bool submit, const void *buf, size_t n)
-{
- ssize_t len = send(p->sock, buf, n, MSG_NOSIGNAL | (submit ? 0 : MSG_MORE));
-
- if (len < 0) {
- if (errno == ECONNRESET || errno == EPIPE || errno == ETIMEDOUT) {
- shutdown(p->sock, SHUT_RDWR);
- pthread_mutex_unlock(&p->mtx);
- return false;
- }
-
- perror("send");
- abort();
- }
-
- if (submit)
- pthread_mutex_unlock(&p->mtx);
-
- return true;
-}
+++ /dev/null
-#ifndef _DRAGONNET_SEND_H_
-#define _DRAGONNET_SEND_H_
-
-#include <dragonnet/peer.h>
-#include <stdbool.h>
-
-bool dragonnet_send_raw(DragonnetPeer *p, bool submit, const void *buf, size_t n);
-
-#endif
+++ /dev/null
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <iphlpapi.h>
-#include <ws2def.h>
-#include <windows.h>
-#include <io.h>
-#define SHUT_RDWR SD_BOTH
-#define MSG_NOSIGNAL 0
-#define MSG_MORE 0
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#endif