commit 33bd1dce42775db46fb1eae240c4ea64f32c0224 parent 0f494ed3df7c8769b52a8b3754ce41e3e8a38626 Author: Michael Savage <mikejsavage@gmail.com> Date: Sat Sep 2 18:48:09 +0300 Sockets overhaul for Windows Diffstat:
http.cc | | | 72 | ++++++++---------------------------------------------------------------- |
platform_network.cc | | | 286 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
platform_network.h | | | 255 | +++++++++++++------------------------------------------------------------------ |
unix_network.cc | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
unix_network.h | | | 58 | ---------------------------------------------------------- |
win32_network.cc | | | 57 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
win32_network.h | | | 47 | ----------------------------------------------- |
diff --git a/http.cc b/http.cc @@ -11,45 +11,12 @@ #include "platform_network.h" #include "http.h" -array< NetAddress > dns( const char * host, array< NetAddress > out ) { - struct addrinfo hints; - memset( &hints, 0, sizeof( struct addrinfo ) ); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - struct addrinfo * addresses; - int ok = getaddrinfo( host, "http", &hints, &addresses ); - if( ok != 0 ) { - return out.slice( 0, 0 ); - } - - struct addrinfo * cursor = addresses; - size_t i = 0; - while( cursor != NULL && i < out.n ) { - out[ i ] = sockaddr_to_netaddress( *( struct sockaddr_storage * ) cursor->ai_addr ); - cursor = cursor->ai_next; - i++; - } - freeaddrinfo( addresses ); - - return out.slice( 0, i ); -} - -bool dns_first( const char * host, NetAddress * address ) { - StaticArray< NetAddress, 1 > storage; - array< NetAddress > addresses = dns( host, storage ); - if( addresses.n == 0 ) return false; - *address = addresses[ 0 ]; - return true; -} - GetResult http_get( const NetAddress & addr, const char * host, const char * path, std::string * body, HttpProgressCallback progress_cb, void * cb_data ) { TCPSocket sock; - if( !sock_new_tcp( &sock, addr, NET_BLOCKING ) ) { + if( !net_new_tcp( &sock, addr, NET_BLOCKING ) ) { return GET_ERROR_CANT_CONNECT; } - SCOPE_EXIT( sock_destroy( &sock ) ); + SCOPE_EXIT( net_destroy( &sock ) ); // TODO: should just be a dynamic string char request[ 1024 ]; @@ -62,40 +29,17 @@ GetResult http_get( const NetAddress & addr, const char * host, const char * pat "\r\n\r\n", path, host ); ASSERT( request_len <= sizeof( request ) - 1 ); - if( !sock_send_tcp( sock, request, request_len ) ) { + if( !net_send( sock, request, request_len ) ) { return GET_ERROR_DISCONNECTED; } std::string response; - char buf[ BUFSIZ ]; while( true ) { - { - fd_set select_fds; - FD_ZERO( &select_fds ); - FD_SET( checked_cast< unsigned int >( sock.fd ), &select_fds ); - - struct timeval timeout; - timeout.tv_sec = 10; - timeout.tv_usec = 0; - - int ok = select( sock.fd + 1, &select_fds, NULL, NULL, &timeout ); - if( ok == 0 ) { - return GET_ERROR_TIMEOUT; - } - if( ok == -1 ) { - if( errno != EINTR ) continue; - return GET_ERROR_DISCONNECTED; - } - } - - ssize_t bytes_read = sock_recv_tcp( sock, buf, sizeof( buf ) ); - if( bytes_read == -1 ) { - if( errno == EINTR ) continue; - return GET_ERROR_DISCONNECTED; - } - if( bytes_read == 0 ) { - break; - } + char buf[ BUFSIZ ]; + size_t bytes_read; + TCPRecvResult ok = net_recv( sock, buf, sizeof( buf ), &bytes_read, 10000 ); + if( ok == TCP_TIMEOUT ) return GET_ERROR_TIMEOUT; + if( ok == TCP_CLOSED ) break; response.append( buf, checked_cast< size_t >( bytes_read ) ); diff --git a/platform_network.cc b/platform_network.cc @@ -0,0 +1,286 @@ +#include "platform.h" +#include "array.h" +#include "ggformat.h" +#include "log.h" + +#include "platform_network.h" + +struct sockaddr_storage; + +static NetAddress sockaddr_to_netaddress( const struct sockaddr_storage & ss ); +static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr ); + +#if PLATFORM_WINDOWS +#include "win32_network.cc" +#elif PLATFORM_UNIX +#include "unix_network.cc" +#else +#error new platform +#endif + +bool operator==( const NetAddress & lhs, const NetAddress & rhs ) { + if( lhs.type != rhs.type ) return false; + if( lhs.port != rhs.port ) return false; + if( lhs.type == NET_IPV4 ) return memcmp( &lhs.ipv4, &rhs.ipv4, sizeof( lhs.ipv4 ) ) == 0; + return memcmp( &lhs.ipv6, &rhs.ipv6, sizeof( lhs.ipv6 ) ) == 0; +} + +bool operator!=( const NetAddress & lhs, const NetAddress & rhs ) { + return !( lhs == rhs ); +} + +void format( FormatBuffer * fb, const NetAddress & addr, const FormatOpts & opts ) { + char buf[ INET6_ADDRSTRLEN ]; + const sockaddr_storage ss = netaddress_to_sockaddr( addr ); + + void * src = ( void * ) &( ( sockaddr_in * ) &ss )->sin_addr; + if( ss.ss_family == AF_INET6 ) { + src = ( void * ) &( ( sockaddr_in6 * ) &ss )->sin6_addr; + } + inet_ntop( ss.ss_family, src, buf, sizeof( buf ) ); + + format( fb, buf ); + format( fb, ":" ); + format( fb, addr.port, FormatOpts() ); +} + +static socklen_t sockaddr_size( const struct sockaddr_storage & ss ) { + return ss.ss_family == AF_INET ? sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 ); +} + +static NetAddress sockaddr_to_netaddress( const struct sockaddr_storage & ss ) { + NetAddress addr; + if( ss.ss_family == AF_INET ) { + const struct sockaddr_in & sa4 = ( const struct sockaddr_in & ) ss; + + addr.type = NET_IPV4; + addr.port = ntohs( sa4.sin_port ); + memcpy( &addr.ipv4, &sa4.sin_addr.s_addr, sizeof( addr.ipv4 ) ); + } + else { + const struct sockaddr_in6 & sa6 = ( const struct sockaddr_in6 & ) ss; + + addr.type = NET_IPV6; + addr.port = ntohs( sa6.sin6_port ); + memcpy( &addr.ipv6, &sa6.sin6_addr.s6_addr, sizeof( addr.ipv6 ) ); + } + return addr; +} + +static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr ) { + struct sockaddr_storage ss; + if( addr.type == NET_IPV4 ) { + struct sockaddr_in & sa4 = ( struct sockaddr_in & ) ss; + + ss.ss_family = AF_INET; + sa4.sin_port = htons( addr.port ); + memcpy( &sa4.sin_addr.s_addr, &addr.ipv4, sizeof( addr.ipv4 ) ); + } + else { + struct sockaddr_in6 & sa6 = ( struct sockaddr_in6 & ) ss; + + ss.ss_family = AF_INET6; + sa6.sin6_port = htons( addr.port ); + memcpy( &sa6.sin6_addr.s6_addr, &addr.ipv6, sizeof( addr.ipv6 ) ); + } + return ss; +} + +UDPSocket net_new_udp( NonblockingBool nonblocking, u16 port ) { + UDPSocket sock; + + sock.ipv4 = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if( sock.ipv4 == INVALID_SOCKET ) { + FATAL( "socket" ); + } + sock.ipv6 = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP ); + if( sock.ipv6 == INVALID_SOCKET ) { + FATAL( "socket" ); + } + + if( nonblocking == NET_NONBLOCKING ) { + make_socket_nonblocking( sock.ipv4 ); + make_socket_nonblocking( sock.ipv6 ); + } + + if( port != 0 ) { + int one = 1; + { + int ok = setsockopt( sock.ipv4, SOL_SOCKET, SO_REUSEADDR, ( char * ) &one, sizeof( one ) ); + if( ok == -1 ) { + FATAL( "setsockopt" ); + } + } + + { + int ok = setsockopt( sock.ipv6, SOL_SOCKET, SO_REUSEADDR, ( char * ) &one, sizeof( one ) ); + if( ok == -1 ) { + FATAL( "setsockopt" ); + } + } + + { + int ok = setsockopt( sock.ipv6, IPPROTO_IPV6, IPV6_V6ONLY, ( char * ) &one, sizeof( one ) ); + if( ok == -1 ) { + FATAL( "setsockopt" ); + } + } + } + + { + sockaddr_in my_addr4; + my_addr4.sin_family = AF_INET; + my_addr4.sin_port = htons( port ); + my_addr4.sin_addr.s_addr = htonl( INADDR_ANY ); + int ok = bind( sock.ipv4, ( struct sockaddr * ) &my_addr4, sizeof( my_addr4 ) ); + if( ok == SOCKET_ERROR ) { + FATAL( "bind" ); + } + } + + { + sockaddr_in6 my_addr6; + my_addr6.sin6_family = AF_INET6; + my_addr6.sin6_port = htons( port ); + my_addr6.sin6_addr = in6addr_any; + int ok = bind( sock.ipv6, ( struct sockaddr * ) &my_addr6, sizeof( my_addr6 ) ); + if( ok == SOCKET_ERROR ) { + FATAL( "bind" ); + } + } + + return sock; +} + +void net_send( UDPSocket sock, const void * data, size_t len, const NetAddress & addr ) { + struct sockaddr_storage ss = netaddress_to_sockaddr( addr ); + socklen_t ss_size = sockaddr_size( ss ); + OSSocket fd = addr.type == NET_IPV4 ? sock.ipv4 : sock.ipv6; + ssize_t ok = sendto( fd, ( const char * ) data, checked_cast< int >( len ), 0, ( struct sockaddr * ) &ss, ss_size ); + if( ok == SOCKET_ERROR ) { + int error = WSAGetLastError(); + FATAL( "sendto" ); + } +} + +void net_destroy( UDPSocket * sock ) { + int ok4 = closesocket( sock->ipv4 ); + if( ok4 == -1 ) { + FATAL( "closesocket" ); + } + int ok6 = closesocket( sock->ipv6 ); + if( ok6 == -1 ) { + FATAL( "closesocket" ); + } + sock->ipv4 = INVALID_SOCKET; + sock->ipv6 = INVALID_SOCKET; +} + +bool net_new_tcp( TCPSocket * sock, const NetAddress & addr, NonblockingBool nonblocking ) { + struct sockaddr_storage ss = netaddress_to_sockaddr( addr ); + socklen_t ss_size = sockaddr_size( ss ); + + sock->fd = socket( ss.ss_family, SOCK_STREAM, IPPROTO_TCP ); + if( sock->fd == INVALID_SOCKET ) { + FATAL( "socket" ); + } + + int ok = connect( sock->fd, ( const sockaddr * ) &ss, ss_size ); + if( ok == -1 ) { + int ok_close = closesocket( sock->fd ); + if( ok_close == -1 ) { + FATAL( "closesocket" ); + } + // TODO: check for actual coding errors too + return false; + } + + if( nonblocking == NET_NONBLOCKING ) { + make_socket_nonblocking( sock->fd ); + } + + return true; +} + +bool net_send( TCPSocket sock, const void * data, size_t len ) { + ssize_t sent = send( sock.fd, ( const char * ) data, len, 0 ); + if( sent < 0 ) return false; + return checked_cast< size_t >( sent ) == len; +} + +TCPRecvResult net_recv( TCPSocket sock, void * buf, size_t buf_size, size_t * bytes_read, u32 timeout_ms ) { + while( true ) { + if( timeout_ms > 0 ) { + fd_set fds; + FD_ZERO( &fds ); + FD_SET( sock.fd, &fds ); + + struct timeval tv; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = ( timeout_ms % 1000 ) * 1000; + + int ok = select( sock.fd + 1, &fds, NULL, NULL, &tv ); + // TODO: update timeout + if( ok == 0 ) { + return TCP_TIMEOUT; + } + if( ok == -1 ) { + if( errno != EINTR ) continue; + FATAL( "select" ); + } + } + + ssize_t r = recv( sock.fd, ( char * ) buf, buf_size, 0 ); + // TODO: this is not right on windows + if( r == -1 ) { + if( errno == EINTR ) continue; + FATAL( "recv" ); + } + + *bytes_read = checked_cast< size_t >( r ); + return r == 0 ? TCP_CLOSED : TCP_OK; + } +} + +void net_destroy( TCPSocket * sock ) { + int ok = closesocket( sock->fd ); + if( ok == -1 ) { + FATAL( "closesocket" ); + } + sock->fd = INVALID_SOCKET; +} + +array< NetAddress > dns( const char * host, array< NetAddress > out ) { + struct addrinfo hints; + memset( &hints, 0, sizeof( struct addrinfo ) ); + hints.ai_family = AF_UNSPEC; + // TODO: figure out why ivp6 doesn't work on windows + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + struct addrinfo * addresses; + int ok = getaddrinfo( host, "http", &hints, &addresses ); + if( ok != 0 ) { + return out.slice( 0, 0 ); + } + + struct addrinfo * cursor = addresses; + size_t i = 0; + while( cursor != NULL && i < out.n ) { + out[ i ] = sockaddr_to_netaddress( *( struct sockaddr_storage * ) cursor->ai_addr ); + cursor = cursor->ai_next; + i++; + } + freeaddrinfo( addresses ); + + return out.slice( 0, i ); +} + +bool dns_first( const char * host, NetAddress * address ) { + StaticArray< NetAddress, 1 > storage; + array< NetAddress > addresses = dns( host, storage ); + if( addresses.n == 0 ) return false; + *address = addresses[ 0 ]; + return true; +} diff --git a/platform_network.h b/platform_network.h @@ -1,240 +1,65 @@ #pragma once -#include <arpa/inet.h> - #include "platform.h" +#include "array.h" #include "ggformat.h" -#include "log.h" + +#if PLATFORM_WINDOWS +typedef s64 OSSocket; +#elif PLATFORM_UNIX +typedef int OSSocket; +#else +#error new platform +#endif enum TransportProtocol { NET_UDP, NET_TCP }; enum IPvX { NET_IPV4, NET_IPV6 }; enum NonblockingBool { NET_BLOCKING, NET_NONBLOCKING }; -struct IPv4 { u8 bytes[ sizeof( struct in_addr ) ]; }; -struct IPv6 { u8 bytes[ sizeof( struct in6_addr ) ]; }; - -struct NetAddress { - IPvX type; - union { - IPv4 ipv4; - IPv6 ipv6; - }; - u16 port; +enum TCPRecvResult { + TCP_OK, + TCP_TIMEOUT, + TCP_CLOSED, }; -inline bool operator==( const NetAddress & lhs, const NetAddress & rhs ) { - if( lhs.type != rhs.type ) return false; - if( lhs.port != rhs.port ) return false; - if( lhs.type == NET_IPV4 ) return memcmp( &lhs.ipv4, &rhs.ipv4, sizeof( lhs.ipv4 ) ) == 0; - return memcmp( &lhs.ipv6, &rhs.ipv6, sizeof( lhs.ipv6 ) ) == 0; -} - -inline bool operator!=( const NetAddress & lhs, const NetAddress & rhs ) { - return !( lhs == rhs ); -} - struct UDPSocket { - int ipv4, ipv6; + OSSocket ipv4, ipv6; }; struct TCPSocket { - int fd; + OSSocket fd; }; -inline NetAddress sockaddr_to_netaddress( const sockaddr_storage & ss ) { - NetAddress addr; - if( ss.ss_family == AF_INET ) { - const struct sockaddr_in & sa4 = ( const struct sockaddr_in & ) ss; - - addr.type = NET_IPV4; - addr.port = ntohs( sa4.sin_port ); - memcpy( &addr.ipv4, &sa4.sin_addr.s_addr, sizeof( addr.ipv4 ) ); - } - else { - const struct sockaddr_in6 & sa6 = ( const struct sockaddr_in6 & ) ss; - - addr.type = NET_IPV6; - addr.port = ntohs( sa6.sin6_port ); - memcpy( &addr.ipv6, &sa6.sin6_addr.s6_addr, sizeof( addr.ipv6 ) ); - } - return addr; -} - -inline struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr, socklen_t * size = NULL ) { - if( size != NULL ) { - *size = addr.type == NET_IPV4 ? sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 ); - } +struct IPv4 { u8 bytes[ 4 ]; }; +struct IPv6 { u8 bytes[ 16 ]; }; - struct sockaddr_storage ss; - if( addr.type == NET_IPV4 ) { - struct sockaddr_in & sa4 = ( struct sockaddr_in & ) ss; - - ss.ss_family = AF_INET; - sa4.sin_port = htons( addr.port ); - memcpy( &sa4.sin_addr.s_addr, &addr.ipv4, sizeof( addr.ipv4 ) ); - } - else { - struct sockaddr_in6 & sa6 = ( struct sockaddr_in6 & ) ss; - - ss.ss_family = AF_INET6; - sa6.sin6_port = htons( addr.port ); - memcpy( &sa6.sin6_addr.s6_addr, &addr.ipv6, sizeof( addr.ipv6 ) ); - } - return ss; -} - -#if PLATFORM_WINDOWS -#include "win32_network.h" -#elif PLATFORM_UNIX -#include "unix_network.h" -#else -#error new platform -#endif - -inline UDPSocket net_new_udp( NonblockingBool nonblocking, u16 port = 0 ) { - UDPSocket sock; - - sock.ipv4 = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); - if( sock.ipv4 == INVALID_SOCKET ) { - FATAL( "socket" ); - } - sock.ipv6 = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP ); - if( sock.ipv6 == INVALID_SOCKET ) { - FATAL( "socket" ); - } - - if( nonblocking == NET_NONBLOCKING ) { - sock_fd_nonblocking( sock.ipv4 ); - sock_fd_nonblocking( sock.ipv6 ); - } - - if( port != 0 ) { - int one = 1; - { - int ok = setsockopt( sock.ipv4, SOL_SOCKET, SO_REUSEADDR, &one, sizeof( one ) ); - if( ok == -1 ) { - FATAL( "setsockopt" ); - } - } - - { - int ok = setsockopt( sock.ipv6, SOL_SOCKET, SO_REUSEADDR, &one, sizeof( one ) ); - if( ok == -1 ) { - FATAL( "setsockopt" ); - } - } - - { - int ok = setsockopt( sock.ipv6, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof( one ) ); - if( ok == -1 ) { - FATAL( "setsockopt" ); - } - } - - { - sockaddr_in my_addr4; - my_addr4.sin_family = AF_INET; - my_addr4.sin_port = htons( port ); - my_addr4.sin_addr.s_addr = htonl( INADDR_ANY ); - int ok = bind( sock.ipv4, ( sockaddr * ) &my_addr4, sizeof( my_addr4 ) ); - if( ok == SOCKET_ERROR ) { - FATAL( "bind" ); - } - } - - { - sockaddr_in6 my_addr6; - my_addr6.sin6_family = AF_INET6; - my_addr6.sin6_port = htons( port ); - my_addr6.sin6_addr = in6addr_any; - int ok = bind( sock.ipv6, ( sockaddr * ) &my_addr6, sizeof( my_addr6 ) ); - if( ok == SOCKET_ERROR ) { - FATAL( "bind" ); - } - } - } - - return sock; -} - -inline bool sock_new_tcp( TCPSocket * sock, const NetAddress & addr, NonblockingBool nonblocking ) { - socklen_t sa_size; - struct sockaddr_storage sa = netaddress_to_sockaddr( addr, &sa_size ); - - sock->fd = socket( sa.ss_family, SOCK_STREAM, IPPROTO_TCP ); - if( sock->fd == INVALID_SOCKET ) { - FATAL( "socket" ); - } - - int ok = connect( sock->fd, ( const sockaddr * ) &sa, sa_size ); - if( ok == -1 ) { - int ok_close = closesocket( sock->fd ); - if( ok_close == -1 ) { - FATAL( "closesocket" ); - } - // TODO: check for actual coding errors too - return false; - } - - if( nonblocking == NET_NONBLOCKING ) { - sock_fd_nonblocking( sock->fd ); - } - - return true; -} - -inline void net_send( UDPSocket sock, const void * data, size_t len, const NetAddress & addr ) { - socklen_t sa_size; - struct sockaddr_storage sa = netaddress_to_sockaddr( addr, &sa_size ); - int fd = addr.type == NET_IPV4 ? sock.ipv4 : sock.ipv6; - ssize_t ok = sendto( fd, data, checked_cast< int >( len ), 0, ( struct sockaddr * ) &sa, sa_size ); - if( ok == SOCKET_ERROR ) { - FATAL( "sendto" ); - } -} +struct NetAddress { + IPvX type; + union { + IPv4 ipv4; + IPv6 ipv6; + }; + u16 port; +}; -inline bool sock_send_tcp( TCPSocket sock, const void * data, size_t len ) { - ssize_t sent = send( sock.fd, data, len, 0 ); - if( sent < 0 ) return false; - return checked_cast< size_t >( sent ) == len; -} +bool operator==( const NetAddress & lhs, const NetAddress & rhs ); +bool operator!=( const NetAddress & lhs, const NetAddress & rhs ); -inline ssize_t sock_recv_tcp( TCPSocket sock, void * buf, size_t buf_size ) { - return recv( sock.fd, buf, buf_size, 0 ); -} +void format( FormatBuffer * fb, const NetAddress & addr, const FormatOpts & opts ); -inline void net_destroy( UDPSocket * sock ) { - int ok4 = closesocket( sock->ipv4 ); - if( ok4 == -1 ) { - FATAL( "closesocket" ); - } - int ok6 = closesocket( sock->ipv6 ); - if( ok6 == -1 ) { - FATAL( "closesocket" ); - } - sock->ipv4 = INVALID_SOCKET; - sock->ipv6 = INVALID_SOCKET; -} +void net_init(); +void net_term(); -inline void sock_destroy( TCPSocket * sock ) { - int ok = closesocket( sock->fd ); - if( ok == -1 ) { - FATAL( "closesocket" ); - } - sock->fd = INVALID_SOCKET; -} +UDPSocket net_new_udp( NonblockingBool nonblocking, u16 port = 0 ); +void net_send( UDPSocket sock, const void * data, size_t len, const NetAddress & addr ); +bool net_tryrecv( UDPSocket sock, void * buf, size_t len, NetAddress * addr, size_t * bytes_received ); +void net_destroy( UDPSocket * sock ); -inline void format( FormatBuffer * fb, const NetAddress & addr, const FormatOpts & opts ) { - char buf[ INET6_ADDRSTRLEN ]; - const sockaddr_storage sa = netaddress_to_sockaddr( addr ); +bool net_new_tcp( TCPSocket * sock, const NetAddress & addr, NonblockingBool nonblocking ); +bool net_send( TCPSocket sock, const void * data, size_t len ); +TCPRecvResult net_recv( TCPSocket sock, void * buf, size_t buf_size, size_t * bytes_read, u32 timeout_ms = 0 ); +void net_destroy( TCPSocket * sock ); - void * src = ( void * ) &( ( sockaddr_in * ) &sa )->sin_addr; - if( sa.ss_family == AF_INET6 ) { - src = ( void * ) &( ( sockaddr_in6 * ) &sa )->sin6_addr; - } - inet_ntop( sa.ss_family, src, buf, sizeof( buf ) ); - format( fb, buf ); - format( fb, ":" ); - format( fb, addr.port, FormatOpts() ); -} +array< NetAddress > dns( const char * host, array< NetAddress > out ); +bool dns_first( const char * host, NetAddress * address ); diff --git a/unix_network.cc b/unix_network.cc @@ -0,0 +1,51 @@ +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <unistd.h> + +#define INVALID_SOCKET ( -1 ) +#define SOCKET_ERROR ( -1 ) + +#define closesocket close + +void net_init() { } +void net_term() { } + +static void make_socket_nonblocking( int fd ) { + int flags = fcntl( fd, F_GETFL, 0 ); + if( flags == -1 ) FATAL( "fcntl F_GETFL" ); + int ok = fcntl( fd, F_SETFL, flags | O_NONBLOCK ); + if( ok == -1 ) FATAL( "fcntl F_SETFL" ); +} + +bool net_tryrecv( UDPSocket sock, void * buf, size_t len, NetAddress * addr, size_t * bytes_received ) { + struct sockaddr_storage sa; + + socklen_t sa_size = sizeof( struct sockaddr_in ); + ssize_t received4 = recvfrom( sock.ipv4, buf, len, 0, ( struct sockaddr * ) &sa, &sa_size ); + if( received4 != -1 ) { + *addr = sockaddr_to_netaddress( sa ); + *bytes_received = size_t( received4 ); + return true; + } + if( received4 == -1 && errno != EAGAIN ) { + FATAL( "recvfrom" ); + } + + sa_size = sizeof( struct sockaddr_in6 ); + ssize_t received6 = recvfrom( sock.ipv6, buf, len, 0, ( struct sockaddr * ) &sa, &sa_size ); + if( received6 != -1 ) { + *addr = sockaddr_to_netaddress( sa ); + *bytes_received = size_t( received6 ); + return true; + } + if( received6 == -1 && errno != EAGAIN ) { + FATAL( "recvfrom" ); + } + + return false; +} diff --git a/unix_network.h b/unix_network.h @@ -1,58 +0,0 @@ -#pragma once - -#include <arpa/inet.h> -#include <sys/types.h> -#include <sys/select.h> -#include <sys/socket.h> -#include <errno.h> -#include <fcntl.h> -#include <netdb.h> -#include <unistd.h> - -struct Socket { - int fd; - TransportProtocol transport; - IPvX ipvx; -}; - -#define INVALID_SOCKET ( -1 ) -#define SOCKET_ERROR ( -1 ) - -#define closesocket close - -inline void net_init() { } -inline void net_term() { } - -inline void sock_fd_nonblocking( int fd ) { - int flags = fcntl( fd, F_GETFL, 0 ); - if( flags == -1 ) FATAL( "fcntl F_GETFL" ); - int ok = fcntl( fd, F_SETFL, flags | O_NONBLOCK ); - if( ok == -1 ) FATAL( "fcntl F_SETFL" ); -} - -inline bool net_tryrecv( UDPSocket sock, void * buf, size_t len, NetAddress * addr, size_t * bytes_received ) { - struct sockaddr_storage sa; - socklen_t sa_size = sizeof( struct sockaddr_in ); - ssize_t received4 = recvfrom( sock.ipv4, buf, len, 0, ( struct sockaddr * ) &sa, &sa_size ); - if( received4 != -1 ) { - *addr = sockaddr_to_netaddress( sa ); - *bytes_received = size_t( received4 ); - return true; - } - if( received4 == -1 && errno != EAGAIN ) { - FATAL( "recvfrom" ); - } - - sa_size = sizeof( struct sockaddr_in6 ); - ssize_t received6 = recvfrom( sock.ipv6, buf, len, 0, ( struct sockaddr * ) &sa, &sa_size ); - if( received6 != -1 ) { - *addr = sockaddr_to_netaddress( sa ); - *bytes_received = size_t( received6 ); - return true; - } - if( received6 == -1 && errno != EAGAIN ) { - FATAL( "recvfrom" ); - } - - return false; -} diff --git a/win32_network.cc b/win32_network.cc @@ -0,0 +1,57 @@ +#include <winsock2.h> +#include <ws2tcpip.h> + +void net_init() { + WSADATA wsa_data; + if( WSAStartup( MAKEWORD( 2, 2 ), &wsa_data ) == SOCKET_ERROR ) { + FATAL( "WSAStartup" ); + } +} + +void net_term() { + if( WSACleanup() == SOCKET_ERROR ) { + FATAL( "WSACleanup" ); + } +} + +static void make_socket_nonblocking( SOCKET fd ) { + u_long one = 1; + int ok = ioctlsocket( fd, FIONBIO, &one ); + if( ok == SOCKET_ERROR ) { + FATAL( "ioctlsocket" ); + } +} + +bool net_tryrecv( UDPSocket sock, void * buf, size_t len, NetAddress * addr, size_t * bytes_received ) { + struct sockaddr_storage sa; + + socklen_t sa_size = sizeof( struct sockaddr_in ); + ssize_t received4 = recvfrom( sock.ipv4, ( char * ) buf, len, 0, ( struct sockaddr * ) &sa, &sa_size ); + if( received4 != SOCKET_ERROR ) { + *addr = sockaddr_to_netaddress( sa ); + *bytes_received = size_t( received4 ); + return true; + } + else { + int error = WSAGetLastError(); + if( error != WSAEWOULDBLOCK && error != WSAECONNRESET ) { + FATAL( "recvfrom" ); + } + } + + sa_size = sizeof( struct sockaddr_in6 ); + ssize_t received6 = recvfrom( sock.ipv6, ( char * ) buf, len, 0, ( struct sockaddr * ) &sa, &sa_size ); + if( received6 != SOCKET_ERROR ) { + *addr = sockaddr_to_netaddress( sa ); + *bytes_received = size_t( received6 ); + return true; + } + else { + int error = WSAGetLastError(); + if( error != WSAEWOULDBLOCK && error != WSAECONNRESET ) { + FATAL( "recvfrom" ); + } + } + + return false; +} diff --git a/win32_network.h b/win32_network.h @@ -1,47 +0,0 @@ -#pragma once - -#include <winsock2.h> -#include <ws2tcpip.h> - -struct Socket { - SOCKET fd; - TransportProtocol transport; - IPvX ipvx; -}; - -inline void net_init() { - WSADATA wsa_data; - if( WSAStartup( MAKEWORD( 2, 2 ), &wsa_data ) == SOCKET_ERROR ) { - FATAL( "WSAStartup" ); - } -} - -inline void net_term() { - if( WSACleanup() == SOCKET_ERROR ) { - FATAL( "WSACleanup" ); - } -} - -inline void sock_fd_nonblocking( SOCKET fd ) { - u_long one = 1; - int ok = ioctlsocket( fd, FIONBIO, &one ); - if( ok == SOCKET_ERROR ) { - FATAL( "ioctlsocket" ); - } -} - -inline bool sock_tryrecv_udp( Socket sock, char * buf, size_t len, sockaddr_storage * addr, socklen_t * addr_len, size_t * bytes_received ) { - ASSERT( sock.transport == NET_UDP ); - - int received = recvfrom( sock.fd, buf, checked_cast< int >( len ), 0, ( sockaddr * ) addr, addr_len ); - if( received == SOCKET_ERROR ) { - int error = WSAGetLastError(); - if( error == WSAEWOULDBLOCK || error == WSAECONNRESET ) { - return false; - } - FATAL( "recvfrom" ); - } - - *bytes_received = size_t( received ); - return true; -}