diff --git a/.gitignore b/.gitignore index 217f59f..e23530c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ chat_server chat_client udp_server udp_client +http_request diff --git a/Makefile b/Makefile index 9646bd5..ee99078 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CFLAGS=-Wall -Wextra -ggdb -I. LDFLAGS=-lpthread all: hello_server hello_client hello_server_v6 hello_client_v6 chat_server \ - chat_client udp_server udp_client + chat_client udp_server udp_client http_request hello_server: examples/hello_server.c $(CC) $(CFLAGS) -o hello_server examples/hello_server.c $(LDFLAGS) @@ -29,6 +29,9 @@ udp_server: examples/udp_server.c udp_client: examples/udp_client.c $(CC) $(CFLAGS) -o udp_client examples/udp_client.c $(LDFLAGS) +http_request: examples/http_request.c + $(CC) $(CFLAGS) -o http_request examples/http_request.c $(LDFLAGS) + clean: rm -rf chat_server rm -rf chat_client @@ -38,3 +41,4 @@ clean: rm -rf hello_client_v6 rm -rf udp_server rm -rf udp_client + rm -rf http_request diff --git a/examples/http_request.c b/examples/http_request.c new file mode 100644 index 0000000..af12956 --- /dev/null +++ b/examples/http_request.c @@ -0,0 +1,47 @@ +#include + +#define SOCK_IMPLEMENTATION +#include "sock.h" + +int main(void) +{ + SockAddr addr = sock_addr("example.com", 80); + if (addr.type == SOCK_ADDR_INVALID) { + sock_log_errors(); + return 1; + } + + printf("%s:%d\n", addr.str, addr.port); + + Sock *sock = sock_create(addr.type, SOCK_TCP); + if (sock == NULL) { + fprintf(stderr, "sock_create: "); + sock_log_errors(); + return 1; + } + + if (!sock_connect(sock, addr)) { + fprintf(stderr, "sock_connect: "); + sock_log_errors(); + sock_close(sock); + return 1; + } + + const char *req = + "GET / HTTP/1.1\r\n" + "Host: example.com\r\n" + "Connection: close\r\n\r\n"; + + sock_send(sock, req, strlen(req)); + + char res[1024]; + memset(res, 0, sizeof(res)); + while (sock_recv(sock, res, sizeof(res)-1) > 0) { + printf("%s\n", res); + memset(res, 0, sizeof(res)); + } + + sock_close(sock); + + return 0; +} diff --git a/sock.h b/sock.h index 1f0a944..6661709 100644 --- a/sock.h +++ b/sock.h @@ -1,4 +1,4 @@ -// sock - v1.1.0 - MIT License - https://github.com/seajee/sock.h +// sock - v1.2.0 - MIT License - https://github.com/seajee/sock.h #ifndef SOCK_H_ #define SOCK_H_ @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -13,8 +14,6 @@ #include #include -#define SOCK_ADDR_STR_CAPACITY 64 - typedef enum { SOCK_ADDR_INVALID, SOCK_IPV4, @@ -22,9 +21,9 @@ typedef enum { } SockAddrType; typedef struct { - SockAddrType type; // Address type - int port; // Address port - char str[SOCK_ADDR_STR_CAPACITY]; // String representation of the address + SockAddrType type; // Address type + int port; // Address port + char str[INET6_ADDRSTRLEN]; // String representation of the address union { struct sockaddr sockaddr; struct sockaddr_in ipv4; @@ -90,21 +89,42 @@ SockAddr sock_addr(const char *addr, int port) if (inet_pton(AF_INET, addr, &sa.ipv4.sin_addr) == 1) { sa.type = SOCK_IPV4; - sa.len = sizeof(sa.ipv4); sa.ipv4.sin_family = AF_INET; sa.ipv4.sin_port = htons(port); + sa.len = sizeof(sa.ipv4); + strncpy(sa.str, addr, sizeof(sa.str)); } else if (inet_pton(AF_INET6, addr, &sa.ipv6.sin6_addr) == 1) { sa.type = SOCK_IPV6; - sa.len = sizeof(sa.ipv6); sa.ipv6.sin6_family = AF_INET6; sa.ipv6.sin6_port = htons(port); + sa.len = sizeof(sa.ipv6); + strncpy(sa.str, addr, sizeof(sa.str)); } else { - sa.type = SOCK_ADDR_INVALID; - return sa; + struct addrinfo *res; + if (getaddrinfo(addr, NULL, NULL, &res) != 0) { + // TODO: specific errors from getaddrinfo are ignored for logging + sa.type = SOCK_ADDR_INVALID; + return sa; + } + + if (res->ai_family == AF_INET) { + sa.type = SOCK_IPV4; + sa.ipv4 = *(struct sockaddr_in*)res->ai_addr; + sa.ipv4.sin_port = htons(port); + sa.len = sizeof(sa.ipv4); + inet_ntop(AF_INET, &sa.ipv4.sin_addr, sa.str, sizeof(sa.str)); + } else { + sa.type = SOCK_IPV6; + sa.ipv6 = *(struct sockaddr_in6*)res->ai_addr; + sa.ipv6.sin6_port = htons(port); + sa.len = sizeof(sa.ipv6); + inet_ntop(AF_INET6, &sa.ipv6.sin6_addr, sa.str, sizeof(sa.str)); + } + + freeaddrinfo(res); } sa.port = port; - strncpy(sa.str, addr, sizeof(sa.str)); return sa; } @@ -291,6 +311,7 @@ void sock_log_errors(void) /* Revision history: + 1.2.0 (2025-04-26) sock_addr can now resolve hostnames 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