platform_network.cc (7776B)
1 #include "platform.h" 2 #include "array.h" 3 #include "ggformat.h" 4 #include "log.h" 5 6 #include "platform_network.h" 7 8 struct sockaddr_storage; 9 10 static NetAddress sockaddr_to_netaddress( const struct sockaddr_storage & ss ); 11 static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr ); 12 static void setsockoptone( OSSocket fd, int level, int opt ); 13 14 #if PLATFORM_WINDOWS 15 #include "win32_network.cc" 16 #elif PLATFORM_UNIX 17 #include "unix_network.cc" 18 #else 19 #error new platform 20 #endif 21 22 bool operator==( const NetAddress & lhs, const NetAddress & rhs ) { 23 if( lhs.type != rhs.type ) return false; 24 if( lhs.port != rhs.port ) return false; 25 if( lhs.type == NET_IPV4 ) return memcmp( &lhs.ipv4, &rhs.ipv4, sizeof( lhs.ipv4 ) ) == 0; 26 return memcmp( &lhs.ipv6, &rhs.ipv6, sizeof( lhs.ipv6 ) ) == 0; 27 } 28 29 bool operator!=( const NetAddress & lhs, const NetAddress & rhs ) { 30 return !( lhs == rhs ); 31 } 32 33 void format( FormatBuffer * fb, const NetAddress & addr, const FormatOpts & opts ) { 34 char buf[ INET6_ADDRSTRLEN ]; 35 const sockaddr_storage ss = netaddress_to_sockaddr( addr ); 36 37 void * src = ( void * ) &( ( sockaddr_in * ) &ss )->sin_addr; 38 if( ss.ss_family == AF_INET6 ) { 39 src = ( void * ) &( ( sockaddr_in6 * ) &ss )->sin6_addr; 40 } 41 inet_ntop( ss.ss_family, src, buf, sizeof( buf ) ); 42 43 format( fb, buf ); 44 format( fb, ":" ); 45 format( fb, addr.port, FormatOpts() ); 46 } 47 48 static socklen_t sockaddr_size( const struct sockaddr_storage & ss ) { 49 return ss.ss_family == AF_INET ? sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 ); 50 } 51 52 static NetAddress sockaddr_to_netaddress( const struct sockaddr_storage & ss ) { 53 NetAddress addr; 54 if( ss.ss_family == AF_INET ) { 55 const struct sockaddr_in & sa4 = ( const struct sockaddr_in & ) ss; 56 57 addr.type = NET_IPV4; 58 addr.port = ntohs( sa4.sin_port ); 59 memcpy( &addr.ipv4, &sa4.sin_addr.s_addr, sizeof( addr.ipv4 ) ); 60 } 61 else { 62 const struct sockaddr_in6 & sa6 = ( const struct sockaddr_in6 & ) ss; 63 64 addr.type = NET_IPV6; 65 addr.port = ntohs( sa6.sin6_port ); 66 memcpy( &addr.ipv6, &sa6.sin6_addr.s6_addr, sizeof( addr.ipv6 ) ); 67 } 68 return addr; 69 } 70 71 static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr ) { 72 struct sockaddr_storage ss; 73 if( addr.type == NET_IPV4 ) { 74 struct sockaddr_in & sa4 = ( struct sockaddr_in & ) ss; 75 76 ss.ss_family = AF_INET; 77 sa4.sin_port = htons( addr.port ); 78 memcpy( &sa4.sin_addr.s_addr, &addr.ipv4, sizeof( addr.ipv4 ) ); 79 } 80 else { 81 struct sockaddr_in6 & sa6 = ( struct sockaddr_in6 & ) ss; 82 83 ss.ss_family = AF_INET6; 84 sa6.sin6_port = htons( addr.port ); 85 memcpy( &sa6.sin6_addr.s6_addr, &addr.ipv6, sizeof( addr.ipv6 ) ); 86 } 87 return ss; 88 } 89 90 static void setsockoptone( OSSocket fd, int level, int opt ) { 91 int one = 1; 92 int ok = setsockopt( fd, level, opt, ( char * ) &one, sizeof( one ) ); 93 if( ok == -1 ) { 94 FATAL( "setsockopt" ); 95 } 96 } 97 98 UDPSocket net_new_udp( NonblockingBool nonblocking, u16 port ) { 99 UDPSocket sock; 100 101 sock.ipv4 = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); 102 if( sock.ipv4 == INVALID_SOCKET ) { 103 FATAL( "socket" ); 104 } 105 sock.ipv6 = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP ); 106 if( sock.ipv6 == INVALID_SOCKET ) { 107 FATAL( "socket" ); 108 } 109 110 if( nonblocking == NET_NONBLOCKING ) { 111 make_socket_nonblocking( sock.ipv4 ); 112 make_socket_nonblocking( sock.ipv6 ); 113 } 114 115 if( port != 0 ) { 116 setsockoptone( sock.ipv4, SOL_SOCKET, SO_REUSEADDR ); 117 setsockoptone( sock.ipv6, SOL_SOCKET, SO_REUSEADDR ); 118 setsockoptone( sock.ipv6, IPPROTO_IPV6, IPV6_V6ONLY ); 119 } 120 121 platform_init_sock( sock.ipv4 ); 122 platform_init_sock( sock.ipv6 ); 123 124 { 125 sockaddr_in my_addr4; 126 my_addr4.sin_family = AF_INET; 127 my_addr4.sin_port = htons( port ); 128 my_addr4.sin_addr.s_addr = htonl( INADDR_ANY ); 129 int ok = bind( sock.ipv4, ( struct sockaddr * ) &my_addr4, sizeof( my_addr4 ) ); 130 if( ok == SOCKET_ERROR ) { 131 FATAL( "bind" ); 132 } 133 } 134 135 { 136 sockaddr_in6 my_addr6; 137 my_addr6.sin6_family = AF_INET6; 138 my_addr6.sin6_port = htons( port ); 139 my_addr6.sin6_addr = in6addr_any; 140 int ok = bind( sock.ipv6, ( struct sockaddr * ) &my_addr6, sizeof( my_addr6 ) ); 141 if( ok == SOCKET_ERROR ) { 142 FATAL( "bind" ); 143 } 144 } 145 146 return sock; 147 } 148 149 void net_send( UDPSocket sock, const void * data, size_t len, const NetAddress & addr ) { 150 struct sockaddr_storage ss = netaddress_to_sockaddr( addr ); 151 socklen_t ss_size = sockaddr_size( ss ); 152 OSSocket fd = addr.type == NET_IPV4 ? sock.ipv4 : sock.ipv6; 153 ssize_t ok = sendto( fd, ( const char * ) data, checked_cast< int >( len ), NET_SEND_FLAGS, ( struct sockaddr * ) &ss, ss_size ); 154 if( ok == SOCKET_ERROR ) { 155 FATAL( "sendto" ); 156 } 157 } 158 159 void net_destroy( UDPSocket * sock ) { 160 int ok4 = closesocket( sock->ipv4 ); 161 if( ok4 == -1 ) { 162 FATAL( "closesocket" ); 163 } 164 int ok6 = closesocket( sock->ipv6 ); 165 if( ok6 == -1 ) { 166 FATAL( "closesocket" ); 167 } 168 sock->ipv4 = INVALID_SOCKET; 169 sock->ipv6 = INVALID_SOCKET; 170 } 171 172 bool net_new_tcp( TCPSocket * sock, const NetAddress & addr, NonblockingBool nonblocking ) { 173 struct sockaddr_storage ss = netaddress_to_sockaddr( addr ); 174 socklen_t ss_size = sockaddr_size( ss ); 175 176 sock->fd = socket( ss.ss_family, SOCK_STREAM, IPPROTO_TCP ); 177 if( sock->fd == INVALID_SOCKET ) { 178 FATAL( "socket" ); 179 } 180 181 int ok = connect( sock->fd, ( const sockaddr * ) &ss, ss_size ); 182 if( ok == -1 ) { 183 int ok_close = closesocket( sock->fd ); 184 if( ok_close == -1 ) { 185 FATAL( "closesocket" ); 186 } 187 // TODO: check for actual coding errors too 188 return false; 189 } 190 191 if( nonblocking == NET_NONBLOCKING ) { 192 make_socket_nonblocking( sock->fd ); 193 } 194 195 platform_init_sock( sock->fd ); 196 197 return true; 198 } 199 200 bool net_send( TCPSocket sock, const void * data, size_t len ) { 201 ssize_t sent = send( sock.fd, ( const char * ) data, len, NET_SEND_FLAGS ); 202 if( sent < 0 ) return false; 203 return checked_cast< size_t >( sent ) == len; 204 } 205 206 TCPRecvResult net_recv( TCPSocket sock, void * buf, size_t buf_size, size_t * bytes_read, u32 timeout_ms ) { 207 while( true ) { 208 if( timeout_ms > 0 ) { 209 fd_set fds; 210 FD_ZERO( &fds ); 211 FD_SET( sock.fd, &fds ); 212 213 struct timeval tv; 214 tv.tv_sec = timeout_ms / 1000; 215 tv.tv_usec = ( timeout_ms % 1000 ) * 1000; 216 217 int ok = select( sock.fd + 1, &fds, NULL, NULL, &tv ); 218 // TODO: update timeout 219 if( ok == 0 ) { 220 return TCP_TIMEOUT; 221 } 222 if( ok == -1 ) { 223 if( errno != EINTR ) continue; 224 FATAL( "select" ); 225 } 226 } 227 228 ssize_t r = recv( sock.fd, ( char * ) buf, buf_size, 0 ); 229 // TODO: this is not right on windows 230 if( r == -1 ) { 231 if( errno == EINTR ) continue; 232 if( errno == ECONNRESET ) return TCP_ERROR; 233 FATAL( "recv" ); 234 } 235 236 *bytes_read = checked_cast< size_t >( r ); 237 return r == 0 ? TCP_CLOSED : TCP_OK; 238 } 239 } 240 241 void net_destroy( TCPSocket * sock ) { 242 int ok = closesocket( sock->fd ); 243 if( ok == -1 ) { 244 FATAL( "closesocket" ); 245 } 246 sock->fd = INVALID_SOCKET; 247 } 248 249 array< NetAddress > dns( const char * host, array< NetAddress > out ) { 250 struct addrinfo hints; 251 memset( &hints, 0, sizeof( struct addrinfo ) ); 252 hints.ai_family = AF_UNSPEC; 253 // TODO: figure out why ivp6 doesn't work on windows 254 hints.ai_family = AF_INET; 255 hints.ai_socktype = SOCK_STREAM; 256 hints.ai_protocol = IPPROTO_TCP; 257 258 struct addrinfo * addresses; 259 int ok = getaddrinfo( host, "http", &hints, &addresses ); 260 if( ok != 0 ) { 261 return out.slice( 0, 0 ); 262 } 263 264 struct addrinfo * cursor = addresses; 265 size_t i = 0; 266 while( cursor != NULL && i < out.n ) { 267 out[ i ] = sockaddr_to_netaddress( *( struct sockaddr_storage * ) cursor->ai_addr ); 268 cursor = cursor->ai_next; 269 i++; 270 } 271 freeaddrinfo( addresses ); 272 273 return out.slice( 0, i ); 274 } 275 276 bool dns_first( const char * host, NetAddress * address ) { 277 StaticArray< NetAddress, 1 > storage; 278 array< NetAddress > addresses = dns( host, storage ); 279 if( addresses.n == 0 ) return false; 280 *address = addresses[ 0 ]; 281 return true; 282 }