diff --git a/.gitignore b/.gitignore index bd16395..217f59f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ hello_server hello_client +hello_server_v6 +hello_client_v6 chat_server chat_client udp_server diff --git a/Makefile b/Makefile index 1b675a7..9646bd5 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,8 @@ CC=gcc CFLAGS=-Wall -Wextra -ggdb -I. LDFLAGS=-lpthread -all: hello_server hello_client chat_server chat_client udp_server udp_client - -chat_server: examples/chat_server.c - $(CC) $(CFLAGS) -o chat_server examples/chat_server.c $(LDFLAGS) - -chat_client: examples/chat_client.c - $(CC) $(CFLAGS) -o chat_client examples/chat_client.c $(LDFLAGS) +all: hello_server hello_client hello_server_v6 hello_client_v6 chat_server \ + chat_client udp_server udp_client hello_server: examples/hello_server.c $(CC) $(CFLAGS) -o hello_server examples/hello_server.c $(LDFLAGS) @@ -16,6 +11,18 @@ hello_server: examples/hello_server.c hello_client: examples/hello_client.c $(CC) $(CFLAGS) -o hello_client examples/hello_client.c $(LDFLAGS) +hello_server_v6: examples/hello_server_v6.c + $(CC) $(CFLAGS) -o hello_server_v6 examples/hello_server_v6.c $(LDFLAGS) + +hello_client_v6: examples/hello_client_v6.c + $(CC) $(CFLAGS) -o hello_client_v6 examples/hello_client_v6.c $(LDFLAGS) + +chat_server: examples/chat_server.c + $(CC) $(CFLAGS) -o chat_server examples/chat_server.c $(LDFLAGS) + +chat_client: examples/chat_client.c + $(CC) $(CFLAGS) -o chat_client examples/chat_client.c $(LDFLAGS) + udp_server: examples/udp_server.c $(CC) $(CFLAGS) -o udp_server examples/udp_server.c $(LDFLAGS) @@ -27,5 +34,7 @@ clean: rm -rf chat_client rm -rf hello_server rm -rf hello_client + rm -rf hello_server_v6 + rm -rf hello_client_v6 rm -rf udp_server rm -rf udp_client diff --git a/examples/chat_server.c b/examples/chat_server.c index 28bfedf..574ccc5 100644 --- a/examples/chat_server.c +++ b/examples/chat_server.c @@ -169,7 +169,8 @@ int main(void) } pthread_detach(thread); - printf("INFO: New client connected\n"); + printf("INFO: New client connected from %s:%d\n", client->addr.str, + client->addr.port); } sock_close(server); diff --git a/examples/hello_client_v6.c b/examples/hello_client_v6.c new file mode 100644 index 0000000..c9996f3 --- /dev/null +++ b/examples/hello_client_v6.c @@ -0,0 +1,32 @@ +#include +#include + +#define SOCK_IMPLEMENTATION +#include "sock.h" + +int main(void) +{ + bool err = false; + + Sock *sock = sock_create(SOCK_IPV6, SOCK_TCP); + if (sock == NULL) { err = "create"; goto defer; } + + SockAddr addr = sock_addr("::1", 6969); + + if (!sock_connect(sock, addr)) { err = "connect"; goto defer; } + + const char *msg = "Hello from client!"; + char buf[128]; + memset(buf, 0, sizeof(buf)); + + sock_send(sock, msg, strlen(msg)); + sock_recv(sock, buf, sizeof(buf)); + printf("%s:%d: %.*s\n", sock->addr.str, sock->addr.port, + (int)sizeof(buf), buf); + +defer: + sock_close(sock); + if (err) sock_log_errors(); + + return 0; +} diff --git a/examples/hello_server.c b/examples/hello_server.c index c25c702..e4fec26 100644 --- a/examples/hello_server.c +++ b/examples/hello_server.c @@ -4,7 +4,8 @@ #define SOCK_IMPLEMENTATION #include "sock.h" -int main(void) { +int main(void) +{ char *err = "None"; Sock *sock = sock_create(SOCK_IPV4, SOCK_TCP); diff --git a/examples/hello_server_v6.c b/examples/hello_server_v6.c new file mode 100644 index 0000000..9063b06 --- /dev/null +++ b/examples/hello_server_v6.c @@ -0,0 +1,36 @@ +#include + +#define SOCK_IMPLEMENTATION +#include "sock.h" + +int main(void) +{ + bool err = false; + + Sock *sock = sock_create(SOCK_IPV6, SOCK_TCP); + if (sock == NULL) { err = true; goto close; } + + SockAddr addr = sock_addr("::", 6969); + if (!sock_bind(sock, addr)) { err = true; goto close; } + if (!sock_listen(sock, 16)) { err = true; goto close; } + + Sock *client = sock_accept(sock); + if (client == NULL) { err = true; goto close; } + + const char *msg = "Hello from server!"; + char buf[128]; + memset(buf, 0, sizeof(buf)); + + sock_send(client, msg, strlen(msg)); + sock_recv(client, buf, sizeof(buf)); + printf("%s:%d: %.*s\n", client->addr.str, client->addr.port, + (int)sizeof(buf), buf); + + sock_close(client); + +close: + sock_close(sock); + if (err) sock_log_errors(); + + return 0; +} diff --git a/sock.h b/sock.h index 89c5061..1f0a944 100644 --- a/sock.h +++ b/sock.h @@ -1,10 +1,11 @@ -// sock - v1.0.3 - MIT License - https://github.com/seajee/sock.h +// sock - v1.1.0 - MIT License - https://github.com/seajee/sock.h #ifndef SOCK_H_ #define SOCK_H_ #include #include +#include #include #include #include @@ -76,6 +77,9 @@ ssize_t sock_recvfrom(Sock *sock, void *buf, size_t size, SockAddr *addr); // Close a socket void sock_close(Sock *sock); +// Log last errors to stderr +void sock_log_errors(void); + #endif // SOCK_H_ #ifdef SOCK_IMPLEMENTATION @@ -111,7 +115,6 @@ Sock *sock_create(SockAddrType domain, SockType type) if (sock == NULL) { return NULL; } - memset(sock, 0, sizeof(*sock)); sock->type = type; @@ -177,12 +180,37 @@ Sock *sock_accept(Sock *sock) if (res == NULL) { return NULL; } - memset(res, 0, sizeof(*res)); res->type = sock->type; res->fd = fd; + SockAddr *addr = &res->addr; + addr->len = sizeof(addr->sockaddr); + getpeername(res->fd, &addr->sockaddr, &addr->len); + // TODO: This is duplicated code from sock_recvfrom + switch (addr->sockaddr.sa_family) { + case AF_INET: { + struct sockaddr_in *ipv4 = &addr->ipv4; + addr->type = SOCK_IPV4; + addr->port = ntohs(ipv4->sin_port); + addr->len = sizeof(*ipv4); + inet_ntop(AF_INET, &ipv4->sin_addr, addr->str, sizeof(addr->str)); + } break; + + case AF_INET6: { + struct sockaddr_in6 *ipv6 = &addr->ipv6; + addr->type = SOCK_IPV6; + addr->port = ntohs(ipv6->sin6_port); + addr->len = sizeof(*ipv6); + inet_ntop(AF_INET6, &ipv6->sin6_addr, addr->str, sizeof(addr->str)); + } break; + + default: { + assert(false && "Unreachable address family"); + } break; + } + return res; } @@ -192,6 +220,8 @@ bool sock_connect(Sock *sock, SockAddr addr) return false; } + sock->addr = addr; + return true; } @@ -251,11 +281,19 @@ void sock_close(Sock *sock) free(sock); } +void sock_log_errors(void) +{ + fprintf(stderr, "SOCK ERROR: %s\n", strerror(errno)); +} + #endif // SOCK_IMPLEMENTATION /* Revision history: + 1.1.0 (2025-04-26) New sock_log_errors function + Fill new Sock's SockAddr after a sock_accept + Save remove SockAddr in Sock in sock_connect 1.0.3 (2025-04-25) Fix incorrect usage of inet_pton 1.0.2 (2025-04-25) Fix sock_recvfrom not recognizing the address family