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; } }
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); }
void wd_ssl_init(void) { unsigned char dh1024_p[] = { 0xBC,0xBB,0x2B,0x4F,0x58,0x58,0x9C,0x4D,0x46,0x0D,0xBB,0x9E, 0x4D,0x85,0x69,0x56,0x43,0x5E,0xFB,0xC8,0xF6,0xC0,0xAC,0x8E, 0xCB,0xF6,0x0B,0x38,0x8F,0x25,0xD6,0x7A,0xA1,0x26,0xC4,0x74, 0x74,0x98,0x96,0x3F,0x96,0x90,0x3B,0x00,0x6E,0xE3,0x0A,0x61, 0xA9,0xA2,0x62,0x49,0xDA,0x7D,0xE0,0x6B,0x8F,0xA7,0x89,0x7F, 0x41,0x09,0x09,0xA3,0xA2,0x5F,0x2C,0xD3,0x77,0x26,0x8D,0x81, 0x33,0x04,0xEF,0x40,0x75,0xB2,0xCF,0xBA,0xEF,0xD5,0x08,0xF4, 0x9E,0x30,0xD2,0x57,0x12,0xD6,0xEA,0x86,0xCA,0x10,0x7B,0x4B, 0x93,0x42,0x7E,0x79,0x42,0x36,0x5D,0x2B,0x23,0xDB,0x7E,0xAB, 0xDB,0xFD,0x1B,0xDA,0x86,0x49,0x15,0x92,0x41,0x56,0xDD,0x68, 0x2C,0x7F,0xAA,0x34,0x56,0x80,0xA5,0x8B }; unsigned char dh1024_g[] = { 0x02 }; wd_control_socket_context = wi_socket_context_init(wi_socket_context_alloc()); wd_transfer_socket_context = wi_socket_context_init(wi_socket_context_alloc()); if(!wi_socket_context_set_ssl_type(wd_control_socket_context, WI_SOCKET_SSL_SERVER) || !wi_socket_context_set_ssl_type(wd_transfer_socket_context, WI_SOCKET_SSL_SERVER)) wi_log_err(WI_STR("Could not set SSL context: %m")); if(!wi_socket_context_set_ssl_dh(wd_control_socket_context, dh1024_p, sizeof(dh1024_p), dh1024_g, sizeof(dh1024_g)) || !wi_socket_context_set_ssl_dh(wd_transfer_socket_context, dh1024_p, sizeof(dh1024_p), dh1024_g, sizeof(dh1024_g))) wi_log_err(WI_STR("Could not set anonymous DH key: %m")); }
wi_boolean_t wt_category_is_valid(wi_string_t *category) { wi_file_t *file; wi_string_t *string; wi_boolean_t result = false; if(wi_string_length(category) == 0) return true; file = wi_file_for_reading(wt_settings.categories); if(!file) { wi_log_err(WI_STR("Could not open %@: %m"), wt_settings.categories); return true; } while((string = wi_file_read_config_line(file))) { if(wi_is_equal(category, string)) { result = true; break; } } return result; }
wi_boolean_t wd_banlist_ip_is_banned(wi_string_t *ip) { wi_file_t *file; wi_string_t *string; wi_boolean_t banned = false; wi_dictionary_rdlock(wd_tempbans); banned = (wi_dictionary_data_for_key(wd_tempbans, ip) != NULL); wi_dictionary_unlock(wd_tempbans); if(banned) return banned; if(wd_settings.banlist) { file = wi_file_for_reading(wd_settings.banlist); if(!file) { wi_log_err(WI_STR("Could not open %@: %m"), wd_settings.banlist); } else { while((string = wi_file_read_config_line(file))) { if(wi_ip_matches_string(ip, string)) { banned = true; break; } } } } return banned; }
wi_boolean_t wi_settings_read_file(wi_settings_t *settings, wi_boolean_t chroot) { wi_file_t *file; wi_string_t *path, *string; wi_boolean_t result = true; path = wi_full_path(wi_settings_config_path); file = wi_file_for_reading(path); if(!file) { wi_log_err(WI_STR("Could not open %@: %s"), path, strerror(errno)); return false; } wi_log_info(WI_STR("Reading %@"), path); _wi_settings_clear(settings); settings->file = path; settings->line = 0; settings->chroot = chroot; while((string = wi_file_read_line(file))) { settings->line++; if(wi_string_length(string) > 0 && !wi_string_has_prefix(string, WI_STR("#"))) { if(!_wi_settings_parse_setting(settings, string)) result = false; } } settings->file = NULL; return result; }
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); }
wi_boolean_t wi_settings_read_file(wi_settings_t *settings) { wi_file_t *file; wi_string_t *string; file = wi_file_for_reading(wi_settings_config_path); if(!file) { wi_log_err(WI_STR("Could not open %@: %s"), wi_settings_config_path, strerror(errno)); return false; } wi_log_info(WI_STR("Reading %@"), wi_settings_config_path); _wi_settings_clear(settings); settings->file = wi_settings_config_path; settings->line = 0; while((string = wi_file_read_line(file))) { settings->line++; if(wi_string_length(string) > 0 && !wi_string_has_prefix(string, WI_STR("#"))) _wi_settings_parse_setting(settings, string); } settings->file = NULL; return true; }
void wd_transfers_queue_download(wi_string_t *path, wi_file_offset_t offset) { wd_client_t *client = wd_client(); wi_string_t *realpath; wd_transfer_t *transfer; struct stat sb; realpath = wd_files_real_path(path); wi_string_resolve_aliases_in_path(realpath); if(!wi_file_stat(realpath, &sb)) { wi_log_err(WI_STR("Could not open %@: %m"), realpath); wd_reply_error(); return; } transfer = wd_transfer_init_download_with_client(wd_transfer_alloc(), client); transfer->path = wi_retain(path); transfer->realpath = wi_retain(realpath); transfer->size = sb.st_size; transfer->offset = offset; transfer->transferred = offset; wi_list_wrlock(wd_transfers); wi_list_append_data(wd_transfers, transfer); wi_list_unlock(wd_transfers); wi_release(transfer); wd_transfers_update_queue(); }
void wd_transfers_queue_download(wi_string_t *path, wi_file_offset_t offset) { wd_user_t *user = wd_users_user_for_thread(); wi_string_t *realpath; wd_transfer_t *transfer; wi_fs_stat_t sb; realpath = wi_string_by_resolving_aliases_in_path(wd_files_real_path(path)); if(!wi_fs_stat_path(realpath, &sb)) { wi_log_err(WI_STR("Could not open %@: %m"), realpath); wd_reply_error(); return; } transfer = wi_autorelease(wd_transfer_init_download_with_user(wd_transfer_alloc(), user)); transfer->path = wi_retain(path); transfer->realpath = wi_retain(realpath); transfer->size = sb.size; transfer->offset = offset; transfer->transferred = offset; wi_lock_lock(wd_transfers_update_queue_lock); wi_array_wrlock(wd_transfers); wi_mutable_array_add_data(wd_transfers, transfer); wi_array_unlock(wd_transfers); wd_transfers_update_queue(); wi_lock_unlock(wd_transfers_update_queue_lock); }
void wt_cmd_hello(wi_array_t *arguments) { wt_client_t *client = wt_client(); if(client->state != WT_CLIENT_STATE_CONNECTED) return; if(wt_ip_is_banned(client->ip)) { wt_reply(511, WI_STR("Banned")); wi_log_err(WI_STR("Connection from %@ denied, host is banned"), client->ip); client->state = WT_CLIENT_STATE_DISCONNECTED; return; } wt_reply(200, WI_STR("%#@%c%#@%c%#@%c%#@%c%#@"), wt_server_version_string, WT_FIELD_SEPARATOR, wt_protocol_version_string, WT_FIELD_SEPARATOR, wt_settings.name, WT_FIELD_SEPARATOR, wt_settings.description, WT_FIELD_SEPARATOR, wi_date_iso8601_string(wt_start_date)); client->state = WT_CLIENT_STATE_SAID_HELLO; }
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 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 wt_control_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wt_client_t *client = argument; wi_string_t *string; wi_socket_state_t state; wi_uinteger_t i = 0; pool = wi_pool_init(wi_pool_alloc()); wt_client_set(client); while(client->state <= WT_CLIENT_STATE_SAID_HELLO) { do { state = wi_socket_wait(client->socket, 0.1); } while(state == WI_SOCKET_TIMEOUT && client->state <= WT_CLIENT_STATE_SAID_HELLO); if(client->state > WT_CLIENT_STATE_SAID_HELLO) { /* invalid state */ break; } if(state == WI_SOCKET_ERROR) { if(wi_error_code() == EINTR) { /* got a signal */ continue; } else { /* error in TCP communication */ wi_log_err(WI_STR("Could not read from %@: %m"), client->ip); break; } } string = wi_socket_read_to_string(client->socket, 0.0, WI_STR(WT_MESSAGE_SEPARATOR_STR)); if(!string || wi_string_length(string) == 0) { if(!string) wi_log_info(WI_STR("Could not read from %@: %m"), client->ip); break; } wt_parse_command(string); if(++i % 10 == 0) wi_pool_drain(pool); } wi_log_info(WI_STR("Disconnect from %@ after %.2fs"), client->ip, wi_time_interval() - client->connect_time); wi_release(pool); }
static wi_boolean_t wd_tracker_read(wd_tracker_t *tracker, uint32_t *message, wi_array_t **arguments) { wi_string_t *string; *message = 0; *arguments = NULL; string = wi_socket_read_to_string(tracker->socket, 30.0, WI_STR(WD_MESSAGE_SEPARATOR_STR)); if(string && wi_string_length(string) > 0) { wi_parse_wired_message(string, message, arguments); } else { if(!string) { wi_log_err(WI_STR("Could not read from tracker %@: %m"), tracker->host); } else { wi_log_err(WI_STR("Could not read from tracker %@: %s"), tracker->host, "Connection closed"); } } return (string != NULL); }
void wd_trackers_register(wi_boolean_t update) { if(wi_array_count(wd_trackers) > 0) { wi_release(wd_trackers_guest_account); wd_trackers_guest_account = wi_retain(wd_accounts_read_user_and_group(WI_STR("guest"))); wi_log_info(WI_STR("Registering with trackers...")); if(!wi_thread_create_thread(wd_trackers_register_thread, wi_number_with_bool(update))) wi_log_err(WI_STR("Could not create a register thread: %m")); } }
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; } }
void wr_client_init(void) { wi_integer_t options; wr_socket_context = wi_socket_context_init(wi_socket_context_alloc()); if(!wi_socket_context_set_ssl_type(wr_socket_context, WI_SOCKET_SSL_CLIENT)) wi_log_err(WI_STR("Could not set SSL context: %m")); if(!wi_socket_context_set_ssl_ciphers(wr_socket_context, WI_STR("ALL:NULL:!MD5:@STRENGTH"))) wi_log_err(WI_STR("Could not set SSL ciphers: %m")); options = WI_STRING_ENCODING_IGNORE | WI_STRING_ENCODING_TRANSLITERATE; wr_client_string_encoding = wi_string_encoding_init_with_charset(wi_string_encoding_alloc(), WI_STR("ISO-8859-1"), options); wr_server_string_encoding = wi_string_encoding_init_with_charset(wi_string_encoding_alloc(), WI_STR("UTF-8"), options); wr_icon = wi_string_init_with_cstring(wi_string_alloc(), wr_default_icon); }
static wi_boolean_t wd_transfer_open(wd_transfer_t *transfer) { if(transfer->type == WD_TRANSFER_DOWNLOAD) transfer->fd = open(wi_string_cstring(transfer->realpath), O_RDONLY, 0); else transfer->fd = open(wi_string_cstring(transfer->realpath), O_WRONLY | O_APPEND | O_CREAT, 0666); if(transfer->fd < 0) { wi_log_err(WI_STR("Could not open %@: %s"), transfer->realpath, strerror(errno)); return false; } return true; }
static void wt_cmd_categories(wi_array_t *arguments) { wi_file_t *file; wi_string_t *string; file = wi_file_for_reading(wt_settings.categories); if(!file) { wt_reply(500, WI_STR("Command Failed")); wi_log_err(WI_STR("Could not open %@: %m"), wt_settings.categories); return; } while((string = wi_file_read_config_line(file))) wt_reply(710, WI_STR("%@"), string); wt_reply(711, WI_STR("Done")); }
static wi_boolean_t wd_tracker_write(wd_tracker_t *tracker, wi_string_t *fmt, ...) { wi_string_t *string; wi_integer_t bytes; va_list ap; va_start(ap, fmt); string = wi_string_init_with_format_and_arguments(wi_string_alloc(), fmt, ap); va_end(ap); bytes = wi_socket_write_format(tracker->socket, 30.0, WI_STR("%@%c"), string, WD_MESSAGE_SEPARATOR); if(bytes <= 0) { wi_log_err(WI_STR("Could not write to tracker %@: %m"), tracker->host); } wi_release(string); return (bytes > 0); }
void wd_control_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wd_client_t *client = argument; wi_string_t *string; unsigned int i = 0; int state; pool = wi_pool_init(wi_pool_alloc()); wd_clients_add_client(client); wd_client_set(client); while(client->state <= WD_CLIENT_STATE_LOGGED_IN) { if(!pool) pool = wi_pool_init(wi_pool_alloc()); if(client->buffer_offset == 0) { do { state = wi_socket_wait(client->socket, 0.1); } while(state == 0 && client->state <= WD_CLIENT_STATE_LOGGED_IN); if(client->state > WD_CLIENT_STATE_LOGGED_IN) { /* invalid state */ break; } if(state < 0) { if(wi_error_code() == EINTR) { /* got a signal */ continue; } else { /* error in TCP communication */ wi_log_err(WI_STR("Could not read from %@: %m"), client->ip); break; } } } wd_client_lock_socket(client); string = wi_socket_read_to_string(client->socket, 0.0, WI_STR(WD_MESSAGE_SEPARATOR_STR)); wd_client_unlock_socket(client); if(!string || wi_string_length(string) == 0) { if(!string) wi_log_info(WI_STR("Could not read from %@: %m"), client->ip); break; } wd_parse_command(string); if(++i % 10 == 0) { wi_release(pool); pool = NULL; } } /* announce parting if client disconnected by itself */ if(client->state == WD_CLIENT_STATE_LOGGED_IN) { client->state = WD_CLIENT_STATE_DISCONNECTED; wd_broadcast_lock(); wd_client_broadcast_leave(client, WD_PUBLIC_CID); wd_broadcast_unlock(); } /* update status for clients logged in and above */ if(client->state >= WD_CLIENT_STATE_LOGGED_IN) { wi_lock_lock(wd_status_lock); wd_current_users--; wd_write_status(true); wi_lock_unlock(wd_status_lock); } wi_log_info(WI_STR("Disconnect from %@"), client->ip); wi_socket_close(client->socket); wd_clients_remove_client(client); wi_release(pool); }
void wd_server_apply_settings(void) { wi_data_t *data; wi_string_t *hostname; /* reload banner */ if(wd_settings.banner) { if(wd_settings.banner_changed) { data = wi_data_init_with_contents_of_file(wi_data_alloc(), wd_settings.banner); if(data) { wi_release(wd_banner); wd_banner = wi_retain(wi_data_base64(data)); } else { wi_log_err(WI_STR("Could not open %@: %m"), wd_settings.banner); } wi_release(data); } } else { wi_release(wd_banner); wd_banner = NULL; } /* reload server name/description */ if(wd_settings.name_changed || wd_settings.description_changed) wd_server_send_server_info(true); /* set SSL cipher list */ if(wd_settings.controlcipher) { if(!wi_socket_tls_set_ciphers(wd_control_socket_tls, wd_settings.controlcipher)) { wi_log_err(WI_STR("Could not set TLS cipher list \"%@\": %m"), wd_settings.controlcipher); } } if(wd_settings.transfercipher) { if(!wi_socket_tls_set_ciphers(wd_transfer_socket_tls, wd_settings.transfercipher)) { wi_log_err(WI_STR("Could not set TLS cipher list \"%@\": %m"), wd_settings.transfercipher); } } /* load SSL certificate */ if(!wd_certificate && !wd_private_key) { if(wd_settings.certificate) { wd_private_key = wi_rsa_init_with_pem_file(wi_rsa_alloc(), wd_settings.certificate); if(!wd_private_key) wi_log_warn(WI_STR("Could not find RSA key in %@, creating one..."), wd_settings.certificate); wd_certificate = wi_x509_init_with_pem_file(wi_x509_alloc(), wd_settings.certificate); if(!wd_certificate) wi_log_warn(WI_STR("Could not find certificate in %@, creating one..."), wd_settings.certificate); } if(!wd_private_key) { wd_private_key = wi_rsa_init_with_bits(wi_rsa_alloc(), 1024); if(wd_private_key) wi_log_info(WI_STR("Created 1024-bit RSA key")); else wi_log_err(WI_STR("Could not create RSA key: %m")); } if(!wd_certificate) { hostname = wi_process_hostname(wi_process()); wd_certificate = wi_x509_init_with_common_name(wi_x509_alloc(), wd_private_key, hostname); if(wd_certificate) wi_log_info(WI_STR("Created self-signed certificate for %@"), hostname); else wi_log_err(WI_STR("Could not create self-signed certificate: %m")); } if(!wi_socket_tls_set_private_key(wd_control_socket_tls, wd_private_key) || !wi_socket_tls_set_private_key(wd_transfer_socket_tls, wd_private_key)) { wi_log_err(WI_STR("Could not set TLS private key: %m")); } if(!wi_socket_tls_set_certificate(wd_control_socket_tls, wd_certificate) || !wi_socket_tls_set_certificate(wd_transfer_socket_tls, wd_certificate)) { wi_log_err(WI_STR("Could not set TLS certificate: %m")); } } }
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 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); }
static void wd_transfer_upload(wd_transfer_t *transfer) { wi_pool_t *pool; wi_string_t *path; wd_account_t *account; char buffer[WD_TRANSFER_BUFFER_SIZE]; wi_time_interval_t timeout, interval, speedinterval, statusinterval, accountinterval; wi_socket_state_t state; ssize_t result, speedbytes, statsbytes; int sd, bytes; pool = wi_pool_init(wi_pool_alloc()); /* start upload */ wi_log_info(WI_STR("Receiving \"%@\" from %@"), transfer->path, wd_user_identifier(transfer->user)); wi_socket_set_direction(transfer->socket, WI_SOCKET_READ); // if(!wi_socket_set_blocking(transfer->socket, false)) // wi_log_warn(WI_STR("Could not set non-blocking for %@: %m"), wd_user_ip(transfer->user)); sd = wi_socket_descriptor(transfer->socket); speedinterval = statusinterval = accountinterval = wi_time_interval(); speedbytes = statsbytes = 0; account = wd_user_account(transfer->user); /* update status */ wi_lock_lock(wd_status_lock); wd_current_uploads++; wd_total_uploads++; wd_write_status(true); wi_lock_unlock(wd_status_lock); while(wd_transfer_state(transfer) == WD_TRANSFER_RUNNING && transfer->transferred < transfer->size) { /* wait to read */ timeout = 0.0; do { state = wi_socket_wait_descriptor(sd, 0.1, true, false); if(state == WI_SOCKET_TIMEOUT) { timeout += 0.1; if(timeout >= 30.0) break; } } while(state == WI_SOCKET_TIMEOUT && wd_transfer_state(transfer) == WD_TRANSFER_RUNNING); if(state == WI_SOCKET_ERROR) { wi_log_err(WI_STR("Could not wait for upload from %@: %m"), wd_user_ip(transfer->user)); break; } if(timeout >= 30.0) { wi_log_err(WI_STR("Timed out waiting to read upload from %@"), wd_user_ip(transfer->user)); break; } /* read data */ bytes = wi_socket_read_buffer(transfer->socket, 30.0, buffer, sizeof(buffer)); if(bytes <= 0) { if(bytes < 0) { wi_log_err(WI_STR("Could not read upload from %@: %m"), wd_user_ip(transfer->user)); } break; } if((wi_file_offset_t) bytes > transfer->size - transfer->transferred) bytes = transfer->size - transfer->transferred; /* write data */ result = write(transfer->fd, buffer, bytes); if(result <= 0) { if(result < 0) { wi_log_err(WI_STR("Could not write upload to %@: %s"), transfer->realpath, strerror(errno)); } break; } /* update counters */ interval = wi_time_interval(); transfer->transferred += bytes; speedbytes += bytes; statsbytes += bytes; /* update speed */ transfer->speed = speedbytes / (interval - speedinterval); wd_transfer_limit_upload_speed(transfer, account, speedbytes, interval, speedinterval); if(interval - speedinterval > 30.0) { speedbytes = 0; speedinterval = interval; } /* update status */ if(interval - statusinterval > wd_current_uploads) { wi_lock_lock(wd_status_lock); wd_uploads_traffic += statsbytes; wd_write_status(false); wi_lock_unlock(wd_status_lock); statsbytes = 0; statusinterval = interval; } /* update account */ if(interval - accountinterval > 15.0) { account = wd_user_account(transfer->user); accountinterval = interval; } wi_pool_drain(pool); } wi_log_info(WI_STR("Received %@/%@ (%llu/%llu bytes) of \"%@\" from %@"), wd_files_string_for_bytes(transfer->transferred - transfer->offset), wd_files_string_for_bytes(transfer->size - transfer->offset), transfer->transferred - transfer->offset, transfer->size - transfer->offset, transfer->path, wd_user_identifier(transfer->user)); /* update status */ wd_transfer_set_state(transfer, WD_TRANSFER_STOPPED); wi_lock_lock(wd_status_lock); wd_current_uploads--; wd_uploads_traffic += statsbytes; wd_write_status(true); wi_lock_unlock(wd_status_lock); if(transfer->transferred == transfer->size) { path = wi_string_by_deleting_path_extension(transfer->realpath); if(wi_fs_rename_path(transfer->realpath, path)) { path = wi_string_by_appending_path_extension(transfer->path, WI_STR(WD_TRANSFERS_PARTIAL_EXTENSION)); wd_files_move_comment(path, transfer->path); } else { wi_log_warn(WI_STR("Could not move %@ to %@: %m"), transfer->realpath, path); } } wi_release(pool); }
wi_boolean_t wi_config_read_file(wi_config_t *config) { wi_enumerator_t *enumerator; wi_runtime_instance_t *instance; wi_file_t *file; wi_mutable_array_t *array; wi_mutable_dictionary_t *previous_values; wi_string_t *string, *name, *value; wi_config_type_t type; file = wi_file_for_reading(config->path); if(!file) { wi_log_err(WI_STR("Could not open %@: %m"), config->path); return false; } wi_log_info(WI_STR("Reading %@"), config->path); config->line = 0; wi_lock_lock(config->lock); previous_values = config->values; config->values = wi_dictionary_init(wi_mutable_dictionary_alloc()); if(config->defaults) { enumerator = wi_dictionary_key_enumerator(config->defaults); while((name = wi_enumerator_next_data(enumerator))) { // instance = wi_mutable_copy(wi_dictionary_data_for_key(config->defaults, name)); instance = wi_dictionary_data_for_key(config->defaults, name); if(wi_runtime_id(instance) == wi_array_runtime_id()) instance = wi_autorelease(wi_mutable_copy(instance)); wi_mutable_dictionary_set_data_for_key(config->values, instance, name); // wi_release(instance); } } while((string = wi_file_read_line(file))) { config->line++; if(wi_string_length(string) > 0 && !wi_string_has_prefix(string, WI_STR("#"))) { if(_wi_config_parse_string(config, string, &name, &value)) { instance = _wi_config_instance_for_setting(config, name, value, &type); if(instance) { wi_log_debug(WI_STR(" %@ = %@"), name, value); if(type == WI_CONFIG_STRINGLIST) { array = wi_dictionary_data_for_key(config->values, name); if(!array) { array = wi_mutable_array(); wi_mutable_dictionary_set_data_for_key(config->values, array, name); } wi_mutable_array_add_data(array, instance); } else { wi_mutable_dictionary_set_data_for_key(config->values, instance, name); } } else { _wi_config_log_error(config, name); } } else { wi_error_set_libwired_error(WI_ERROR_SETTINGS_SYNTAXERROR); _wi_config_log_error(config, string); } } } enumerator = wi_dictionary_key_enumerator(config->values); while((name = wi_enumerator_next_data(enumerator))) { instance = wi_dictionary_data_for_key(config->values, name); if(!previous_values || !wi_is_equal(instance, wi_dictionary_data_for_key(previous_values, name))) wi_mutable_set_add_data(config->changes, name); } wi_release(previous_values); wi_lock_unlock(config->lock); return true; }
wi_boolean_t wi_config_write_file(wi_config_t *config) { wi_enumerator_t *enumerator; wi_file_t *file, *tmpfile; wi_string_t *string, *name, *value; wi_mutable_set_t *keys; wi_boolean_t write; file = wi_file_for_updating(config->path); if(!file) { wi_log_err(WI_STR("Could not open %@: %m"), config->path); return false; } tmpfile = wi_file_temporary_file(); wi_lock_lock(config->lock); keys = wi_autorelease(wi_mutable_copy(config->changes)); while((string = wi_file_read_line(file))) { if(wi_string_length(string) == 0) { wi_file_write_format(tmpfile, WI_STR("\n")); } else if(wi_string_has_prefix(string, WI_STR("#"))) { write = true; string = wi_string_substring_from_index(string, 1); if(_wi_config_parse_string(config, string, &name, &value)) { if(wi_set_contains_data(keys, name)) { if(_wi_config_write_setting_to_file(config, name, tmpfile)) { write = false; wi_mutable_set_remove_data(keys, name); } } } if(write) wi_file_write_format(tmpfile, WI_STR("#%@\n"), string); } else { write = true; if(_wi_config_parse_string(config, string, &name, &value)) { if(wi_set_contains_data(keys, name)) { if(_wi_config_write_setting_to_file(config, name, tmpfile)) { write = false; wi_mutable_set_remove_data(keys, name); } } } if(write) wi_file_write_format(tmpfile, WI_STR("%@\n"), string); } } enumerator = wi_set_data_enumerator(keys); while((name = wi_enumerator_next_data(enumerator))) _wi_config_write_setting_to_file(config, name, tmpfile); wi_mutable_set_remove_all_data(config->changes); wi_lock_unlock(config->lock); wi_file_truncate(file, 0); wi_file_seek(tmpfile, 0); while((string = wi_file_read_line(tmpfile))) wi_file_write_format(file, WI_STR("%@\n"), string); 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 }
void wt_read_servers(void) { FILE *fp; wt_server_packed_t server_packed; wt_server_t *server; char magic[5]; wi_time_interval_t interval, update; unsigned int version, count = 0; wi_lock_lock(wt_servers_lock); fp = fopen(wi_string_cstring(wt_settings.servers), "r"); if(!fp) { if(errno != ENOENT) { wi_log_err(WI_STR("Could not open %@: %s"), wt_settings.servers, strerror(errno)); } goto end; } if(fread(&magic, 4, 1, fp) != 1 || strncmp(magic, WT_SERVER_MAGIC, 4) != 0) { wi_log_warn(WI_STR("Could not read %@: %s"), wt_settings.servers, "Not a server file"); goto end; } if(fread(&version, 4, 1, fp) != 1 || version != WT_SERVER_VERSION) { wi_log_warn(WI_STR("Could not read %@: %s"), wt_settings.servers, "Wrong version"); goto end; } wi_log_info(WI_STR("Reading %@"), wt_settings.servers); interval = wi_time_interval(); wi_list_wrlock(wt_servers); while((fread(&server_packed, sizeof(wt_server_packed_t), 1, fp)) > 0) { update = server_packed.update_time > 0 ? server_packed.update_time : server_packed.register_time; if(interval - update < wt_settings.minupdatetime) { server = wt_server_init_with_packed(wt_server_alloc(), server_packed); wi_lock_lock(wt_status_lock); wt_current_servers++; wt_current_users += server->users; wt_current_files += server->files; wt_current_size += server->size; wi_lock_unlock(wt_status_lock); wi_list_append_data(wt_servers, server); wi_release(server); count++; } } wi_list_unlock(wt_servers); if(count > 0) { wi_lock_lock(wt_status_lock); wt_write_status(true); wi_lock_unlock(wt_status_lock); wi_log_info(WI_STR("Loaded %u %s from %@"), count, count == 1 ? "server" : "servers", wt_settings.servers); } end: wi_lock_unlock(wt_servers_lock); }