C library for IPv4 and IPv6 TCP and UDP sockets.
A caller passes an explicit address to bind, and keeps the descriptor for
select. Listening sockets and accepted sockets are non-blocking. A
connected TCP socket and a UDP socket stay blocking. The public header is
include/socket.h. It uses C linkage, so a C++ translation unit can include
it.
- GNU make.
- gcc, unless
CCis set. The C skill uses gcc for syntax checks. - cppcheck, for
make c-check.
make lib writes the static archive build/libsocket.a. The archive is
built as C11 with -Wall -Wextra -Wpedantic -Werror. The compiler is gcc
unless CC is set. make clean removes build/.
make lib
cc -std=c11 -Iinclude -o demo demo.c build/libsocket.amake lib CC=clang selects the compiler. make lib CFLAGS=-g adds flags to
that C11 build. make with no target prints the makefile help.
make update refreshes the makefile skills. make lib and make test do
not need that checkout. make c-check and make version do.
Listen on the IPv4 loopback address and connect to it.
#include "socket.h"
int main(void)
{
int listener = -1;
int client = -1;
if (socket_tcp_listen(&listener, "127.0.0.1", 4545, 16) != SOCKET_OK) {
return 1;
}
if (socket_tcp_connect(&client, "127.0.0.1", 4545) != SOCKET_OK) {
socket_close(&listener);
return 1;
}
socket_close(&client);
socket_close(&listener);
return 0;
}Port 0 lets the system choose the port. socket_tcp_accept takes the
queued connection. The listening descriptor stays open.
Bind takes a numeric address. A host name is rejected.
| Address | Bind result |
|---|---|
127.0.0.1 |
That IPv4 address |
0.0.0.0 |
Every IPv4 interface |
::1 |
That IPv6 address |
:: |
Every IPv6 interface |
fe80::1%lo0 |
That link-local address and zone |
An IPv6 socket is IPv6 only, so :: does not accept IPv4. socket_ipv4 and
socket_ipv6 report whether a text is that kind of address. *valid is 1
or 0.
socket_tcp_connect takes a name or a numeric address and tries each IPv4
and IPv6 result.
Note: Callers serialise use of a given descriptor. New descriptors are close-on-exec.
socket_tcp_listen sets SO_REUSEADDR, makes the socket non-blocking, and
listens. socket_tcp_accept returns SOCKET_AGAIN when nothing is queued.
The accepted socket is non-blocking and has keepalive enabled.
socket_tcp_read reads once. End of file is success and *got is 0. No
data on a non-blocking socket is SOCKET_AGAIN. The call does not close the
socket and does not add a NUL.
socket_tcp_write writes until the buffer is finished, the socket would
block, or a real error occurs. *sent is how many bytes were accepted. A
length of 0 writes nothing.
socket_udp_bind binds one blocking UDP socket. It uses the same address
rules as socket_tcp_listen. Sending and receiving stay with the caller.
| Code | Value | Meaning |
|---|---|---|
SOCKET_OK |
0 |
The call succeeded. |
SOCKET_INVAL |
-2 |
An argument is missing or unusable. Out-pointers stay unchanged. |
SOCKET_IO |
-3 |
A system call failed. |
SOCKET_AGAIN |
-4 |
A non-blocking socket cannot finish yet. |
socket_close(NULL) returns SOCKET_INVAL. Descriptors 0, 1, and 2
stay open. A descriptor that is already -1 is success. After a successful
close, *fd is -1.
int socket_ipv4(const char *text, int *valid);
int socket_ipv6(const char *text, int *valid);
int socket_tcp_listen(int *fd, const char *address, unsigned short port,
int backlog);
int socket_tcp_accept(int listen_fd, int *fd);
int socket_tcp_connect(int *fd, const char *host, unsigned short port);
int socket_tcp_read(int fd, void *buffer, size_t capacity, size_t *got);
int socket_tcp_write(int fd, const void *buffer, size_t length, size_t *sent);
int socket_udp_bind(int *fd, const char *address, unsigned short port);
int socket_close(int *fd);| Name | Purpose |
|---|---|
socket_ipv4 |
Report whether a text is an IPv4 address. |
socket_ipv6 |
Report whether a text is an IPv6 address. |
socket_tcp_listen |
Bind a non-blocking listening socket. |
socket_tcp_accept |
Accept one non-blocking connection. |
socket_tcp_connect |
Connect a blocking socket. |
socket_tcp_read |
Read once from a TCP socket. |
socket_tcp_write |
Write a buffer to a TCP socket. |
socket_udp_bind |
Bind a blocking UDP socket. |
socket_close |
Close a descriptor and store -1. |
The version text is the macro SOCKET_VERSION_STRING in
include/socket.h. It is a dotted semantic version. .bumpversion.toml
is the version source, and a bump updates that macro.
After make init, make version prints the version from
.bumpversion.toml.
make update
make lib
make check
make cleanmake c-check syntax-checks every .c and .h file, then runs cppcheck.
make check runs c-check and then the behaviour tests. make test runs
only the behaviour tests.