diff options
Diffstat (limited to 'src/socket')
| -rw-r--r-- | src/socket/socket.h | 20 | ||||
| -rw-r--r-- | src/socket/socket_internal.h | 11 | ||||
| -rw-r--r-- | src/socket/socket_linux.c | 170 | ||||
| -rw-r--r-- | src/socket/socket_windows.c | 122 |
4 files changed, 191 insertions, 132 deletions
diff --git a/src/socket/socket.h b/src/socket/socket.h index bb42a3d..18e3040 100644 --- a/src/socket/socket.h +++ b/src/socket/socket.h @@ -1,21 +1,20 @@ #pragma once +#include <al/types.h> +#include <al/str.h> + #ifndef _WIN32 #include <unistd.h> #include <sys/socket.h> +#include <sys/un.h> +#include <sys/eventfd.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <netinet/in.h> #include <poll.h> -#include <sys/un.h> -#include <sys/eventfd.h> #else #include "../winwrap.h" #endif -#include <al/types.h> -#include <al/str.h> - enum { AKI_SOCKET_TCP = 0, AKI_SOCKET_UDP, @@ -26,10 +25,11 @@ struct aki_socket { u8 type; #ifndef _WIN32 s32 fd; - struct sockaddr_in addr_in; + struct addrinfo *addrinfo; struct sockaddr_un addr_un; #else SOCKET fd; + s32 internal_fd; SOCKADDR_IN addr_in; #endif }; @@ -62,9 +62,11 @@ void aki_socket_set_nodelay(struct aki_socket *sock, s32 nodelay); void aki_socket_set_send_buf(struct aki_socket *sock, u32 sndbuf); u32 aki_socket_get_send_buf(struct aki_socket *sock); -bool aki_socket_listen(struct aki_socket *sock, str *addr, s32 port); +bool aki_socket_set(struct aki_socket *sock, str *addr, u16 port); +bool aki_socket_bind(struct aki_socket *sock, str *addr, u16 port); +bool aki_socket_listen(struct aki_socket *sock); bool aki_socket_accept(struct aki_socket *sock, struct aki_socket *c); -bool aki_socket_connect(struct aki_socket *sock, str *addr, s32 port); +bool aki_socket_connect(struct aki_socket *sock, str *addr, u16 port); s32 aki_socket_get_fd(struct aki_socket *sock); diff --git a/src/socket/socket_internal.h b/src/socket/socket_internal.h new file mode 100644 index 0000000..33f6a7b --- /dev/null +++ b/src/socket/socket_internal.h @@ -0,0 +1,11 @@ +#pragma once + +#include <al/str.h> + +static str *ipany = al_str_c("0.0.0.0"); +static inline str *aki_socket_display_addr(str *addr) +{ + return addr ? addr : ipany; +} + +#define aki_socket_printf_addr(addr) AL_STR_PRINTF(aki_socket_display_addr(addr)) diff --git a/src/socket/socket_linux.c b/src/socket/socket_linux.c index adab91b..753f6b9 100644 --- a/src/socket/socket_linux.c +++ b/src/socket/socket_linux.c @@ -1,5 +1,4 @@ #include <al/log.h> -#include <unistd.h> #include <sys/fcntl.h> #include <netinet/tcp.h> #include <netdb.h> @@ -7,6 +6,7 @@ #include "../util/error.h" #include "socket.h" +#include "socket_internal.h" void aki_fd_set_blocking(s32 fd, bool blocking) { @@ -31,7 +31,7 @@ bool aki_socket_init(struct aki_socket *sock) { switch (sock->type) { case AKI_SOCKET_TCP: - sock->fd = socket(AF_INET, SOCK_STREAM, 0); + sock->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); break; case AKI_SOCKET_UDP: sock->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -39,6 +39,8 @@ bool aki_socket_init(struct aki_socket *sock) case AKI_SOCKET_UNIX: sock->fd = socket(AF_UNIX, SOCK_STREAM, 0); break; + default: + al_assert_and_return(false); } if (sock->fd < 0) { @@ -46,6 +48,8 @@ bool aki_socket_init(struct aki_socket *sock) return false; } + sock->addrinfo = NULL; + return true; } @@ -56,8 +60,7 @@ void aki_socket_set_blocking(struct aki_socket *sock, bool blocking) void aki_socket_set_nodelay(struct aki_socket *sock, s32 nodelay) { - //al_assert(sock->type == AKI_SOCKET_TCP); - if (sock->type != AKI_SOCKET_TCP) return; // TODO: + al_assert(sock->type == AKI_SOCKET_TCP); setsockopt(sock->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)); } @@ -91,141 +94,155 @@ void aki_socket_set_recv_buf(struct aki_socket *sock, u32 rcvbuf) al_assert(aki_socket_get_recv_buf(sock) == receive_queue_size); } -#define al_log_socket_err(func) \ - al_log_error("socket", #func"(%.*s:%d) failed: %s (%d).", \ - AL_STR_PRINTF(addr), port, aki_strerror(errno), errno); +static bool parse_address(struct aki_socket *sock, str *addr, u16 port) +{ + struct addrinfo hints = { 0 }; + hints.ai_family = AF_INET; + switch (sock->type) { + case AKI_SOCKET_TCP: + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + break; + case AKI_SOCKET_UDP: + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + break; + } + + char *c_str = addr ? al_str_to_c_str(addr) : NULL; + if (!c_str) hints.ai_flags = AI_PASSIVE; + char port_str[6]; + al_sprintf(port_str, "%hu", port); + s32 status = getaddrinfo(c_str, port_str, &hints, &sock->addrinfo); + al_free(c_str); + if (status != 0) { + al_log_error("socket", "Failed to parse address (%s).", gai_strerror(status)); + return false; + } + + return true; +} + +bool aki_socket_set(struct aki_socket *sock, str *addr, u16 port) +{ + al_assert(sock->type == AKI_SOCKET_UDP); + return parse_address(sock, addr, port); +} -bool aki_socket_listen(struct aki_socket *sock, str *addr, s32 port) +bool aki_socket_bind(struct aki_socket *sock, str *addr, u16 port) { struct sockaddr *saddr = NULL; socklen_t addrlen = 0; switch (sock->type) { - case AKI_SOCKET_TCP: { - sock->addr_in.sin_family = AF_INET; - sock->addr_in.sin_addr.s_addr = htonl(INADDR_ANY); - sock->addr_in.sin_port = htons(port); - saddr = (struct sockaddr *)&sock->addr_in; - addrlen = sizeof(sock->addr_in); + case AKI_SOCKET_TCP: + case AKI_SOCKET_UDP: { + if (!parse_address(sock, addr, port)) return false; + saddr = sock->addrinfo->ai_addr; + addrlen = sock->addrinfo->ai_addrlen; break; } case AKI_SOCKET_UNIX: { + al_assert(addr); sock->addr_un.sun_family = AF_UNIX; char *c_str = al_str_to_c_str(addr); al_memcpy(sock->addr_un.sun_path, c_str, al_strlen(c_str) + 1); + unlink(c_str); al_free(c_str); saddr = (struct sockaddr *)&sock->addr_un; addrlen = sizeof(sock->addr_un); break; } - case AKI_SOCKET_UDP: - al_assert(false); + default: + al_assert_and_return(false); } if (bind(sock->fd, saddr, addrlen) < 0) { - al_log_socket_err(bind) + al_log_error("socket", "bind(%.*s:%hu) failed: %s (%d).", + aki_socket_printf_addr(addr), port, aki_strerror(errno), errno); return false; } + al_log_info("socket", "Socket bound to %.*s:%hu.", aki_socket_printf_addr(addr), port); + + return true; +} + +bool aki_socket_listen(struct aki_socket *sock) +{ + al_assert(sock->type == AKI_SOCKET_TCP || sock->type == AKI_SOCKET_UNIX); + if (listen(sock->fd, SOMAXCONN) < 0) { - al_log_socket_err(listen) + al_log_error("socket", "listen() failed: %s (%d).", aki_strerror(errno), errno); return false; } - al_log_info("socket", "Listening on %.*s:%d.", AL_STR_PRINTF(addr), port); + al_log_info("socket", "Listening."); return true; } bool aki_socket_accept(struct aki_socket *sock, struct aki_socket *cl) { - cl->type = sock->type; + al_assert(sock->type == AKI_SOCKET_TCP || sock->type == AKI_SOCKET_UNIX); + cl->type = sock->type; struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - if ((cl->fd = accept(sock->fd, (struct sockaddr *)&addr, &len)) == -1) { + socklen_t addrlen = sizeof(addr); + if ((cl->fd = accept(sock->fd, (struct sockaddr *)&addr, &addrlen)) == -1) { al_log_error("socket", "accept() failed: %s (%d).", aki_strerror(errno), errno); return false; } + cl->addrinfo = NULL; + switch (cl->type) { case AKI_SOCKET_TCP: { - s32 port = 0; - char ipstr[INET6_ADDRSTRLEN] = { 0 }; + u16 port = 0; + char addr_str[INET6_ADDRSTRLEN] = { 0 }; if (addr.ss_family == AF_INET) { struct sockaddr_in *saddr = (struct sockaddr_in *)&addr; port = ntohs(saddr->sin_port); - inet_ntop(AF_INET, &saddr->sin_addr, ipstr, sizeof(ipstr)); + inet_ntop(AF_INET, &saddr->sin_addr, addr_str, sizeof(addr_str)); } else if (addr.ss_family == AF_INET6) { struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)&addr; port = ntohs(saddr->sin6_port); - inet_ntop(AF_INET6, &saddr->sin6_addr, ipstr, sizeof(ipstr)); + inet_ntop(AF_INET6, &saddr->sin6_addr, addr_str, sizeof(addr_str)); } - al_log_info("socket", "Connection from %s:%d.", ipstr, port); + al_log_info("socket", "Connection from %s:%hu.", addr_str, port); break; } case AKI_SOCKET_UNIX: al_log_info("socket", "Connection on UNIX socket."); break; - case AKI_SOCKET_UDP: - al_assert(false); } return true; } -bool aki_socket_connect(struct aki_socket *sock, str *addr, s32 port) +bool aki_socket_connect(struct aki_socket *sock, str *addr, u16 port) { + s32 ret; switch (sock->type) { case AKI_SOCKET_TCP: - case AKI_SOCKET_UDP: { - char *c_str = al_str_to_c_str(addr); - struct hostent *hptr = gethostbyname(c_str); - al_free(c_str); - - if (!hptr) { - al_log_error("socket", "Failed to parse address."); - return false; - } - - if (hptr->h_addrtype != AF_INET) { - al_log_error("socket", "Bad address family."); - return false; - } - - sock->addr_in.sin_family = AF_INET; - sock->addr_in.sin_addr.s_addr = ((struct in_addr *)hptr->h_addr_list[0])->s_addr; - sock->addr_in.sin_port = htons(port); - - break; - } - default: - break; - } - - switch (sock->type) { - case AKI_SOCKET_TCP: - case AKI_SOCKET_UDP: { - s32 ret = connect(sock->fd, (struct sockaddr *)&sock->addr_in, sizeof(sock->addr_in)); - if (ret != 0 && errno != EINPROGRESS) { - al_log_socket_err(connect) - return false; - } + case AKI_SOCKET_UDP: + if (!parse_address(sock, addr, port)) return false; + ret = connect(sock->fd, sock->addrinfo->ai_addr, sock->addrinfo->ai_addrlen); break; - } - case AKI_SOCKET_UNIX: { + case AKI_SOCKET_UNIX: sock->addr_un.sun_family = AF_UNIX; al_memcpy(sock->addr_un.sun_path, addr->data, addr->len); sock->addr_un.sun_path[addr->len] = '\0'; - if (connect(sock->fd, (struct sockaddr *)&sock->addr_un, sizeof(sock->addr_un)) < 0) { - al_log_socket_err(connect) - return false; - } + ret = connect(sock->fd, (struct sockaddr *)&sock->addr_un, sizeof(sock->addr_un)); break; - } default: - al_assert(false); - break; + al_assert_and_return(false); + } + + if (ret != 0 && errno != EINPROGRESS) { + al_log_error("socket", "connect(%.*s:%hu) failed: %s (%d).", + aki_socket_printf_addr(addr), port, aki_strerror(errno), errno); + return false; } return true; @@ -243,13 +260,12 @@ ssize_t aki_socket_write(struct aki_socket *sock, void *buf, size_t size) ssize_t aki_socket_sendto(struct aki_socket *sock, void *buf, size_t size) { - return sendto(sock->fd, buf, size, 0, (const struct sockaddr *)&sock->addr_in, sizeof(sock->addr_in)); + return sendto(sock->fd, buf, size, 0, sock->addrinfo->ai_addr, sock->addrinfo->ai_addrlen); } ssize_t aki_socket_recvfrom(struct aki_socket *sock, void *buf, size_t size) { - socklen_t addrlen = sizeof(sock->addr_in); - return recvfrom(sock->fd, buf, size, 0, (struct sockaddr *)&sock->addr_in, &addrlen); + return recvfrom(sock->fd, buf, size, 0, sock->addrinfo->ai_addr, &sock->addrinfo->ai_addrlen); } s32 aki_socket_get_fd(struct aki_socket *sock) @@ -265,4 +281,8 @@ void aki_socket_shutdown(struct aki_socket *sock) void aki_socket_close(struct aki_socket *sock) { close(sock->fd); + if (sock->addrinfo) { + freeaddrinfo(sock->addrinfo); + sock->addrinfo = NULL; + } } diff --git a/src/socket/socket_windows.c b/src/socket/socket_windows.c index a7192d8..013a5bd 100644 --- a/src/socket/socket_windows.c +++ b/src/socket/socket_windows.c @@ -1,116 +1,142 @@ #include <al/log.h> #include "socket.h" +#include "socket_internal.h" -bool aki_socket_init(struct aki_socket *s) +bool aki_socket_init(struct aki_socket *sock) { - switch (s->type) { + al_assert(sock->type == AKI_SOCKET_TCP); + + switch (sock->type) { case AKI_SOCKET_TCP: - s->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + sock->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); break; - case AKI_SOCKET_UDP: - al_assert(false); - return false; - case AKI_SOCKET_UNIX: - al_assert(false); - return false; } - if (s->sock == INVALID_SOCKET) { + if (sock->fd == INVALID_SOCKET) { al_log_error("socket", "socket() failed: %d.", WSAGetLastError()); return false; } + sock->internal_fd = _open_osfhandle(sock->fd, 0); + return true; } -void aki_socket_set_blocking(struct aki_socket *s, bool blocking) +void aki_socket_set_blocking(struct aki_socket *sock, bool blocking) { u_long mode = blocking ? 0 : 1; - ioctlsocket(s->sock, FIONBIO, &mode); + ioctlsocket(sock->fd, FIONBIO, &mode); } -void aki_socket_set_nodelay(struct aki_socket *s, s32 nodelay) +void aki_socket_set_nodelay(struct aki_socket *sock, s32 nodelay) { - (void)s; + (void)sock; (void)nodelay; } -#define al_log_socket_err(func) \ - al_log_error("socket", #func"(%.*s:%d) failed: %d.", \ - AL_STR_PRINTF(addr), port, WSAGetLastError()); +bool aki_socket_set(struct aki_socket *sock, str *addr, u16 port) +{ + (void)sock; + (void)addr; + (void)port; + return false; +} -bool aki_socket_listen(struct aki_socket *s, str *addr, s32 port) +bool aki_socket_bind(struct aki_socket *sock, str *addr, u16 port) { - s->addr_in.sin_family = AF_INET; - s->addr_in.sin_addr.s_addr = INADDR_ANY; - s->addr_in.sin_port = aki_htons(port); - al_memset(s->addr_in.sin_zero, '\0', 8); - if (bind(s->sock, (SOCKADDR *)&s->addr_in, sizeof(s->addr_in)) == SOCKET_ERROR) { - al_log_socket_err(bind); + sock->addr_in.sin_family = AF_INET; + sock->addr_in.sin_addr.s_addr = INADDR_ANY; + sock->addr_in.sin_port = aki_htons(port); + al_memset(sock->addr_in.sin_zero, '\0', sizeof(sock->addr_in.sin_zero)); + if (bind(sock->fd, (SOCKADDR *)&sock->addr_in, sizeof(sock->addr_in)) == SOCKET_ERROR) { + al_log_error("socket", "bind(%.*s:%hu) failed: %d.", + aki_socket_printf_addr(addr), port, WSAGetLastError()); return false; } - if (listen(s->sock, SOMAXCONN) == SOCKET_ERROR) { - al_log_socket_err(listen); + + al_log_info("socket", "Socket bound to %.*s:%hu.", aki_socket_printf_addr(addr), port); + + return true; +} + +bool aki_socket_listen(struct aki_socket *sock) +{ + if (listen(sock->fd, SOMAXCONN) == SOCKET_ERROR) { + al_log_error("socket", "listen() failed: %d.", WSAGetLastError()); return false; } + + al_log_info("socket", "Listening."); + return true; } -bool aki_socket_accept(struct aki_socket *s, struct aki_socket *c) +bool aki_socket_accept(struct aki_socket *sock, struct aki_socket *cl) { - c->type = s->type; - if ((c->sock = accept(s->sock, NULL, NULL)) == INVALID_SOCKET) { + cl->type = sock->type; + if ((cl->fd = accept(sock->fd, NULL, NULL)) == INVALID_SOCKET) { + al_log_error("socket", "accept() failed: %d.", WSAGetLastError()); return false; } + cl->internal_fd = _open_osfhandle(cl->fd, 0); return true; } -bool aki_socket_connect(struct aki_socket *s, str *addr, s32 port) +bool aki_socket_connect(struct aki_socket *sock, str *addr, u16 port) { - s->addr_in.sin_family = AF_INET; + sock->addr_in.sin_family = AF_INET; char *c_str = al_str_to_c_str(addr); - s->addr_in.sin_addr.s_addr = inet_addr(c_str); + sock->addr_in.sin_addr.s_addr = inet_addr(c_str); al_free(c_str); - s->addr_in.sin_port = aki_htons(port); - al_memset(s->addr_in.sin_zero, '\0', 8); - s32 ret = connect(s->sock, (SOCKADDR *)&s->addr_in, sizeof(s->addr_in)); + sock->addr_in.sin_port = aki_htons(port); + al_memset(sock->addr_in.sin_zero, '\0', sizeof(sock->addr_in.sin_zero)); + s32 ret = connect(sock->fd, (SOCKADDR *)&sock->addr_in, sizeof(sock->addr_in)); if (ret == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { - al_log_socket_err(connect); + al_log_error("socket", "connect() failed: %d.", WSAGetLastError()); return false; } return true; } -s32 aki_socket_get_fd(struct aki_socket *s) +s32 aki_socket_get_fd(struct aki_socket *sock) +{ + return sock->internal_fd; +} + +ssize_t aki_socket_read(struct aki_socket *sock, void *buf, size_t size) { - return _open_osfhandle(s->sock, 0); + return recv(sock->fd, buf, (s32)size, 0); } -ssize_t aki_socket_read(struct aki_socket *s, void *buf, size_t size) +ssize_t aki_socket_write(struct aki_socket *sock, void *buf, size_t size) { - return recv(s->sock, buf, (s32)size, 0); + return send(sock->fd, buf, (s32)size, 0); } -ssize_t aki_socket_write(struct aki_socket *s, void *buf, size_t size) +ssize_t aki_socket_sendto(struct aki_socket *sock, void *buf, size_t size) { - return send(s->sock, buf, (s32)size, 0); + (void)sock; + (void)buf; + (void)size; + return 0; } -ssize_t aki_socket_sendto(struct aki_socket *s, void *buf, size_t size) +ssize_t aki_socket_recvfrom(struct aki_socket *sock, void *buf, size_t size) { - (void)s; + (void)sock; (void)buf; (void)size; return 0; } -void aki_socket_shutdown(struct aki_socket *s) +void aki_socket_shutdown(struct aki_socket *sock) { - if (shutdown(s->sock, SD_SEND) == SOCKET_ERROR) {} + if (shutdown(sock->fd, SD_BOTH) == SOCKET_ERROR) {} } -void aki_socket_close(struct aki_socket *s) +void aki_socket_close(struct aki_socket *sock) { - closesocket(s->sock); + _close(sock->internal_fd); + //closesocket(sock->fd); } |