netc

A simple C library for opening network sockets using linux syscalls.
git clone git://depsterr.com/git/netc
Log | Files | Refs | README | LICENSE

commit 0d5d10d8de052b8755a443f39f434ae0cc940f31
parent 07cb89aa18a78decf68813c5e1ec566e52373ab1
Author: depsterr <depsterr@protonmail.com>
Date:   Sat,  4 Jul 2020 19:23:36 +0200

Added listen function

Diffstat:
AISCLICENSE | 26++++++++++++++++++++++++++
MMakefile | 5++++-
MREADME.md | 11++++++++++-
Alisten_example.c | 26++++++++++++++++++++++++++
Mnetc.c | 61++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Anetc.h | 18++++++++++++++++++
Aopen_example.c | 19+++++++++++++++++++
7 files changed, 159 insertions(+), 7 deletions(-)

diff --git a/ISCLICENSE b/ISCLICENSE @@ -0,0 +1,26 @@ +ISC-License + +Copyright 2016-2020 Laslo Hunhold <dev@frign.de> + +Copyright 2004 Ted Unangst <tedu@openbsd.org> +Copyright 2004 Todd C. Miller <Todd.Miller@courtesan.com> +Copyright 2008 Otto Moerbeek <otto@drijf.net> +Copyright 2017-2018 Hiltjo Posthuma <hiltjo@codemadness.org> +Copyright 2017-2018 Quentin Rameau <quinq@fifth.space> +Copyright 2018 Josuah Demangeon <mail@josuah.net> +Copyright 2018 Dominik Schmidt <domischmidt@swissonline.ch> +Copyright 2018 Aaron Burrow <burrows@charstarstar.com> +Copyright 2020 Nihal Jere <nihal@nihaljere.xyz> +Copyright 2020 Rainer Holzner <rholzner@web.de> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile @@ -4,7 +4,10 @@ default: $(CC) netc.c -shared -o netc.so object: $(CC) netc.c -c -o netc.o +examples: object + $(CC) open_example.c netc.o -o open_example + $(CC) listen_example.c netc.o -o listen_example install: default install -Dm755 netc.so $(DESTDIR)$(PREFIX)/lib64/netc.so clean: - rm -f netc.o netc.so + rm -f netc.o netc.so open_example listen_example diff --git a/README.md b/README.md @@ -6,6 +6,15 @@ A simple C library for opening network socket filedescriptors using linux syscal Functions --------- -To open a socket use `netc_open` which takes two arguments, both of type `const char*`, host and port. The function will then return a normal linux file descriptor. +`netc_open` +To open a socket use `netc_open` which takes two arguments, both of type `const char*`, host and port. The function will then return a normal linux file descriptor. (see `open_example.c`) + +`netc_listen` +Open a listener socket file descriptor that's able to accept connections through the accept syscall. (see `listen_example.c`) All functions which can fail may return an error value, to check if a function failed, simply check if it's return value is below zero. If a function failed you may use the `netc_decode_error` to get a string corresponding to the error code. + +Source +------ + +A lot of this code has been taken from other projects, like [quark](https://tools.suckless.org/quark/) by suckless and [irc.c](https://c9x.me/irc/) by c9x. diff --git a/listen_example.c b/listen_example.c @@ -0,0 +1,26 @@ +#include <sys/types.h> +#include <sys/socket.h> + +#include <stdio.h> +#include <unistd.h> + +#include "netc.h" + +int main() { + char buffer[4096]; + int fd; + fd = netc_listen("127.0.0.1", "8080", 100); + + if (fd < 0) { + puts(netc_decode_error(fd)); + return 1; + } + + int cfd; + cfd = accept(fd, 0, 0); + + int size; + size = read(cfd, buffer, sizeof(buffer)); + + write(1, buffer, size); +} diff --git a/netc.c b/netc.c @@ -1,3 +1,8 @@ +/* netc, a simple c networking library. + This all code in this library is licensed under the MIT LICENSE unless otherwise specified. + See the LICENSE file for more details on the MIT LICENSE and read the comments in this file + for more information on licensing */ + #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> @@ -11,19 +16,31 @@ #include <string.h> typedef enum NetcError { + NETC_ERROR_TOP = 0, GET_ADDR_INFO = -1, OPEN_CONNECTION = -2, + SET_SOCK_OPT = -3, + CLOSE = -4, + BIND = -5, + LISTEN = -6, + NETC_ERROR_BOT = -7, } NetcError; -static const char* NetcErrorStrings[] = { +const char* NetcErrorStrings[] = { [GET_ADDR_INFO * -1] = "Call to getaddrinfo failed.", [OPEN_CONNECTION * -1] = "Unable to open a connection.", + [SET_SOCK_OPT * -1] = "Unable to set socket options.", + [CLOSE * -1] = "Unable to close socket.", + [BIND * -1] = "Unable to bind to address.", + [LISTEN * -1] = "Unable to mark socket as listener.", }; const char* netc_decode_error(NetcError err) { - return NetcErrorStrings[err * -1]; + return (err > NETC_ERROR_BOT && err < NETC_ERROR_TOP) ? NetcErrorStrings[err * -1] : "Not a NetcError."; } +/* thank you https://c9x.me/irc/ */ +/* c9x placed their code in public domain, as such I place the contents of this function in public domain */ int netc_open(const char* host, const char* port) { struct addrinfo hints, *res = NULL; int fd = -1; @@ -36,18 +53,52 @@ int netc_open(const char* host, const char* port) { return GET_ADDR_INFO; for(;res;res = res->ai_next) { - if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) + if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) continue; - if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { + if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) { close(fd); continue; } + break; } - if (fd == -1) + if (fd < 0) return OPEN_CONNECTION; freeaddrinfo(res); return fd; } + +/* thank you http://tools.suckless.org/quark/ */ +/* In additon to the MIT LICENSE This function is licensed under the ISC license, + see the ISCLICENSE file or https://git.suckless.org/quark/file/LICENSE.html */ +int netc_listen(const char* host, const char* port, ssize_t connections) { + struct addrinfo *ai, *p, hints = { .ai_flags = AI_NUMERICSERV, .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM }; + int fd = -1; + + if (getaddrinfo(host, port, &hints, &ai)) + return GET_ADDR_INFO; + + for (p = ai; p; p = p->ai_next) { + if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) + continue; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) + return SET_SOCK_OPT; + if (bind(fd, p->ai_addr, p->ai_addrlen) < 0) { + close(fd); + continue; + } + break; + } + + freeaddrinfo(ai); + + if (!p) + return BIND; + + if (listen(fd, connections) < 0) + return LISTEN; + + return fd; +} diff --git a/netc.h b/netc.h @@ -0,0 +1,18 @@ +#include <stdio.h> + +typedef enum NetcError { + NETC_ERROR_TOP = 0, + GET_ADDR_INFO = -1, + OPEN_CONNECTION = -2, + SET_SOCK_OPT = -3, + CLOSE = -4, + BIND = -5, + LISTEN = -6, + NETC_ERROR_BOT = -7, +} NetcError; + +const char* netc_decode_error(NetcError err); + +int netc_open(const char* host, const char* port); + +int netc_listen(const char* host, const char* port, ssize_t connections); diff --git a/open_example.c b/open_example.c @@ -0,0 +1,19 @@ +#include <sys/types.h> +#include <sys/socket.h> + +#include <stdio.h> +#include <unistd.h> + +#include "netc.h" + +int main() { + int fd; + fd = netc_open("127.0.0.1", "8080"); + + if (fd < 0) { + puts(netc_decode_error(fd)); + return 1; + } + + write(fd, "Hello!\n", 7); +}