platform_network.cc (5047B)
1 #include "common.h" 2 3 #include "platform.h" 4 #include "platform_network.h" 5 6 struct sockaddr_storage; 7 8 static NetAddress sockaddr_to_netaddress( const struct sockaddr_storage & ss ); 9 static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr ); 10 static void setsockoptone( PlatformSocket fd, int level, int opt ); 11 12 #if PLATFORM_WINDOWS 13 #include "win32_network.cc" 14 #elif PLATFORM_UNIX 15 #include "unix_network.cc" 16 #else 17 #error new platform 18 #endif 19 20 bool operator==( const NetAddress & lhs, const NetAddress & rhs ) { 21 if( lhs.type != rhs.type ) return false; 22 if( lhs.port != rhs.port ) return false; 23 if( lhs.type == NET_IPV4 ) return memcmp( &lhs.ipv4, &rhs.ipv4, sizeof( lhs.ipv4 ) ) == 0; 24 return memcmp( &lhs.ipv6, &rhs.ipv6, sizeof( lhs.ipv6 ) ) == 0; 25 } 26 27 bool operator!=( const NetAddress & lhs, const NetAddress & rhs ) { 28 return !( lhs == rhs ); 29 } 30 31 static socklen_t sockaddr_size( const struct sockaddr_storage & ss ) { 32 return ss.ss_family == AF_INET ? sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 ); 33 } 34 35 static NetAddress sockaddr_to_netaddress( const struct sockaddr_storage & ss ) { 36 NetAddress addr; 37 if( ss.ss_family == AF_INET ) { 38 const struct sockaddr_in & sa4 = ( const struct sockaddr_in & ) ss; 39 40 addr.type = NET_IPV4; 41 addr.port = ntohs( sa4.sin_port ); 42 memcpy( &addr.ipv4, &sa4.sin_addr.s_addr, sizeof( addr.ipv4 ) ); 43 } 44 else { 45 const struct sockaddr_in6 & sa6 = ( const struct sockaddr_in6 & ) ss; 46 47 addr.type = NET_IPV6; 48 addr.port = ntohs( sa6.sin6_port ); 49 memcpy( &addr.ipv6, &sa6.sin6_addr.s6_addr, sizeof( addr.ipv6 ) ); 50 } 51 return addr; 52 } 53 54 static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr ) { 55 struct sockaddr_storage ss; 56 if( addr.type == NET_IPV4 ) { 57 struct sockaddr_in & sa4 = ( struct sockaddr_in & ) ss; 58 59 ss.ss_family = AF_INET; 60 sa4.sin_port = htons( addr.port ); 61 memcpy( &sa4.sin_addr.s_addr, &addr.ipv4, sizeof( addr.ipv4 ) ); 62 } 63 else { 64 struct sockaddr_in6 & sa6 = ( struct sockaddr_in6 & ) ss; 65 66 ss.ss_family = AF_INET6; 67 sa6.sin6_port = htons( addr.port ); 68 memcpy( &sa6.sin6_addr.s6_addr, &addr.ipv6, sizeof( addr.ipv6 ) ); 69 } 70 return ss; 71 } 72 73 static void setsockoptone( PlatformSocket fd, int level, int opt ) { 74 int one = 1; 75 int ok = setsockopt( fd, level, opt, ( char * ) &one, sizeof( one ) ); 76 if( ok == -1 ) { 77 FATAL( "setsockopt" ); 78 } 79 } 80 81 #if PLATFORM_WINDOWS 82 // TODO: horrible 83 char last_error_str[ 1024 ]; 84 #endif 85 86 bool net_new_tcp( TCPSocket * sock, const NetAddress & addr, const char ** err ) { 87 struct sockaddr_storage ss = netaddress_to_sockaddr( addr ); 88 socklen_t ss_size = sockaddr_size( ss ); 89 90 sock->fd = socket( ss.ss_family, SOCK_STREAM, IPPROTO_TCP ); 91 if( sock->fd == INVALID_SOCKET ) 92 FATAL( "socket" ); 93 94 int ok = connect( sock->fd, ( const sockaddr * ) &ss, ss_size ); 95 if( ok == -1 ) { 96 if( err != NULL ) { 97 #if PLATFORM_WINDOWS 98 int error = WSAGetLastError(); 99 FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 100 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), last_error_str, sizeof( last_error_str ), NULL ); 101 102 *err = last_error_str; 103 #else 104 *err = strerror( errno ); 105 #endif 106 } 107 int ok_close = closesocket( sock->fd ); 108 if( ok_close == -1 ) 109 FATAL( "closesocket" ); 110 // TODO: check for actual coding errors too 111 return false; 112 } 113 114 setsockoptone( sock->fd, SOL_SOCKET, SO_KEEPALIVE ); 115 setsockoptone( sock->fd, IPPROTO_TCP, TCP_NODELAY ); 116 117 platform_init_sock( sock->fd ); 118 119 return true; 120 } 121 122 bool net_send( TCPSocket sock, const void * data, size_t len ) { 123 ssize_t sent = send( sock.fd, ( const char * ) data, len, NET_SEND_FLAGS ); 124 if( sent < 0 ) return false; 125 return checked_cast< size_t >( sent ) == len; 126 } 127 128 TCPRecvResult net_recv( TCPSocket sock, void * buf, size_t buf_size, size_t * bytes_read ) { 129 while( true ) { 130 ssize_t r = recv( sock.fd, ( char * ) buf, buf_size, 0 ); 131 // TODO: this is not right on windows 132 if( r == -1 ) { 133 if( errno == EINTR ) continue; 134 if( errno == ECONNRESET ) return TCP_ERROR; 135 FATAL( "recv" ); 136 } 137 138 *bytes_read = checked_cast< size_t >( r ); 139 return r == 0 ? TCP_CLOSED : TCP_OK; 140 } 141 } 142 143 void net_destroy( TCPSocket * sock ) { 144 int ok = closesocket( sock->fd ); 145 if( ok == -1 ) { 146 FATAL( "closesocket" ); 147 } 148 sock->fd = INVALID_SOCKET; 149 } 150 151 size_t dns( const char * host, NetAddress * out, size_t n ) { 152 struct addrinfo hints; 153 memset( &hints, 0, sizeof( struct addrinfo ) ); 154 hints.ai_family = AF_UNSPEC; 155 // TODO: figure out why ivp6 doesn't work on windows 156 hints.ai_family = AF_INET; 157 hints.ai_socktype = SOCK_STREAM; 158 hints.ai_protocol = IPPROTO_TCP; 159 160 struct addrinfo * addresses; 161 int ok = getaddrinfo( host, "http", &hints, &addresses ); 162 if( ok != 0 ) 163 return 0; 164 165 struct addrinfo * cursor = addresses; 166 size_t i = 0; 167 while( cursor != NULL && i < n ) { 168 out[ i ] = sockaddr_to_netaddress( *( struct sockaddr_storage * ) cursor->ai_addr ); 169 cursor = cursor->ai_next; 170 i++; 171 } 172 freeaddrinfo( addresses ); 173 174 return i; 175 } 176 177 bool dns_first( const char * host, NetAddress * address ) { 178 return dns( host, address, 1 ) == 1; 179 }