#include "net.h" #include #include #include "log.h" #ifdef __WINDOWS__ typedef int socklen_t; #else # include # include # include # include # include # define SOCKET_ERROR -1 typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr SOCKADDR; typedef struct in_addr IN_ADDR; #endif static void net_perror(const char *s) { #ifdef _WIN32 int error = WSAGetLastError(); char *wsa_message; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &wsa_message, 0, NULL); // no explicit '\n', wsa_message already contains a trailing '\n' fprintf(stderr, "%s: [%d] %s", s, error, wsa_message); LocalFree(wsa_message); #else perror(s); #endif } socket_t net_connect(uint32_t addr, uint16_t port) { socket_t sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { net_perror("socket"); return INVALID_SOCKET; } SOCKADDR_IN sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(addr); sin.sin_port = htons(port); if (connect(sock, (SOCKADDR *) &sin, sizeof(sin)) == SOCKET_ERROR) { net_perror("connect"); net_close(sock); return INVALID_SOCKET; } return sock; } socket_t net_listen(uint32_t addr, uint16_t port, int backlog) { socket_t sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { net_perror("socket"); return INVALID_SOCKET; } int reuse = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(reuse)) == -1) { net_perror("setsockopt(SO_REUSEADDR)"); } SOCKADDR_IN sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(addr); // htonl() harmless on INADDR_ANY sin.sin_port = htons(port); if (bind(sock, (SOCKADDR *) &sin, sizeof(sin)) == SOCKET_ERROR) { net_perror("bind"); net_close(sock); return INVALID_SOCKET; } if (listen(sock, backlog) == SOCKET_ERROR) { net_perror("listen"); net_close(sock); return INVALID_SOCKET; } return sock; } socket_t net_accept(socket_t server_socket) { SOCKADDR_IN csin; socklen_t sinsize = sizeof(csin); return accept(server_socket, (SOCKADDR *) &csin, &sinsize); } ssize_t net_recv(socket_t socket, void *buf, size_t len) { return recv(socket, buf, len, 0); } ssize_t net_recv_all(socket_t socket, void *buf, size_t len) { return recv(socket, buf, len, MSG_WAITALL); } ssize_t net_send(socket_t socket, const void *buf, size_t len) { return send(socket, buf, len, 0); } ssize_t net_send_all(socket_t socket, const void *buf, size_t len) { size_t copied = 0; ssize_t w = 0; while (len > 0) { w = send(socket, buf, len, 0); if (w == -1) { return copied ? (ssize_t) copied : -1; } len -= w; buf = (char *) buf + w; copied += w; } return copied; } bool net_shutdown(socket_t socket, int how) { return !shutdown(socket, how); } bool net_init(void) { #ifdef __WINDOWS__ WSADATA wsa; int res = WSAStartup(MAKEWORD(2, 2), &wsa) < 0; if (res < 0) { LOGC("WSAStartup failed with error %d", res); return false; } #endif return true; } void net_cleanup(void) { #ifdef __WINDOWS__ WSACleanup(); #endif } bool net_close(socket_t socket) { #ifdef __WINDOWS__ return !closesocket(socket); #else return !close(socket); #endif }