wi_socket_t * wi_socket_init_with_address(wi_socket_t *_socket, wi_address_t *address, wi_socket_type_t type) { _socket->address = wi_copy(address); _socket->close = true; _socket->buffer = wi_string_init_with_capacity(wi_string_alloc(), WI_SOCKET_BUFFER_SIZE); _socket->type = type; _socket->sd = socket(wi_address_family(_socket->address), _socket->type, 0); if(_socket->sd < 0) { wi_error_set_errno(errno); wi_release(_socket); return NULL; } if(!_wi_socket_set_option_int(_socket, SOL_SOCKET, SO_REUSEADDR, 1)) { wi_release(_socket); return NULL; } #ifdef SO_REUSEPORT if(!_wi_socket_set_option_int(_socket, SOL_SOCKET, SO_REUSEPORT, 1)) { wi_release(_socket); return NULL; } #endif return _socket; }
wi_integer_t wi_address_compare_family(wi_runtime_instance_t *instance1, wi_runtime_instance_t *instance2) { wi_address_t *address1 = instance1; wi_address_t *address2 = instance2; wi_address_family_t family1; wi_address_family_t family2; family1 = wi_address_family(address1); family2 = wi_address_family(address2); if(family1 == WI_ADDRESS_IPV4 && family2 == WI_ADDRESS_IPV6) return 1; else if(family1 == WI_ADDRESS_IPV6 && family2 == WI_ADDRESS_IPV4) return -1; return 0; }
static wi_string_t * _wi_address_description(wi_runtime_instance_t *instance) { wi_address_t *address = instance; wi_string_t *family; switch(wi_address_family(address)) { case WI_ADDRESS_IPV4: family = WI_STR("ipv4"); break; case WI_ADDRESS_IPV6: family = WI_STR("ipv6"); break; case WI_ADDRESS_NULL: default: family = WI_STR("none"); break; } return wi_string_with_format(WI_STR("<%@ %p>{family = %@, address = %@, port = %lu}"), wi_runtime_class_name(address), address, family, wi_address_string(address), wi_address_port(address)); }
void wi_socket_set_interactive(wi_socket_t *socket, wi_boolean_t interactive) { if(socket->type == WI_SOCKET_TCP && interactive) _wi_socket_set_option(socket, IPPROTO_TCP, TCP_NODELAY, 1); if(wi_address_family(socket->address) == WI_ADDRESS_IPV4) _wi_socket_set_option(socket, IPPROTO_IP, IP_TOS, interactive ? IPTOS_LOWDELAY : IPTOS_THROUGHPUT); socket->interactive = interactive; }
void wi_socket_set_interactive(wi_socket_t *socket, wi_boolean_t interactive) { _wi_socket_set_option_int(socket, IPPROTO_TCP, TCP_NODELAY, interactive ? 1 : 0); #if defined(IPTOS_LOWDELAY) && defined(IPTOS_THROUGHPUT) if(wi_address_family(socket->address) == WI_ADDRESS_IPV4) _wi_socket_set_option_int(socket, IPPROTO_IP, IP_TOS, interactive ? IPTOS_LOWDELAY : IPTOS_THROUGHPUT); #endif socket->interactive = interactive; }
wi_boolean_t wi_socket_listen(wi_socket_t *socket) { struct sockaddr *sa; struct sockaddr_storage ss; wi_uinteger_t port; socklen_t length; port = wi_address_port(socket->address); sa = wi_address_sa(socket->address); length = wi_address_sa_length(socket->address); if(socket->type == WI_SOCKET_TCP) { if(wi_address_family(socket->address) == WI_ADDRESS_IPV6) _wi_socket_set_option_int(socket, IPPROTO_IPV6, IPV6_V6ONLY, 1); } if(bind(socket->sd, sa, length) < 0) { wi_error_set_errno(errno); return false; } if(socket->type == WI_SOCKET_TCP) { if(listen(socket->sd, SOMAXCONN) < 0) { wi_error_set_errno(errno); return false; } } if(port == 0) { length = sizeof(ss); if(getsockname(socket->sd, (struct sockaddr *) &ss, &length) == 0) { wi_release(socket->address); socket->address = wi_address_init_with_sa(wi_address_alloc(), (struct sockaddr *) &ss); } } socket->direction = WI_SOCKET_READ; return true; }
void wd_server_init(void) { wi_enumerator_t *enumerator; wi_array_t *array, *addresses; wi_address_t *address; wi_socket_t *control_socket, *transfer_socket; wi_string_t *ip, *string; wi_address_family_t family; wd_control_sockets = wi_array_init(wi_mutable_array_alloc()); wd_transfer_sockets = wi_array_init(wi_mutable_array_alloc()); addresses = wi_array_init(wi_mutable_array_alloc()); if(wi_array_count(wd_settings.address) > 0) { /* listen on configured addresses */ wi_array_rdlock(wd_settings.address); enumerator = wi_array_data_enumerator(wd_settings.address); while((string = wi_enumerator_next_data(enumerator))) { array = wi_host_addresses(wi_host_with_string(string)); if(array) wi_mutable_array_add_data_from_array(addresses, array); else wi_log_err(WI_STR("Could not resolve \"%@\": %m"), string); } wi_array_unlock(wd_settings.address); } else { /* add wildcard addresses */ wi_mutable_array_add_data(addresses, wi_address_wildcard_for_family(WI_ADDRESS_IPV6)); wi_mutable_array_add_data(addresses, wi_address_wildcard_for_family(WI_ADDRESS_IPV4)); } enumerator = wi_array_data_enumerator(addresses); while((address = wi_enumerator_next_data(enumerator))) { ip = wi_address_string(address); family = wi_address_family(address); /* force address family? */ if(wd_address_family != WI_ADDRESS_NULL && family != wd_address_family) continue; /* create sockets */ wi_address_set_port(address, wd_settings.port); control_socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP)); wi_address_set_port(address, wd_settings.port + 1); transfer_socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP)); if(!control_socket || !transfer_socket) { wi_log_warn(WI_STR("Could not create socket for %@: %m"), ip); continue; } /* listen on sockets */ if(!wi_socket_listen(control_socket)) { wi_log_warn(WI_STR("Could not listen on %@ port %u: %m"), ip, wi_address_port(wi_socket_address(control_socket))); continue; } if(!wi_socket_listen(transfer_socket)) { wi_log_warn(WI_STR("Could not listen on %@ port %u: %m"), ip, wi_address_port(wi_socket_address(transfer_socket))); continue; } wi_socket_set_interactive(control_socket, true); wi_socket_set_interactive(transfer_socket, false); /* add to list of sockets */ wi_mutable_array_add_data(wd_control_sockets, control_socket); wi_mutable_array_add_data(wd_transfer_sockets, transfer_socket); wi_log_info(WI_STR("Listening on %@ ports %d-%d"), ip, wd_settings.port, wd_settings.port + 1); } if(wi_array_count(wd_control_sockets) == 0 || wi_array_count(wd_transfer_sockets) == 0) wi_log_fatal(WI_STR("No addresses available for listening")); wi_release(addresses); #ifdef HAVE_DNS_SD_H if(wd_settings.zeroconf) wd_server_register_dnssd(); #endif }