static void wd_transfer_listen_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wi_socket_t *socket; wi_address_t *address; pool = wi_pool_init(wi_pool_alloc()); while(wd_running) { wi_pool_drain(pool); socket = wi_socket_accept_multiple(wd_transfer_sockets, 30.0, &address); if(!address) { wi_log_err(WI_STR("Could not accept a connection: %m")); continue; } if(!socket) { wi_log_err(WI_STR("Could not accept a connection for %@: %m"), wi_address_string(address)); continue; } if(!wi_thread_create_thread(wd_transfer_accept_thread, socket)) { wi_log_err(WI_STR("Could not create a transfer thread for %@: %m"), wi_address_string(address)); continue; } } wi_release(pool); }
static void wd_control_accept_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wi_socket_t *socket = argument; wi_string_t *ip; wd_user_t *user; pool = wi_pool_init(wi_pool_alloc()); ip = wi_address_string(wi_socket_address(socket)); if(!wi_socket_accept_tls(socket, wd_control_socket_tls, 30.0)) { wi_log_err(WI_STR("Could not accept a TLS connection for %@: %m"), ip); goto end; } if(!wi_socket_set_timeout(socket, 30.0)) wi_log_warn(WI_STR("Could not set timeout for %@: %m"), ip); wi_socket_set_direction(socket, WI_SOCKET_READ); wi_log_info(WI_STR("Connect from %@"), ip); user = wd_user_with_socket(socket); wd_users_add_user(user); wd_users_set_user_for_thread(user); wd_command_loop_for_user(user); end: wi_socket_close(socket); wi_release(pool); }
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)); }
static void wd_transfer_accept_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wi_socket_t *socket = argument; wi_array_t *arguments; wi_string_t *ip, *string, *command; wd_transfer_t *transfer; pool = wi_pool_init(wi_pool_alloc()); ip = wi_address_string(wi_socket_address(socket)); if(!wi_socket_accept_tls(socket, wd_transfer_socket_tls, 30.0)) { wi_log_err(WI_STR("Could not accept a connection for %@: %m"), ip); goto end; } if(!wi_socket_set_timeout(socket, 30.0)) wi_log_warn(WI_STR("Could not set timeout for %@: %m"), ip); string = wi_socket_read_to_string(socket, 5.0, WI_STR(WD_MESSAGE_SEPARATOR_STR)); if(!string || wi_string_length(string) == 0) { if(!string) wi_log_warn(WI_STR("Could not read from %@: %m"), ip); goto end; } wi_parse_wired_command(string, &command, &arguments); if(wi_is_equal(command, WI_STR("TRANSFER")) && wi_array_count(arguments) >= 1) { transfer = wd_transfers_transfer_with_hash(WI_ARRAY(arguments, 0)); if(!transfer) goto end; if(!wi_is_equal(ip, wd_user_ip(transfer->user))) goto end; wi_lock_lock(transfer->socket_lock); if(!transfer->socket) { transfer->socket = wi_retain(socket); wi_lock_unlock(transfer->socket_lock); wd_transfer_loop(transfer); } else { wi_lock_unlock(transfer->socket_lock); } } end: wi_socket_close(socket); wi_release(pool); }
static void wr_command_save(wi_array_t *arguments) { wi_file_t *file; wi_string_t *path, *login, *password, *port; path = wi_user_home(); path = wi_string_by_appending_path_component(path, WI_STR(WB_WIREBOT_USER_PATH)); path = wi_string_by_appending_path_component(path, WI_ARRAY(arguments, 0)); file = wi_file_for_writing(path); if(!file) { wr_printf_prefix(WI_STR("save: %@: %m"), path); return; } wi_file_write_format(file, WI_STR("charset %@\n"), wi_string_encoding_charset(wr_client_string_encoding)); wi_file_write_format(file, WI_STR("timestamp %@\n"), wr_timestamp_format); wi_file_write_format(file, WI_STR("nick %@\n"), wr_nick); if(wi_string_length(wr_status) > 0) wi_file_write_format(file, WI_STR("status %@\n"), wr_status); if(wr_icon_path) wi_file_write_format(file, WI_STR("icon %@\n"), wr_icon_path); if(wr_connected) { if(wi_string_length(wi_p7_socket_user_name(wr_p7_socket)) > 0) login = wi_string_with_format(WI_STR("-l %@"), wi_p7_socket_user_name(wr_p7_socket)); else login = NULL; if(wi_string_length(wr_password) > 0) password = wi_string_with_format(WI_STR("-p %@"), wr_password); else password = NULL; if(wi_address_port(wi_socket_address(wr_socket)) != WR_PORT) port = wi_string_with_format(WI_STR("-P %u"), wi_address_port(wi_socket_address(wr_socket))); else port = NULL; wi_file_write_format(file, WI_STR("open %#@ %#@ %#@ %@\n"), login, password, port, wi_address_string(wi_socket_address(wr_socket))); } wr_printf_prefix(WI_STR("save: \"%@\" saved"), path); }
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_control_listen_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wi_socket_t *socket; wi_address_t *address; wi_string_t *ip; wd_user_t *user; pool = wi_pool_init(wi_pool_alloc()); while(wd_running) { wi_pool_drain(pool); /* accept new user */ socket = wi_socket_accept_multiple(wd_control_sockets, wd_control_socket_context, 30.0, &address); if(!address) { wi_log_err(WI_STR("Could not accept a connection: %m")); continue; } ip = wi_address_string(address); if(!socket) { wi_log_err(WI_STR("Could not accept a connection for %@: %m"), ip); continue; } wi_socket_set_direction(socket, WI_SOCKET_READ); wi_log_info(WI_STR("Connect from %@"), ip); /* spawn a user thread */ user = wd_user_with_socket(socket); if(!wi_thread_create_thread(wd_control_thread, user)) wi_log_err(WI_STR("Could not create a thread for %@: %m"), ip); } wi_release(pool); }
void wr_client_disconnect(void) { if(wr_connected) { wi_log_info(WI_STR("Connection to %@ closed"), wi_address_string(wi_socket_address(wr_socket))); wr_connected = false; } wr_runloop_remove_socket(wr_socket); wi_socket_close(wr_socket); wi_release(wr_p7_socket); wi_release(wr_socket); wi_release(wr_server); wi_release(wr_password); wr_chats_clear(); wr_users_clear(); }
static wd_user_t * wd_user_init_with_socket(wd_user_t *user, wi_socket_t *socket) { wi_address_t *address; user->uid = wd_user_next_uid(); user->socket = wi_retain(socket); user->state = WD_USER_CONNECTED; user->login_time = wi_time_interval(); user->idle_time = user->login_time; address = wi_socket_address(socket); user->ip = wi_retain(wi_address_string(address)); user->host = wi_retain(wi_address_hostname(address)); user->user_lock = wi_recursive_lock_init(wi_recursive_lock_alloc()); user->socket_lock = wi_lock_init(wi_lock_alloc()); user->transfers_queue = wi_array_init(wi_array_alloc()); return user; }
static wd_user_t * wd_user_init_with_socket(wd_user_t *user, wi_socket_t *socket) { wi_address_t *address; user->id = wd_user_next_id(); user->socket = wi_retain(socket); user->state = WD_USER_CONNECTED; user->login_time = wi_date_init(wi_date_alloc()); user->idle_time = wi_date_init(wi_date_alloc()); address = wi_socket_address(socket); user->ip = wi_retain(wi_address_string(address)); user->host = wi_retain(wi_address_hostname(address)); user->user_lock = wi_recursive_lock_init(wi_recursive_lock_alloc()); user->socket_lock = wi_recursive_lock_init(wi_recursive_lock_alloc()); user->subscribed_paths = wi_set_init_with_capacity(wi_mutable_set_alloc(), 0, true); user->subscribed_virtualpaths = wi_dictionary_init(wi_mutable_dictionary_alloc()); return user; }
void wr_client_disconnect(void) { if(wr_connected) { wr_wprintf_prefix(wr_console_window, WI_STR("Connection to %@ closed"), wi_address_string(wi_socket_address(wr_socket))); wr_connected = false; } wr_runloop_remove_socket(wr_socket); wi_socket_close(wr_socket); wi_release(wr_p7_socket); wi_release(wr_socket); wi_release(wr_server); wi_release(wr_password); wr_windows_clear(); wr_chats_clear(); wr_users_clear(); wr_draw_header(); wr_draw_divider(); }
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; }
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 }
static void wd_transfer_listen_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wi_socket_t *socket; wi_address_t *address; wi_array_t *arguments; wi_string_t *ip, *string, *command; wd_transfer_t *transfer; pool = wi_pool_init(wi_pool_alloc()); while(wd_running) { wi_pool_drain(pool); /* accept new connection */ socket = wi_socket_accept_multiple(wd_transfer_sockets, wd_transfer_socket_context, 30.0, &address); if(!address) { wi_log_err(WI_STR("Could not accept a connection: %m")); continue; } ip = wi_address_string(address); if(!socket) { wi_log_err(WI_STR("Could not accept a connection for %@: %m"), ip); continue; } string = wi_socket_read_to_string(socket, 5.0, WI_STR(WD_MESSAGE_SEPARATOR_STR)); if(!string || wi_string_length(string) == 0) { if(!string) wi_log_warn(WI_STR("Could not read from %@: %m"), ip); continue; } /* parse command */ wi_parse_wired_command(string, &command, &arguments); if(wi_is_equal(command, WI_STR("TRANSFER")) && wi_array_count(arguments) >= 1) { /* get transfer by identifier */ transfer = wd_transfers_transfer_with_hash(WI_ARRAY(arguments, 0)); if(!transfer) continue; if(!wi_is_equal(ip, wd_user_ip(transfer->user))) continue; transfer->socket = wi_retain(socket); /* spawn a transfer thread */ if(!wi_thread_create_thread(wd_transfer_thread, transfer)) wi_log_err(WI_STR("Could not create a thread for %@: %m"), ip); } } wi_release(pool); }
static wi_boolean_t _wi_address_is_equal(wi_runtime_instance_t *instance1, wi_runtime_instance_t *instance2) { wi_address_t *address1 = instance1; wi_address_t *address2 = instance2; return wi_is_equal(wi_address_string(address1), wi_address_string(address2)); }
static wi_hash_code_t _wi_address_hash(wi_runtime_instance_t *instance) { wi_address_t *address = instance; return wi_hash(wi_address_string(address)); }
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); }