static struct net_connection* start_listening_socket(const char* bind_addr, uint16_t port, int backlog, struct hub_info* hub) { struct net_connection* server; struct sockaddr_storage addr; socklen_t sockaddr_size; int sd, ret; if (ip_convert_address(bind_addr, port, (struct sockaddr*) &addr, &sockaddr_size) == -1) { return 0; } sd = net_socket_create(addr.ss_family, SOCK_STREAM, IPPROTO_TCP); if (sd == -1) { return 0; } if ((net_set_reuseaddress(sd, 1) == -1) || (net_set_nonblocking(sd, 1) == -1)) { net_close(sd); return 0; } ret = net_bind(sd, (struct sockaddr*) &addr, sockaddr_size); if (ret == -1) { LOG_ERROR("hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error())); net_close(sd); return 0; } ret = net_listen(sd, backlog); if (ret == -1) { LOG_ERROR("hub_start_service(): Unable to listen to socket"); net_close(sd); return 0; } server = net_con_create(); net_con_initialize(server, sd, net_on_accept, hub, NET_EVENT_READ); return server; }
int net_socket( const char name[], const char ifname[], int protocol, int af ) { int sock; if( protocol == IPPROTO_TCP ) { sock = socket( af, SOCK_STREAM, IPPROTO_TCP ); } else if( protocol == IPPROTO_UDP ) { sock = socket( af, SOCK_DGRAM, IPPROTO_UDP ); } else { sock = -1; } if( sock < 0 ) { log_err( "%s: Failed to create socket: %s", name, strerror( errno ) ); return -1; } if( net_set_nonblocking( sock ) < 0 ) { close( sock ); log_err( "%s: Failed to make socket nonblocking: '%s'", name, strerror( errno ) ); return -1; } #if defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) if( ifname ) { close( sock ); log_err( "%s: Bind to device not supported on Windows and MacOSX.", name ); return -1; } #else if( ifname && setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen( ifname ) ) ) { close( sock ); log_err( "%s: Unable to bind to device '%s': %s", name, ifname, strerror( errno ) ); return -1; } #endif const int optval = 1; if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) ) < 0 ) { close( sock ); log_err( "%s: Unable to set SO_REUSEADDR for '%s': %s", name, strerror( errno ) ); return -1; } return sock; }
int net_bind( const char *name, const char* addr, const char* port, const char* ifce, int protocol, int af ) { char addrbuf[FULL_ADDSTRLEN+1]; int sock; int val; IP sockaddr; if( af != AF_INET && af != AF_INET6 ) { log_err( "NET: Unknown address family value." ); return -1; } if( addr_parse( &sockaddr, addr, port, af ) != 0 ) { log_err( "NET: Failed to parse IP address '%s' and port '%s'.", addr, port ); return -1; } if( protocol == IPPROTO_TCP ) { sock = socket( sockaddr.ss_family, SOCK_STREAM, IPPROTO_TCP ); } else if( protocol == IPPROTO_UDP ) { sock = socket( sockaddr.ss_family, SOCK_DGRAM, IPPROTO_UDP ); } else { sock = -1; } if( sock < 0 ) { log_err( "NET: Failed to create socket: %s", strerror( errno ) ); return -1; } val = 1; if ( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val) ) < 0 ) { close( sock ); log_err( "NET: Failed to set socket option SO_REUSEADDR: %s", strerror( errno )); return -1; } if( ifce && setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, ifce, strlen( ifce ) ) ) { close( sock ); log_err( "NET: Unable to bind to device '%s': %s", ifce, strerror( errno ) ); return -1; } if( af == AF_INET6 ) { val = 1; if( setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val) ) < 0 ) { close( sock ); log_err( "NET: Failed to set socket option IPV6_V6ONLY: %s", strerror( errno )); return -1; } } if( bind( sock, (struct sockaddr*) &sockaddr, sizeof(IP) ) < 0 ) { close( sock ); log_err( "NET: Failed to bind socket to address: '%s'", strerror( errno ) ); return -1; } if( net_set_nonblocking( sock ) < 0 ) { close( sock ); log_err( "NET: Failed to make socket nonblocking: '%s'", strerror( errno ) ); return -1; } if( protocol == IPPROTO_TCP && listen( sock, 5 ) < 0 ) { close( sock ); log_err( "NET: Failed to listen on socket: '%s'", strerror( errno ) ); return -1; } log_info( ifce ? "%s: Bind to %s, interface %s" : "%s: Bind to %s" , name, str_addr( &sockaddr, addrbuf ), ifce ); return sock; }