| |
| #include "pipe/p_compiler.h" |
| #include "util/u_network.h" |
| #include "util/u_debug.h" |
| #include "util/u_string.h" |
| |
| #include <stdio.h> |
| #if defined(PIPE_SUBSYSTEM_WINDOWS_USER) |
| # include <winsock2.h> |
| # include <windows.h> |
| # include <ws2tcpip.h> |
| #elif defined(PIPE_OS_UNIX) |
| # include <sys/socket.h> |
| # include <netinet/in.h> |
| # include <unistd.h> |
| # include <fcntl.h> |
| # include <netdb.h> |
| #else |
| # warning "No socket implementation" |
| #endif |
| |
| boolean |
| u_socket_init(void) |
| { |
| #if defined(PIPE_SUBSYSTEM_WINDOWS_USER) |
| WORD wVersionRequested; |
| WSADATA wsaData; |
| int err; |
| |
| /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ |
| wVersionRequested = MAKEWORD(1, 1); |
| |
| err = WSAStartup(wVersionRequested, &wsaData); |
| if (err != 0) { |
| debug_printf("WSAStartup failed with error: %d\n", err); |
| return FALSE; |
| } |
| return TRUE; |
| #elif defined(PIPE_HAVE_SOCKETS) |
| return TRUE; |
| #else |
| return FALSE; |
| #endif |
| } |
| |
| void |
| u_socket_stop(void) |
| { |
| #if defined(PIPE_SUBSYSTEM_WINDOWS_USER) |
| WSACleanup(); |
| #endif |
| } |
| |
| void |
| u_socket_close(int s) |
| { |
| if (s < 0) |
| return; |
| |
| #if defined(PIPE_OS_UNIX) |
| shutdown(s, SHUT_RDWR); |
| close(s); |
| #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER) |
| shutdown(s, SD_BOTH); |
| closesocket(s); |
| #else |
| assert(0); |
| #endif |
| } |
| |
| int u_socket_accept(int s) |
| { |
| #if defined(PIPE_HAVE_SOCKETS) |
| return accept(s, NULL, NULL); |
| #else |
| return -1; |
| #endif |
| } |
| |
| int |
| u_socket_send(int s, void *data, size_t size) |
| { |
| #if defined(PIPE_HAVE_SOCKETS) |
| return send(s, data, size, 0); |
| #else |
| return -1; |
| #endif |
| } |
| |
| int |
| u_socket_peek(int s, void *data, size_t size) |
| { |
| #if defined(PIPE_HAVE_SOCKETS) |
| return recv(s, data, size, MSG_PEEK); |
| #else |
| return -1; |
| #endif |
| } |
| |
| int |
| u_socket_recv(int s, void *data, size_t size) |
| { |
| #if defined(PIPE_HAVE_SOCKETS) |
| return recv(s, data, size, 0); |
| #else |
| return -1; |
| #endif |
| } |
| |
| int |
| u_socket_connect(const char *hostname, uint16_t port) |
| { |
| #if defined(PIPE_HAVE_SOCKETS) |
| int s, r; |
| struct addrinfo hints, *addr; |
| char portString[20]; |
| |
| memset(&hints, 0, sizeof hints); |
| hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version |
| hints.ai_socktype = SOCK_STREAM; |
| |
| util_snprintf(portString, sizeof(portString), "%d", port); |
| |
| r = getaddrinfo(hostname, portString, NULL, &addr); |
| if (r != 0) { |
| return -1; |
| } |
| |
| s = socket(addr->ai_family, SOCK_STREAM, IPPROTO_TCP); |
| if (s < 0) { |
| freeaddrinfo(addr); |
| return -1; |
| } |
| |
| if (connect(s, addr->ai_addr, (int) addr->ai_addrlen)) { |
| u_socket_close(s); |
| freeaddrinfo(addr); |
| return -1; |
| } |
| |
| freeaddrinfo(addr); |
| |
| return s; |
| #else |
| assert(0); |
| return -1; |
| #endif |
| } |
| |
| int |
| u_socket_listen_on_port(uint16_t portnum) |
| { |
| #if defined(PIPE_HAVE_SOCKETS) |
| int s; |
| struct sockaddr_in sa; |
| memset(&sa, 0, sizeof(struct sockaddr_in)); |
| |
| sa.sin_family = AF_INET; |
| sa.sin_port = htons(portnum); |
| |
| s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
| if (s < 0) |
| return -1; |
| |
| if (bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) == -1) { |
| u_socket_close(s); |
| return -1; |
| } |
| |
| listen(s, 0); |
| |
| return s; |
| #else |
| assert(0); |
| return -1; |
| #endif |
| } |
| |
| void |
| u_socket_block(int s, boolean block) |
| { |
| #if defined(PIPE_OS_UNIX) |
| int old = fcntl(s, F_GETFL, 0); |
| if (old == -1) |
| return; |
| |
| /* TODO obey block */ |
| if (block) |
| fcntl(s, F_SETFL, old & ~O_NONBLOCK); |
| else |
| fcntl(s, F_SETFL, old | O_NONBLOCK); |
| #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER) |
| u_long iMode = block ? 0 : 1; |
| ioctlsocket(s, FIONBIO, &iMode); |
| #else |
| assert(0); |
| #endif |
| } |