void wi_test_host_runtime_functions(void) { wi_host_t *host1, *host2, *host3, *host4, *host5, *host6; host1 = wi_host(); host2 = wi_autorelease(wi_copy(host1)); host3 = wi_host_with_string(WI_STR("localhost")); host4 = wi_autorelease(wi_copy(host3)); host5 = wi_host_with_string(WI_STR("aab119a592b9e23779b66649677b436d24b35aaa5ad5beadf4c2a945b70577e5.com")); host6 = wi_autorelease(wi_copy(host5)); WI_TEST_ASSERT_EQUAL_INSTANCES(host1, host2, ""); WI_TEST_ASSERT_EQUAL_INSTANCES(host3, host4, ""); WI_TEST_ASSERT_EQUAL_INSTANCES(host5, host6, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host1, host3, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host2, host3, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host1, host4, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host2, host4, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host1, host5, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host2, host5, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host1, host6, ""); WI_TEST_ASSERT_NOT_EQUAL_INSTANCES(host2, host6, ""); WI_TEST_ASSERT_EQUALS(wi_hash(host1), wi_hash(host2), ""); WI_TEST_ASSERT_EQUALS(wi_hash(host3), wi_hash(host4), ""); WI_TEST_ASSERT_EQUALS(wi_hash(host5), wi_hash(host6), ""); WI_TEST_ASSERT_EQUALS(wi_runtime_id(host1), wi_host_runtime_id(), ""); WI_TEST_ASSERT_EQUALS(wi_runtime_id(host2), wi_host_runtime_id(), ""); WI_TEST_ASSERT_EQUALS(wi_runtime_id(host3), wi_host_runtime_id(), ""); WI_TEST_ASSERT_EQUALS(wi_runtime_id(host4), wi_host_runtime_id(), ""); WI_TEST_ASSERT_EQUALS(wi_runtime_id(host5), wi_host_runtime_id(), ""); WI_TEST_ASSERT_EQUALS(wi_runtime_id(host6), wi_host_runtime_id(), ""); #ifdef HAVE_GETIFADDRS WI_TEST_ASSERT_NOT_EQUALS(wi_string_index_of_string(wi_description(host1), WI_STR("127.0.0.1"), 0), WI_NOT_FOUND, ""); #else WI_TEST_ASSERT_NOT_EQUALS(wi_string_index_of_string(wi_description(host1), WI_STR("0.0.0.0"), 0), WI_NOT_FOUND, ""); #endif WI_TEST_ASSERT_NOT_EQUALS(wi_string_index_of_string(wi_description(host3), WI_STR("127.0.0.1"), 0), WI_NOT_FOUND, ""); }
void wi_test_host_creation(void) { wi_host_t *host; host = wi_host(); WI_TEST_ASSERT_NOT_NULL(host, ""); WI_TEST_ASSERT_NOT_NULL(wi_host_address(host), ""); host = wi_host_with_string(WI_STR("localhost")); WI_TEST_ASSERT_NOT_NULL(host, ""); WI_TEST_ASSERT_NOT_NULL(wi_host_address(host), ""); }
void wi_test_host_addresses(void) { wi_host_t *host; wi_array_t *addresses; host = wi_host(); addresses = wi_host_addresses(host); WI_TEST_ASSERT_TRUE(wi_array_count(addresses) > 0, ""); WI_TEST_ASSERT_TRUE(wi_array_contains_data(addresses, wi_host_address(host)), ""); #ifndef HAVE_GETIFADDRS WI_TEST_ASSERT_TRUE(wi_array_contains_data(addresses, wi_address_wildcard_for_family(WI_ADDRESS_IPV4)), ""); WI_TEST_ASSERT_TRUE(wi_array_contains_data(addresses, wi_address_wildcard_for_family(WI_ADDRESS_IPV6)), ""); #endif host = wi_host_with_string(WI_STR("aab119a592b9e23779b66649677b436d24b35aaa5ad5beadf4c2a945b70577e5.com")); WI_TEST_ASSERT_NULL(wi_host_addresses(host), ""); WI_TEST_ASSERT_NULL(wi_host_address(host), ""); }
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 }
void wr_client_connect(wi_string_t *hostname, wi_uinteger_t port, wi_string_t *login, wi_string_t *password) { wi_enumerator_t *enumerator; wi_array_t *addresses; wi_address_t *address; wi_p7_socket_t *p7_socket; wi_p7_message_t *message; wi_socket_t *socket; wi_string_t *ip; wr_server_t *server; if(wr_connected) wr_client_disconnect(); wr_printf_prefix(WI_STR("Connecting to %@..."), hostname); if(port == 0) port = WR_PORT; if(!login) login = WI_STR("guest"); if(!password) password = WI_STR(""); addresses = wi_host_addresses(wi_host_with_string(hostname)); if(!addresses) { wr_printf_prefix(WI_STR("Could not resolve \"%@\": %m"), hostname); return; } enumerator = wi_array_data_enumerator(addresses); while((address = wi_enumerator_next_data(enumerator))) { ip = wi_address_string(address); wr_printf_prefix(WI_STR("Trying %@ at port %u..."), ip, port); wi_address_set_port(address, port); socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP)); if(!socket) { wr_printf_prefix(WI_STR("Could not open a socket to %@: %m"), ip); continue; } wi_socket_set_interactive(socket, true); if(!wi_socket_connect(socket, 10.0)) { wr_printf_prefix(WI_STR("Could not connect to %@: %m"), ip); continue; } p7_socket = wi_autorelease(wi_p7_socket_init_with_socket(wi_p7_socket_alloc(), socket, wr_p7_spec)); if(!wi_p7_socket_connect(p7_socket, 10.0, WI_P7_COMPRESSION_DEFLATE | WI_P7_ENCRYPTION_RSA_AES256_SHA1 | WI_P7_CHECKSUM_SHA1, WI_P7_BINARY, login, wi_string_sha1(password))) { wr_printf_prefix(WI_STR("Could not connect to %@: %m"), ip); continue; } wr_printf_prefix(WI_STR("Connected using %@/%u bits, logging in..."), wi_cipher_name(wi_p7_socket_cipher(p7_socket)), wi_cipher_bits(wi_p7_socket_cipher(p7_socket))); server = wr_client_login(p7_socket, login, password); if(!server) break; wr_printf_prefix(WI_STR("Logged in, welcome to %@"), wr_server_name(server)); message = wi_p7_message_with_name(WI_STR("wired.chat.join_chat"), wr_p7_spec); wi_p7_message_set_uint32_for_name(message, wr_chat_id(wr_public_chat), WI_STR("wired.chat.id")); wr_client_write_message(p7_socket, message); wr_connected = true; wr_socket = wi_retain(socket); wr_p7_socket = wi_retain(p7_socket); wr_server = wi_retain(server); wr_password = wi_retain(password); wi_socket_set_direction(wr_socket, WI_SOCKET_READ); wr_runloop_add_socket(wr_socket, &wr_runloop_server_callback); break; } wr_draw_divider(); }
void wd_trackers_apply_settings(void) { wi_enumerator_t *enumerator, *address_enumerator; wi_string_t *string, *path; wi_url_t *url; wi_address_t *address; wd_tracker_t *tracker; wi_uinteger_t port; wi_array_wrlock(wd_trackers); wi_mutable_array_remove_all_data(wd_trackers); enumerator = wi_array_data_enumerator(wd_settings.tracker); while((string = wi_enumerator_next_data(enumerator))) { tracker = wi_autorelease(wd_tracker_init(wd_tracker_alloc())); url = wi_autorelease(wi_url_init_with_string(wi_url_alloc(), string)); if(!wi_url_is_valid(url)) { wi_log_warn(WI_STR("Could not parse tracker URL \"%@\""), string); continue; } tracker->tls = wi_socket_tls_init_with_type(wi_socket_tls_alloc(), WI_SOCKET_TLS_CLIENT); if(!tracker->tls) { wi_log_warn(WI_STR("Could not create TLS context: %m")); continue; } if(wd_settings.controlcipher) { if(!wi_socket_tls_set_ciphers(tracker->tls, wd_settings.controlcipher)) { wi_log_err(WI_STR("Could not set TLS cipher list \"%@\": %m"), wd_settings.controlcipher); continue; } } path = wi_url_path(url); if(!path || wi_string_length(path) == 0) path = WI_STR("/"); tracker->host = wi_retain(wi_url_host(url)); tracker->category = wi_retain(wi_string_substring_from_index(path, 1)); tracker->addresses = wi_retain(wi_host_addresses(wi_host_with_string(tracker->host))); if(!tracker->addresses) { wi_log_warn(WI_STR("Could not resolve \"%@\": %m"), tracker->host); continue; } port = wi_url_port(url); if(port == 0) port = WD_TRACKER_PORT; address_enumerator = wi_array_data_enumerator(tracker->addresses); while((address = wi_enumerator_next_data(address_enumerator))) wi_address_set_port(address, port); wi_mutable_array_add_data(wd_trackers, tracker); } wi_array_unlock(wd_trackers); }
void wr_connect(wi_string_t *hostname, wi_uinteger_t port, wi_string_t *login, wi_string_t *password) { wi_enumerator_t *enumerator; wi_array_t *addresses; wi_address_t *address; wi_socket_t *socket; wi_string_t *ip; if(wr_connected) wr_disconnect(); wr_printf_prefix(WI_STR("Connecting to %@..."), hostname); if(port == 0) port = WR_CONTROL_PORT; addresses = wi_host_addresses(wi_host_with_string(hostname)); if(!addresses) { wr_printf_prefix(WI_STR("Could not resolve \"%@\": %m"), hostname); return; } enumerator = wi_array_data_enumerator(addresses); while((address = wi_enumerator_next_data(enumerator))) { ip = wi_address_string(address); wr_printf_prefix(WI_STR("Trying %@ at port %u..."), ip, port); wi_address_set_port(address, port); socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP)); if(!socket) { wr_printf_prefix(WI_STR("Could not open a socket to %@: %m"), ip); continue; } wi_socket_set_interactive(socket, true); if(!wi_socket_connect(socket, 10.0)) { wr_printf_prefix(WI_STR("Could not connect to %@: %m"), ip); continue; } if(!wi_socket_connect_tls(socket, wr_socket_tls, 10.0)) { wr_printf_prefix(WI_STR("Could not connect to %@: %m"), ip); continue; } wr_printf_prefix(WI_STR("Connected using %@/%@/%u bits, logging in..."), wi_socket_cipher_version(socket), wi_socket_cipher_name(socket), wi_socket_cipher_bits(socket)); wr_connected = true; wr_host = wi_retain(hostname); wr_port = port; wr_login = wi_retain(login); wr_password = wi_retain(password); wr_socket = wi_retain(socket); wr_address = wi_retain(address); wr_runloop_add_socket(wr_socket, &wr_runloop_server_callback); wr_send_command(WI_STR("HELLO")); break; } if(wr_socket) wi_socket_set_direction(wr_socket, WI_SOCKET_READ); }
static void wt_cmd_register(wi_array_t *arguments) { wt_client_t *client = wt_client(); wi_enumerator_t *enumerator; wi_array_t *array; wi_address_t *address, *hostaddress; wi_url_t *url; wi_string_t *hostname; wt_server_t *server; wi_boolean_t failed = false, passed; uint32_t bandwidth; url = wi_autorelease(wi_url_init_with_string(wi_url_alloc(), WI_ARRAY(arguments, 1))); hostname = wi_url_host(url); address = wi_socket_address(client->socket); if(!wi_url_is_valid(url)) { /* invalid URL */ if(wt_settings.strictlookup) { wt_reply(503, WI_STR("Syntax Error")); wi_log_warn(WI_STR("Register from %@ as \"%@\" URL %@ aborted: %s"), client->ip, WI_ARRAY(arguments, 2), WI_ARRAY(arguments, 1), "Invalid URL"); return; } failed = true; goto failed; } if(wi_ip_version(hostname) > 0) { /* hostname is numeric, compare with source address */ if(!wi_is_equal(hostname, client->ip)) { /* IP mismatch */ if(wt_settings.strictlookup) { wt_reply(530, WI_STR("Address Mismatch")); wi_log_warn(WI_STR("Register from %@ as \"%@\" URL %@ denied: %s"), client->ip, WI_ARRAY(arguments, 2), WI_ARRAY(arguments, 1), "IP mismatch"); return; } failed = true; goto failed; } } else { /* hostname is symbolic */ if(wt_settings.lookup) { /* look up and compare with source address */ passed = false; array = wi_host_addresses(wi_host_with_string(hostname)); if(array) { enumerator = wi_array_data_enumerator(array); while((hostaddress = wi_enumerator_next_data(enumerator))) { if(wi_is_equal(hostaddress, address)) { passed = true; break; } } } if(!passed) { /* lookup failed */ if(wt_settings.strictlookup) { wt_reply(531, WI_STR("Address Mismatch")); wi_log_warn(WI_STR("Register from %@ as \"%@\" URL %@ denied: %s"), client->ip, WI_ARRAY(arguments, 2), WI_ARRAY(arguments, 1), "Lookup failed"); return; } failed = true; goto failed; } } if(wt_settings.reverselookup) { /* reverse look up and compare to hostname */ if(!wi_is_equal(wi_address_hostname(address), hostname)) { /* reverse lookup failed */ if(wt_settings.strictlookup) { wt_reply(531, WI_STR("Address Mismatch")); wi_log_warn(WI_STR("Register from %@ as \"%@\" URL % denied: %@"), client->ip, WI_ARRAY(arguments, 2), WI_ARRAY(arguments, 1), "Reverse lookup failed"); return; } failed = true; goto failed; } } } failed: /* get bandwidth */ bandwidth = wi_string_uint32(WI_ARRAY(arguments, 3)); /* bandwidth too low? */ if(wt_settings.minbandwidth > 0 && bandwidth < wt_settings.minbandwidth) { wt_reply(516, WI_STR("Permission Denied")); wi_log_warn(WI_STR("Register from %@ as \"%@\" URL %@ denied: Bandwidth %.0f Kbps considered too low"), client->ip, WI_ARRAY(arguments, 2), WI_ARRAY(arguments, 1), bandwidth / 128.0); return; } /* bandwidth too high? */ if(wt_settings.maxbandwidth > 0 && bandwidth > wt_settings.maxbandwidth) { wt_reply(516, WI_STR("Permission Denied")); wi_log_warn(WI_STR("Register from %@ as \"%@\" URL %@ denied: Bandwidth %.0f Kbps considered too high"), client->ip, WI_ARRAY(arguments, 2), WI_ARRAY(arguments, 1), bandwidth / 128.0); return; } /* is there an existing server from this host? */ server = wt_servers_server_with_ip(client->ip); if(server) { if(server->port == wi_url_port(url)) { /* remove existing server in preparation for re-registration */ wt_servers_remove_stats_for_server(server); wt_servers_remove_server(server); } else { /* multiple servers from the same IP allowed? */ if(!wt_settings.allowmultiple) { wt_reply(530, WI_STR("Address Registered")); wi_log_warn(WI_STR("Register from %@ as \"%@\" URL %@ denied: %s"), client->ip, WI_ARRAY(arguments, 2), WI_ARRAY(arguments, 1), "A server from the same address is already registered"); return; } } } /* rewrite URL if host verification failed */ if(failed) { wi_url_set_scheme(url, WI_STR("wired")); wi_url_set_host(url, client->ip); if(wi_string_length(WI_ARRAY(arguments, 1)) == 0) wi_log_info(WI_STR("Rewriting URL to %@"), wi_url_string(url)); else wi_log_info(WI_STR("Rewriting URL from %@ to %@"), WI_ARRAY(arguments, 1), wi_url_string(url)); } /* create new server */ server = wt_server_init(wt_server_alloc()); server->key = wi_retain(wi_string_sha1(wi_autorelease(wi_string_init_random_string_with_length(wi_string_alloc(), 1024)))); server->port = wi_url_port(url); server->bandwidth = bandwidth; server->register_time = wi_time_interval(); server->update_time = 0.0; server->ip = wi_retain(client->ip); server->category = wt_servers_category_is_valid(WI_ARRAY(arguments, 0)) ? wi_retain(WI_ARRAY(arguments, 0)) : wi_string_init(wi_string_alloc()); server->name = wi_retain(WI_ARRAY(arguments, 2)); server->description = wi_retain(WI_ARRAY(arguments, 4)); server->url = wi_copy(wi_url_string(url)); wt_servers_add_server(server); wt_servers_add_stats_for_server(server); /* reply 700 */ wt_reply(700, WI_STR("%@"), server->key); wi_log_info(WI_STR("Registered \"%@\" with URL %@"), server->name, server->url); wt_servers_write_file(); wi_release(server); }
void wr_connect(wi_string_t *hostname, unsigned int port, wi_string_t *login, wi_string_t *password) { wi_list_t *addresses; wi_list_node_t *node; wi_address_t *address; wi_socket_t *socket; wi_string_t *ip; if(wr_connected) wr_disconnect(); wr_printf_prefix(WI_STR("Connecting to %@..."), hostname); if(port == 0) port = WR_CONTROL_PORT; addresses = wi_host_addresses(wi_host_with_string(hostname)); if(!addresses) { wr_printf_prefix(WI_STR("Could not resolve \"%@\": %m"), hostname); return; } WI_LIST_FOREACH(addresses, node, address) { ip = wi_address_string(address); wr_printf_prefix(WI_STR("Trying %@..."), ip); wi_address_set_port(address, port); socket = wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP); wi_socket_set_interactive(socket, true); if(!wi_socket_connect(socket, wr_socket_context, 10.0)) { wr_printf_prefix(WI_STR("Could not connect to %@: %m"), ip); goto next; } wr_printf_prefix(WI_STR("Connected using %@/%@/%u bits, logging in..."), wi_socket_cipher_version(socket), wi_socket_cipher_name(socket), wi_socket_cipher_bits(socket)); wr_connected = true; wr_host = wi_retain(hostname); wr_port = port; wr_login = wi_retain(login); wr_password = wi_retain(password); wr_socket = wi_retain(socket); wr_address = wi_retain(address); wr_runloop_add_socket(wr_socket, &wr_runloop_server_callback); wr_send_command(WI_STR("HELLO")); next: wi_release(socket); if(wr_connected) break; }