fnet.c

Simple C networking library
git clone git://git.finwo.net/lib/fnet.c
Log | Files | Refs | README

commit 7703a5bd8bf4e5d5e94157aa632e6684f9700cf2
parent b7fdc6ac99c3071d071984c3d40a0798b13ecf12
Author: Yersa Nordman <yersa@finwo.nl>
Date:   Thu, 27 Jul 2023 00:37:18 +0200

Listening on arbitrary address

Diffstat:
Msrc/fnet.c | 127++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/fnet.h | 23++++++++++++-----------
Mtest.c | 25+++++++++++++++++++++++++
3 files changed, 157 insertions(+), 18 deletions(-)

diff --git a/src/fnet.c b/src/fnet.c @@ -2,8 +2,14 @@ extern "C" { #endif +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> #include "tidwall/buf.h" @@ -13,14 +19,16 @@ extern "C" { struct fnet_internal_t { struct fnet_t ext; // KEEP AT TOP, allows casting between fnet_internal_t* and fnet_t* - FNET_SOCKET sock; + FNET_SOCKET *fds; + int nfds; FNET_FLAG flags; FNET_CALLBACK(onConnect); FNET_CALLBACK_VA(onData, struct buf *data); FNET_CALLBACK(onClose); }; -struct fnet_t * fnet_listen(const char *address, uint16_t port, struct fnet_connect_options_t *options) { +struct fnet_t * fnet_listen(const char *address, uint16_t port, const struct fnet_options_t *options) { + struct fnet_internal_t *conn; // Checking arguments are given if (!address) { @@ -40,16 +48,117 @@ struct fnet_t * fnet_listen(const char *address, uint16_t port, struct fnet_conn switch(options->proto) { case FNET_PROTO_TCP: // Intentionally empty + // TODO: tcp-specific arg validation break; default: fprintf(stderr, "fnet_listen: unknown protocol\n"); return NULL; } + // 1-to-1 copy, don't touch the options + conn = malloc(sizeof(struct fnet_internal_t)); + conn->ext.proto = options->proto; + conn->ext.status = FNET_STATUS_INITIALIZING; + conn->ext.udata = options->udata; + conn->flags = options->flags; + conn->onConnect = options->onConnect; + conn->onData = options->onData; + conn->onClose = options->onClose; + conn->nfds = 0; + conn->fds = NULL; + + /* struct sockaddr_in servaddr; */ + struct addrinfo hints = {}, *addrs; + char port_str[6] = {}; + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + // Get address info + snprintf(port_str, sizeof(port_str), "%d", port); + int ai_err = getaddrinfo(address, port_str, &hints, &addrs); + if (ai_err != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ai_err)); + fnet_free((struct fnet_t *)conn); + return NULL; + } + + // Count the addresses to listen on + // For example, "localhost" turned to "127.0.0.1" and "::1" + int naddrs = 0; + struct addrinfo *addrinfo = addrs; + while(addrinfo) { + naddrs++; + addrinfo = addrinfo->ai_next; + } + + conn->fds = calloc(naddrs, sizeof(FNET_SOCKET)); + if (!conn->fds) { + fprintf(stderr, "%s\n", strerror(ENOMEM)); + fnet_free((struct fnet_t *)conn); + return NULL; + } + + addrinfo = addrs; + for (; addrinfo ; addrinfo = addrinfo->ai_next ) { + + int fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); + if (fd < 0) { + fprintf(stderr, "socket\n"); + fnet_free((struct fnet_t *)conn); + return NULL; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) { + fprintf(stderr, "setsockopt(SO_REUSEADDR)\n"); + fnet_free((struct fnet_t *)conn); + return NULL; + } + + // TODO: set nonblock + + if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) < 0) { + fprintf(stderr, "bind\n"); + fnet_free((struct fnet_t *)conn); + return NULL; + } + + if (listen(fd, SOMAXCONN) < 0) { + fprintf(stderr, "bind\n"); + fnet_free((struct fnet_t *)conn); + return NULL; + } + + conn->fds[conn->nfds] = fd; + conn->nfds++; + + } + + freeaddrinfo(addrs); + + fprintf(stdout, "All fine and dandy: %d\n", naddrs); + + /* servaddr.sin_family = AF_INET; */ + /* servaddr.sin_addr.s_addr = htonl(INADDR_ANY); */ + /* servaddr.sin_port = htonl(INADDR_ANY); */ + + + /* // TODO: open different kinds of sockets */ + /* conn->sock = socket(AF_INET, SOCK_STREAM, 0); */ + /* if (sock < 0) { */ + /* fprintf(stderr, "fnet_listen: could not create socket\n"); */ + /* fnet_free(conn); */ + /* return NULL; */ + /* } */ + + + + return NULL; } -struct fnet_t * fnet_connect(const char *address, uint16_t port, struct fnet_connect_options_t *options) { +struct fnet_t * fnet_connect(const char *address, uint16_t port, const struct fnet_options_t *options) { // Checking arguments are given if (!address) { @@ -79,13 +188,13 @@ struct fnet_t * fnet_connect(const char *address, uint16_t port, struct fnet_con return NULL; } -FNET_RETURNCODE fnet_process(struct fnet_t *connection) { +FNET_RETURNCODE fnet_process(const struct fnet_t *connection) { struct fnet_internal_t *conn = (struct fnet_internal_t *)connection; // Checking arguments are given if (!conn) { fprintf(stderr, "fnet_process: connection argument is required\n"); - return FNET_RETURNCODE_MISSING_ARGUMENT: + return FNET_RETURNCODE_MISSING_ARGUMENT; } return FNET_RETURNCODE_OK; @@ -93,7 +202,7 @@ FNET_RETURNCODE fnet_process(struct fnet_t *connection) { -FNET_RETURNCODE fnet_write(struct fnet_t *connection, struct buf *buf) { +FNET_RETURNCODE fnet_write(const struct fnet_t *connection, struct buf *buf) { struct fnet_internal_t *conn = (struct fnet_internal_t *)connection; // Checking arguments are given @@ -109,7 +218,7 @@ FNET_RETURNCODE fnet_write(struct fnet_t *connection, struct buf *buf) { return FNET_RETURNCODE_OK; } -FNET_RETURNCODE fnet_close(struct fnet_t *connection) { +FNET_RETURNCODE fnet_close(const struct fnet_t *connection) { struct fnet_internal_t *conn = (struct fnet_internal_t *)connection; // Checking arguments are given @@ -130,6 +239,10 @@ FNET_RETURNCODE fnet_free(struct fnet_t *connection) { return FNET_RETURNCODE_MISSING_ARGUMENT; } + // TODO: check if the connections are closed? + + if (conn->fds) free(conn->fds); + free(conn); return FNET_RETURNCODE_OK; diff --git a/src/fnet.h b/src/fnet.h @@ -19,11 +19,12 @@ extern "C" { #define FNET_RETURNCODE_OK 0 #define FNET_RETURNCODE_MISSING_ARGUMENT 1 -#define FNET_STATUS uint8_t -#define FNET_STATUS_CONNECTING 1 // Client-only status -#define FNET_STATUS_CONNECTED 2 // Client = connected, server = listening -#define FNET_STATUS_ERROR 4 -#define FNET_STATUS_CLOSED 8 +#define FNET_STATUS uint8_t +#define FNET_STATUS_INITIALIZING 0 +#define FNET_STATUS_CONNECTING 1 // Client-only status +#define FNET_STATUS_READY 2 // Client = connected, server = listening +#define FNET_STATUS_ERROR 4 +#define FNET_STATUS_CLOSED 8 #define FNET_CALLBACK(NAME) void (*(NAME))(struct fnet_t *connection, void *udata) #define FNET_CALLBACK_VA(NAME, ...) void (*(NAME))(struct fnet_t *connection, __VA_ARGS__, void *udata) @@ -34,7 +35,7 @@ struct fnet_t { void *udata; }; -struct fnet_connect_options_t { +struct fnet_options_t { FNET_PROTOCOL proto; FNET_FLAG flags; FNET_CALLBACK(onConnect); @@ -43,12 +44,12 @@ struct fnet_connect_options_t { void *udata; }; -struct fnet_t * fnet_listen(const char *address, uint16_t port, struct fnet_connect_options_t *options); -struct fnet_t * fnet_connect(const char *address, uint16_t port, struct fnet_connect_options_t *options); +struct fnet_t * fnet_listen(const char *address, uint16_t port, const struct fnet_options_t *options); +struct fnet_t * fnet_connect(const char *address, uint16_t port, const struct fnet_options_t *options); -FNET_RETURNCODE fnet_process(struct fnet_t *connection); -FNET_RETURNCODE fnet_write(struct fnet_t *connection, struct buf *buf); -FNET_RETURNCODE fnet_close(struct fnet_t *connection); +FNET_RETURNCODE fnet_process(const struct fnet_t *connection); +FNET_RETURNCODE fnet_write(const struct fnet_t *connection, struct buf *buf); +FNET_RETURNCODE fnet_close(const struct fnet_t *connection); FNET_RETURNCODE fnet_free(struct fnet_t *connection); FNET_RETURNCODE fnet_step(); diff --git a/test.c b/test.c @@ -1,3 +1,28 @@ +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> + +#include "fnet.h" + int main() { + uint16_t us = 1337; + /* uint32_t ui = 1337; */ + + const struct fnet_options_t opts = { + .proto = FNET_PROTO_TCP, + .flags = 0, + .onConnect = NULL, + .onData = NULL, + .onClose = NULL, + .udata = NULL, + }; + + struct fnet_t *conn = fnet_listen("::", 1337, &opts); + + sleep(3600); + + printf("d: %d\n", us); + printf("h: %i\n", us); + return 42; }