static void wd_tracker_update(wd_tracker_t *tracker) { wi_socket_t *socket; wi_integer_t bytes; uint32_t guest, download; guest = (wd_trackers_guest_account != NULL); download = (guest && wd_trackers_guest_account->download); socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), tracker->address, WI_SOCKET_UDP)); if(!socket) { wi_log_err(WI_STR("Could not create a socket for tracker %@: %m"), tracker->host); return; } bytes = wi_socket_sendto(socket, tracker->context, WI_STR("UPDATE %#@%c%u%c%u%c%u%c%u%c%llu%c"), tracker->key, WD_FIELD_SEPARATOR, wd_current_users, WD_FIELD_SEPARATOR, guest, WD_FIELD_SEPARATOR, download, WD_FIELD_SEPARATOR, wd_files_unique_count, WD_FIELD_SEPARATOR, wd_files_unique_size, WD_MESSAGE_SEPARATOR); if(bytes < 0) { wi_log_err(WI_STR("Could not send message to tracker %@: %m"), tracker->host); return; } }
wi_socket_t * wi_socket_accept(wi_socket_t *accept_socket, wi_time_interval_t timeout, wi_address_t **address) { wi_socket_t *socket; struct sockaddr_storage ss; socklen_t length; int sd, err = 0; length = sizeof(ss); sd = accept(accept_socket->sd, (struct sockaddr *) &ss, &length); if(sd < 0) err = errno; *address = (length > 0) ? wi_autorelease(wi_address_init_with_sa(wi_address_alloc(), (struct sockaddr *) &ss)) : NULL; if(sd < 0) { wi_error_set_errno(err); return NULL; } socket = wi_socket_init_with_descriptor(wi_socket_alloc(), sd); socket->close = true; socket->address = wi_retain(*address); socket->type = accept_socket->type; socket->direction = WI_SOCKET_READ; socket->interactive = accept_socket->interactive; return wi_autorelease(socket); }
static void wr_msg_400(wi_array_t *arguments) { wi_address_t *address; wr_transfer_t *transfer; transfer = wr_transfers_transfer_with_path(WI_ARRAY(arguments, 0)); if(!transfer) return; address = wi_copy(wr_address); wi_address_set_port(address, wi_address_port(address) + 1); transfer->state = WR_TRANSFER_RUNNING; transfer->offset = wi_string_uint64(WI_ARRAY(arguments, 1)); transfer->transferred = transfer->offset; transfer->key = wi_retain(WI_ARRAY(arguments, 2)); transfer->start_time = wi_time_interval(); transfer->socket = wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP); wi_socket_set_interactive(transfer->socket, false); if(!wi_socket_connect(transfer->socket, wr_socket_context, 15.0)) { wr_printf_prefix(WI_STR("Could not connect to %@: %m"), wi_address_string(address)); wr_transfer_stop(transfer); goto end; } wi_file_seek(transfer->file, transfer->offset); if(transfer->type == WR_TRANSFER_DOWNLOAD) { wi_socket_set_direction(transfer->socket, WI_SOCKET_READ); wr_runloop_add_socket(transfer->socket, wr_runloop_download_callback); } else { wi_socket_set_direction(transfer->socket, WI_SOCKET_WRITE); wr_runloop_add_socket(transfer->socket, wr_runloop_upload_callback); } wr_send_command_on_socket(transfer->socket, WI_STR("TRANSFER %#@"), transfer->key); wr_printf_prefix(WI_STR("Starting transfer of \"%@\""), transfer->name); wr_draw_transfers(true); end: wi_release(address); }
static void wd_tracker_update(wd_tracker_t *tracker) { wi_socket_t *socket; wi_data_t *data; wi_string_t *string; wi_integer_t bytes; uint32_t guest, download; guest = (wd_trackers_guest_account != NULL); download = (guest && wd_trackers_guest_account->download); socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), tracker->address, WI_SOCKET_UDP)); if(!socket) { wi_log_err(WI_STR("Could not create a socket for tracker %@: %m"), tracker->host); return; } string = wi_string_with_format(WI_STR("UPDATE %#@%c%u%c%u%c%u%c%u%c%llu%c"), tracker->key, WD_FIELD_SEPARATOR, wd_current_users, WD_FIELD_SEPARATOR, guest, WD_FIELD_SEPARATOR, download, WD_FIELD_SEPARATOR, wd_files_count, WD_FIELD_SEPARATOR, wd_files_size, WD_MESSAGE_SEPARATOR); data = wi_rsa_encrypt(tracker->public_key, wi_string_data(string)); bytes = wi_socket_sendto_data(socket, data); if(bytes < 0) { wi_log_err(WI_STR("Could not send message to tracker %@: %m"), tracker->host); return; } }
wi_socket_t * wi_socket_with_address(wi_address_t *address, wi_socket_type_t type) { return wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, type)); }
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(); }
static void wd_tracker_register(wd_tracker_t *tracker) { wi_enumerator_t *enumerator; wi_address_t *address; wi_array_t *arguments; wi_string_t *ip, *string; uint32_t message; wi_boolean_t fatal = false; if(!wi_lock_trylock(tracker->register_lock)) return; enumerator = wi_array_data_enumerator(tracker->addresses); while((address = wi_enumerator_next_data(enumerator))) { tracker->active = false; tracker->address = NULL; ip = wi_address_string(address); wi_log_info(WI_STR("Trying %@ for tracker %@..."), ip, tracker->host); tracker->socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP)); if(!tracker->socket) { wi_log_err(WI_STR("Could not create socket for tracker %@: %m"), tracker->host); continue; } if(!wi_socket_connect(tracker->socket, 30.0)) { wi_log_err(WI_STR("Could not connect to tracker %@: %m"), tracker->host); continue; } if(!wi_socket_connect_tls(tracker->socket, tracker->tls, 30.0)) { wi_log_err(WI_STR("Could not connect to tracker %@: %m"), tracker->host); continue; } if(!wd_tracker_write(tracker, WI_STR("HELLO"))) continue; if(!wd_tracker_read(tracker, &message, &arguments)) continue; if(message != 200) { string = wi_array_components_joined_by_string(arguments, WI_STR(" ")); wi_log_err(WI_STR("Could not register with tracker %@: Unexpected reply \"%u %@\""), tracker->host, message, string); fatal = true; continue; } if(!wd_tracker_write(tracker, WI_STR("CLIENT %#@"), wd_server_version_string)) continue; if(!wd_tracker_write(tracker, WI_STR("REGISTER %#@%c%#@%c%#@%c%u%c%#@"), tracker->category, WD_FIELD_SEPARATOR, wd_settings.url, WD_FIELD_SEPARATOR, wd_settings.name, WD_FIELD_SEPARATOR, wd_settings.bandwidth, WD_FIELD_SEPARATOR, wd_settings.description)) continue; if(!wd_tracker_read(tracker, &message, &arguments)) continue; if(message != 700 || wi_array_count(arguments) < 1) { string = wi_array_components_joined_by_string(arguments, WI_STR(" ")); wi_log_err(WI_STR("Could not register with tracker %@: Unexpected reply \"%u %@\""), tracker->host, message, string); break; } wi_release(tracker->key); tracker->key = wi_retain(WI_ARRAY(arguments, 0)); tracker->public_key = wi_retain(wi_socket_ssl_public_key(tracker->socket)); if(!tracker->public_key) { wi_log_err(WI_STR("Could not get public key from the tracker %@: %m"), tracker->host); break; } wi_log_info(WI_STR("Registered with the tracker %@"), tracker->host); tracker->active = true; tracker->address = address; break; } wi_lock_unlock(tracker->register_lock); }
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); }
wi_socket_t * wi_socket_accept(wi_socket_t *accept_socket, wi_socket_context_t *context, wi_time_interval_t timeout, wi_address_t **address) { wi_socket_t *socket; #ifdef WI_SSL SSL *ssl = NULL; #endif struct sockaddr_storage ss; socklen_t length; int sd; length = sizeof(ss); sd = accept(accept_socket->sd, (struct sockaddr *) &ss, &length); *address = (length > 0) ? wi_autorelease(wi_address_init_with_sa(wi_address_alloc(), (struct sockaddr *) &ss)) : NULL; if(sd < 0) { wi_error_set_errno(errno); goto err; } #ifdef WI_SSL if(context && context->ssl_ctx) { ssl = SSL_new(context->ssl_ctx); if(!ssl) { wi_error_set_ssl_error(); goto err; } if(SSL_set_fd(ssl, sd) != 1) { wi_error_set_ssl_error(); goto err; } if(!context->certificate && context->dh) { if(SSL_set_tmp_dh(ssl, context->dh) != 1) { wi_error_set_ssl_error(); goto err; } } if(timeout > 0.0) { if(wi_socket_wait_descriptor(sd, timeout, true, false) <= 0) goto err; } if(SSL_accept(ssl) != 1) { wi_error_set_ssl_error(); goto err; } } #endif socket = wi_socket_init_with_descriptor(wi_socket_alloc(), sd); socket->close = true; socket->address = wi_retain(*address); socket->type = accept_socket->type; socket->direction = WI_SOCKET_READ; socket->interactive = accept_socket->interactive; #ifdef WI_SSL socket->ssl = ssl; #endif return wi_autorelease(socket); err: #ifdef WI_SSL if(ssl) SSL_free(ssl); #endif if(sd >= 0) close(sd); return NULL; }
wi_p7_socket_t * wi_p7_socket_init_with_descriptor(wi_p7_socket_t *p7_socket, int sd, wi_p7_spec_t *p7_spec) { p7_socket->socket = wi_socket_init_with_descriptor(wi_socket_alloc(), sd); p7_socket->spec = wi_retain(p7_spec); return p7_socket; }
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; }