fnet.c

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

commit f755dcac74463f5a776b5f15d16729a97d9ef54f
parent 280593786a4446d195e255b6062b0a909ae11d5b
Author: Yersa Nordman <yersa@finwo.nl>
Date:   Wed,  2 Aug 2023 01:00:54 +0200

Implemented fnet_connect fn

Diffstat:
Msrc/fnet.c | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 83 insertions(+), 2 deletions(-)

diff --git a/src/fnet.c b/src/fnet.c @@ -208,6 +208,7 @@ struct fnet_t * fnet_listen(const char *address, uint16_t port, const struct fne } struct fnet_t * fnet_connect(const char *address, uint16_t port, const struct fnet_options_t *options) { + struct fnet_internal_t *conn; // Checking arguments are given if (!address) { @@ -215,7 +216,7 @@ struct fnet_t * fnet_connect(const char *address, uint16_t port, const struct fn return NULL; } if (!port) { - fprintf(stderr, "fnet_listen: port argument is required\n"); + fprintf(stderr, "fnet_connect: port argument is required\n"); return NULL; } if (!options) { @@ -233,8 +234,88 @@ struct fnet_t * fnet_connect(const char *address, uint16_t port, const struct fn return NULL; } + // 1-to-1 copy, don't touch the options + conn = _fnet_init(options); + + /* 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 = malloc(sizeof(FNET_SOCKET)); + if (!conn->fds) { + fprintf(stderr, "%s\n", strerror(ENOMEM)); + fnet_free((struct fnet_t *)conn); + freeaddrinfo(addrs); + return NULL; + } + + fprintf(stderr, "Addresses: %d\n", naddrs); + + 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); + freeaddrinfo(addrs); + return NULL; + } + + // Skip found address on failure to connect + if (connect(fd, addrinfo->ai_addr, sizeof(struct sockaddr))) { + close(fd); + continue; + } + + if (setnonblock(fd) < 0) { + close(fd); + fprintf(stderr, "setnonblock\n"); + fnet_free((struct fnet_t *)conn); + freeaddrinfo(addrs); + return NULL; + } + + conn->fds[conn->nfds] = fd; + conn->nfds++; + + // Only need 1 connection + break; + } + + freeaddrinfo(addrs); + + // Could not connect, might be unreachable, might be something else + // We're not checking for the WHY here + if (conn->nfds != 1) { + fnet_free((struct fnet_t *)conn); + return NULL; + } - return NULL; + conn->ext.status = FNET_STATUS_CONNECTED; + return conn; } FNET_RETURNCODE fnet_process(const struct fnet_t *connection) {