/* ============= Sys_StringToNetAdr ============= */ bool Sys_StringToNetAdr( const char *s, netadr_t *a, bool doDNSResolve ) { struct sockaddr sadr; if ( !Net_StringToSockaddr( s, &sadr, doDNSResolve ) ) { return false; } Net_SockadrToNetadr( &sadr, a ); return true; }
/* * @brief Creates and binds a new network socket for the specified protocol. */ int32_t Net_Socket(net_addr_type_t type, const char *iface, in_port_t port) { int32_t sock, i = 1; switch (type) { case NA_BROADCAST: case NA_DATAGRAM: if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { Com_Error(ERR_DROP, "socket: %s\n", Net_GetErrorString()); } if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const void *) &i, sizeof(i)) == -1) { Com_Error(ERR_DROP, "setsockopt: %s\n", Net_GetErrorString()); } break; case NA_STREAM: if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { Com_Error(ERR_DROP, "socket: %s", Net_GetErrorString()); } if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const void *) &i, sizeof(i)) == -1) { Com_Error(ERR_DROP, "setsockopt: %s", Net_GetErrorString()); } break; default: Com_Error(ERR_DROP, "Invalid socket type: %d", type); } // make all sockets non-blocking if (ioctl(sock, FIONBIO, (void *) &i) == -1) { Com_Error(ERR_DROP, "ioctl: %s\n", Net_GetErrorString()); } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); if (iface) { Net_StringToSockaddr(iface, &addr); } else { addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; } addr.sin_port = htons(port); if (bind(sock, (void *) &addr, sizeof(addr)) == -1) { Com_Error(ERR_DROP, "bind: %s\n", Net_GetErrorString()); } return sock; }
/* * @brief localhost * idnewt * idnewt:28000 * 192.246.40.70 * 192.246.40.70:28000 */ _Bool Net_StringToNetaddr(const char *s, net_addr_t *a) { struct sockaddr_in saddr; if (!g_strcmp0(s, "localhost")) { memset(a, 0, sizeof(*a)); a->type = NA_LOCAL; return true; } if (!Net_StringToSockaddr(s, (struct sockaddr *) &saddr)) return false; Net_SockaddrToNetaddr(&saddr, a); return true; }
/* * @brief Parses the hostname and port into the specified net_addr_t. */ _Bool Net_StringToNetaddr(const char *s, net_addr_t *a) { struct sockaddr_in saddr; if (!Net_StringToSockaddr(s, &saddr)) return false; a->addr = saddr.sin_addr.s_addr; if (a->addr == net_lo) { a->port = 0; a->type = NA_LOOP; } else { a->port = saddr.sin_port; a->type = NA_DATAGRAM; } return true; }
/** * @brief Parses the hostname and port into the specified net_addr_t. */ _Bool Net_StringToNetaddr(const char *s, net_addr_t *a) { net_sockaddr saddr; if (!Net_StringToSockaddr(s, &saddr)) { return false; } a->addr = saddr.sin_addr.s_addr; if (g_strcmp0(s, "localhost") == 0) { a->port = 0; a->type = NA_LOOP; } else { a->port = saddr.sin_port; a->type = NA_DATAGRAM; } return true; }
/* * @brief */ static int32_t Net_Socket(const char *net_interface, uint16_t port) { int32_t sock; struct sockaddr_in addr; int32_t i = 1; if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { Com_Error(ERR_FATAL, "Call socket: %s\n", Net_ErrorString()); return 0; } // make it non-blocking if (ioctl(sock, FIONBIO, (char *) &i) == -1) { Com_Error(ERR_FATAL, "Call ioctl: %s\n", Net_ErrorString()); return 0; } // make it broadcast capable if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &i, sizeof(i)) == -1) { Com_Error(ERR_FATAL, "Call setsockopt: %s\n", Net_ErrorString()); return 0; } if (!net_interface || !net_interface[0] || !strcasecmp(net_interface, "localhost")) addr.sin_addr.s_addr = INADDR_ANY; else Net_StringToSockaddr(net_interface, (struct sockaddr *) &addr); addr.sin_port = htons(port); addr.sin_family = AF_INET; if (bind(sock, (void *) &addr, sizeof(addr)) == -1) { Com_Print("ERROR: UDP_OpenSocket: bind: %s\n", Net_ErrorString()); close(sock); return 0; } return sock; }
/** * @brief Establishes a TCP connection to the specified host. * * @param host The host to connect to. See Net_StringToNetaddr. */ int32_t Net_Connect(const char *host, struct timeval *timeout) { int32_t sock = Net_Socket(NA_STREAM, NULL, 0); struct sockaddr_in to; Net_StringToSockaddr(host, &to); if (connect(sock, (const struct sockaddr *) &to, sizeof(to)) == -1) { if (Net_GetError() == EINPROGRESS) { fd_set w_set; FD_ZERO(&w_set); FD_SET((uint32_t) sock, &w_set); if (select(sock + 1, NULL, &w_set, NULL, timeout) < 1) { Com_Error(ERROR_DROP, "%s\n", Net_GetErrorString()); } int32_t error = -1; socklen_t len = sizeof(error); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &error, &len) < 0) { Com_Error(ERROR_DROP, "%s\n", Net_GetErrorString()); } if (error) { Com_Error(ERROR_DROP, "%s\n", strerror(error)); } } else { Com_Error(ERROR_DROP, "%s\n", Net_GetErrorString()); } } return sock; }
/* ======================== NET_IPSocket ======================== */ int NET_IPSocket( const char* bind_ip, int port, netadr_t* bound_to ) { SOCKET newsocket; sockaddr_in address; if( port != PORT_ANY ) { if( bind_ip ) { idLib::Printf( "Opening IP socket: %s:%i\n", bind_ip, port ); } else { idLib::Printf( "Opening IP socket: localhost:%i\n", port ); } } if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) { idLib::Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() ); return 0; } // make it non-blocking #ifdef _WIN32 // which has no fcntl() unsigned long _true = 1; if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) { idLib::Printf( "WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString() ); closesocket( newsocket ); return 0; } #else int flags = fcntl( newsocket, F_GETFL, 0 ); if( flags < 0 ) { idLib::Printf( "WARNING: UDP_OpenSocket: fcntl F_GETFL: %s\n", NET_ErrorString() ); closesocket( newsocket ); return 0; } flags |= O_NONBLOCK; if( fcntl( newsocket, F_SETFL, flags ) < 0 ) { idLib::Printf( "WARNING: UDP_OpenSocket: fcntl F_SETFL with O_NONBLOCK: %s\n", NET_ErrorString() ); closesocket( newsocket ); return 0; } #endif // make it broadcast capable int i = 1; if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, ( char* )&i, sizeof( i ) ) == SOCKET_ERROR ) { idLib::Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() ); closesocket( newsocket ); return 0; } if( !bind_ip || !bind_ip[0] || !idStr::Icmp( bind_ip, "localhost" ) ) { address.sin_addr.s_addr = INADDR_ANY; } else { Net_StringToSockaddr( bind_ip, &address, true ); } if( port == PORT_ANY ) { address.sin_port = 0; } else { address.sin_port = htons( ( short )port ); } address.sin_family = AF_INET; if( bind( newsocket, ( const sockaddr* )&address, sizeof( address ) ) == SOCKET_ERROR ) { idLib::Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() ); closesocket( newsocket ); return 0; } // if the port was PORT_ANY, we need to query again to know the real port we got bound to // ( this used to be in idUDP::InitForPort ) if( bound_to ) { socklen_t len = sizeof( address ); if( getsockname( newsocket, ( struct sockaddr* )&address, &len ) == SOCKET_ERROR ) { common->Printf( "ERROR: IPSocket: getsockname: %s\n", NET_ErrorString() ); closesocket( newsocket ); return 0; } Net_SockadrToNetadr( &address, bound_to ); } return newsocket; }
/* ==================== NET_IPSocket ==================== */ int NET_IPSocket( const char *net_interface, int port, netadr_t *bound_to ) { SOCKET newsocket; struct sockaddr_in address; unsigned long _true = 1; int i = 1; int err; if( net_interface ) { common->DPrintf( "Opening IP socket: %s:%i\n", net_interface, port ); } else { common->DPrintf( "Opening IP socket: localhost:%i\n", port ); } if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) { err = WSAGetLastError(); if( err != WSAEAFNOSUPPORT ) { common->Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() ); } return 0; } // make it non-blocking if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) { common->Printf( "WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString() ); return 0; } // make it broadcast capable if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) { common->Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() ); return 0; } if( !net_interface || !net_interface[0] || !idStr::Icmp( net_interface, "localhost" ) ) { address.sin_addr.s_addr = INADDR_ANY; } else { Net_StringToSockaddr( net_interface, (struct sockaddr *)&address, true ); } if( port == PORT_ANY ) { address.sin_port = 0; } else { address.sin_port = htons( (short)port ); } address.sin_family = AF_INET; if( bind( newsocket, (const struct sockaddr *)&address, sizeof(address) ) == SOCKET_ERROR ) { common->Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() ); closesocket( newsocket ); return 0; } // if the port was PORT_ANY, we need to query again to know the real port we got bound to // ( this used to be in idPort::InitForPort ) if ( bound_to ) { int len = sizeof( address ); getsockname( newsocket, (sockaddr *)&address, &len ); Net_SockadrToNetadr( (sockaddr *)&address, bound_to ); } return newsocket; }