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_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); }
void wt_write_servers(void) { static char magic[] = WT_SERVER_MAGIC; static uint32_t version = WT_SERVER_VERSION; FILE *fp; wi_list_node_t *node; wt_server_t *server; wt_server_packed_t server_packed; wi_lock_lock(wt_servers_lock); fp = fopen(wi_string_cstring(wt_settings.servers), "w"); if(!fp) { wi_log_warn(WI_STR("Could not open %@: %s"), wt_settings.servers, strerror(errno)); goto end; } fwrite(magic, 4, 1, fp); fwrite(&version, 4, 1, fp); wi_list_rdlock(wt_servers); WI_LIST_FOREACH(wt_servers, node, server) { server_packed = wt_server_packed(server); fwrite(&server_packed, sizeof(wt_server_packed_t), 1, fp); }
wi_runtime_instance_t * wi_autorelease(wi_runtime_instance_t *instance) { wi_pool_t *pool; _wi_pool_array_t *array, *new_array; if(!instance) return NULL; pool = _wi_pool_pool(); if(!pool) { wi_log_warn(WI_STR("Instance %@ autoreleased with no pool in place - just leaking"), instance); return instance; } array = pool->array; if(array->length >= _WI_POOL_ARRAY_SIZE) { new_array = wi_malloc(sizeof(_wi_pool_array_t)); new_array->next = array; array = new_array; pool->array = array; } array->instances[array->length] = instance; array->length++; return instance; }
static void _wi_pool_remove_pool(wi_pool_t *pool) { _wi_pool_stack_t *stack; wi_pool_t *p; uint32_t break_index, stack_index; int32_t i; stack = _wi_pool_poolstack(&stack_index); if(!stack) { wi_log_warn(WI_STR("Orphaned pool in thread %@"), wi_thread_current_thread()); return; } break_index = 0; for(i = stack->length - 1; i >= 0; --i) { p = stack->pools[i]; if(p == pool) { stack->length = i; break_index = i; break; } wi_release(p); } if(break_index == 0) _wi_pool_remove_poolstack(stack, stack_index); }
static void wi_test_fsevents_thread(wi_runtime_instance_t *instance) { wi_pool_t *pool; pool = wi_pool_init(wi_pool_alloc()); if(!wi_fsevents_run_with_timeout(wi_test_fsevents_fsevents, 1.0)) wi_log_warn(WI_STR("wi_fsevents_run_with_timeout: %m")); wi_condition_lock_lock(wi_test_fsevents_lock); wi_condition_lock_unlock_with_condition(wi_test_fsevents_lock, 1); wi_release(pool); }
static void wi_assert_default_handler(const char *file, unsigned int line, wi_string_t *fmt, ...) { wi_string_t *string; va_list ap; va_start(ap, fmt); string = wi_string_init_with_format_and_arguments(wi_string_alloc(), fmt, ap); va_end(ap); wi_log_warn(WI_STR("Assertion failed at %s:%u: %@"), file, line, string); wi_release(string); wi_crash(); }
static void _wi_tests_assert_handler(const char *file, unsigned int line, wi_string_t *fmt, ...) { wi_string_t *string; va_list ap; va_start(ap, fmt); string = wi_string_init_with_format_and_arguments(wi_string_alloc(), fmt, ap); va_end(ap); wi_log_warn(WI_STR("%@:%u: %@"), wi_string_last_path_component(wi_string_with_cstring(file)), line, string); wi_release(string); _wi_tests_current_test->passed = false; longjmp(_wi_tests_jmp_buf, 1); }
static void wd_server_register_dnssd(void) { DNSServiceRef service; DNSServiceErrorType err; err = DNSServiceRegister(&service, 0, kDNSServiceInterfaceIndexAny, wi_string_cstring(wd_settings.name), WD_DNSSD_NAME, NULL, NULL, htons(wd_settings.port), 0, NULL, wd_server_register_dnssd_reply, NULL); if(err != kDNSServiceErr_NoError) wi_log_warn(WI_STR("Could not register for DNS service discovery: %d"), err); }
static void wt_update_servers(wi_timer_t *timer) { wi_enumerator_t *enumerator; wt_server_t *server; void *key; wi_time_interval_t interval, update; wi_boolean_t changed = false; wi_dictionary_wrlock(wt_servers); if(wi_dictionary_count(wt_servers) > 0) { interval = wi_time_interval(); enumerator = wi_array_data_enumerator(wi_dictionary_all_keys(wt_servers)); while((key = wi_enumerator_next_data(enumerator))) { server = wi_dictionary_data_for_key(wt_servers, key); update = server->update_time > 0.0 ? server->update_time : server->register_time; if(interval - update > wt_settings.minupdatetime) { wi_log_warn(WI_STR("Deleting \"%@\" with URL %@: Last update %.0f seconds ago considered too slow"), server->name, server->url, interval - update); wt_servers_remove_stats_for_server(server); wi_dictionary_remove_data_for_key(wt_servers, key); changed = true; } } } wi_dictionary_unlock(wt_servers); if(changed) { wi_lock_lock(wt_status_lock); wt_write_status(true); wi_lock_unlock(wt_status_lock); wt_servers_write_file(); } }
void wt_servers_write_file(void) { static char magic[] = WT_SERVER_MAGIC; static uint32_t version = WT_SERVER_VERSION; FILE *fp; wi_enumerator_t *enumerator; wt_server_t *server; wt_server_packed_t server_packed; wi_lock_lock(wt_servers_lock); fp = fopen(wi_string_cstring(wt_settings.servers), "w"); if(!fp) { wi_log_warn(WI_STR("Could not open %@: %s"), wt_settings.servers, strerror(errno)); goto end; } fwrite(magic, 4, 1, fp); fwrite(&version, 4, 1, fp); wi_dictionary_rdlock(wt_servers); enumerator = wi_dictionary_data_enumerator(wt_servers); while((server = wi_enumerator_next_data(enumerator))) { server_packed = wt_server_packed(server); fwrite(&server_packed, sizeof(wt_server_packed_t), 1, fp); } wi_dictionary_unlock(wt_servers); fclose(fp); end: wi_lock_unlock(wt_servers_lock); }
static void wt_update_servers(wi_timer_t *timer) { wi_list_node_t *node, *next_node; wt_server_t *server; wi_time_interval_t interval, update; unsigned int count = 0; if(wi_list_count(wt_servers) > 0) { interval = wi_time_interval(); wi_list_rdlock(wt_servers); for(node = wi_list_first_node(wt_servers); node; node = next_node) { next_node = wi_list_node_next_node(node); server = wi_list_node_data(node); update = server->update_time > 0.0 ? server->update_time : server->register_time; if(interval - update > wt_settings.minupdatetime) { wi_log_warn(WI_STR("Deleting \"%@\" with URL %@: Last update %.0f seconds ago considered too slow"), server->name, server->url, interval - update); wt_server_stats_remove(server); wi_list_remove_node(wt_servers, node); 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); wt_write_servers(); } } }
static void _wi_settings_log_error(wi_settings_t *settings, wi_string_t *name) { wi_log_warn(WI_STR("Could not interpret the setting \"%@\" at %@ line %d: %m"), name, settings->file, settings->line); }
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); }
static wi_boolean_t wd_transfers_run_upload(wd_transfer_t *transfer, wd_user_t *user, wi_p7_message_t *message) { wi_p7_message_t *reply; wi_string_t *path; wi_p7_uint32_t transaction; wi_boolean_t result; reply = wi_p7_message_with_name(WI_STR("wired.transfer.upload_ready"), wd_p7_spec); wi_p7_message_set_string_for_name(reply, transfer->path, WI_STR("wired.file.path")); wi_p7_message_set_oobdata_for_name(reply, transfer->dataoffset, WI_STR("wired.transfer.data_offset")); wi_p7_message_set_oobdata_for_name(reply, transfer->rsrcoffset, WI_STR("wired.transfer.rsrc_offset")); if(wi_p7_message_get_uint32_for_name(message, &transaction, WI_STR("wired.transaction"))) wi_p7_message_set_uint32_for_name(reply, transaction, WI_STR("wired.transaction")); if(!wd_user_write_message(user, 30.0, reply)) { wi_log_error(WI_STR("Could not write message \"%@\" to %@: %m"), wi_p7_message_name(reply), wd_user_identifier(user)); return false; } reply = wd_user_read_message(user, 30.0); if(!reply) { wi_log_warn(WI_STR("Could not read message from %@ while waiting for upload: %m"), wd_user_identifier(user)); return false; } if(!wi_p7_spec_verify_message(wd_p7_spec, reply)) { wi_log_error(WI_STR("Could not verify message from %@ while waiting for upload: %m"), wd_user_identifier(user)); wd_user_reply_error(user, WI_STR("wired.error.invalid_message"), reply); return false; } if(!wi_is_equal(wi_p7_message_name(reply), WI_STR("wired.transfer.upload"))) { wi_log_error(WI_STR("Could not accept message %@ from %@: Expected \"wired.transfer.upload\""), wi_p7_message_name(reply), wd_user_identifier(user)); wd_user_reply_error(user, WI_STR("wired.error.invalid_message"), reply); return false; } wi_p7_message_get_uint64_for_name(reply, &transfer->remainingdatasize, WI_STR("wired.transfer.data")); wi_p7_message_get_uint64_for_name(reply, &transfer->remainingrsrcsize, WI_STR("wired.transfer.rsrc")); transfer->finderinfo = wi_retain(wi_p7_message_data_for_name(reply, WI_STR("wired.transfer.finderinfo"))); wi_socket_set_interactive(wd_user_socket(user), false); result = wd_transfer_upload(transfer); wi_socket_set_interactive(wd_user_socket(user), true); if(transfer->transferred == transfer->datasize + transfer->rsrcsize) { path = wi_string_by_deleting_path_extension(transfer->realdatapath); if(wi_fs_rename_path(transfer->realdatapath, path)) { if(transfer->executable) { if(!wi_fs_set_mode_for_path(path, 0755)) wi_log_error(WI_STR("Could not set mode for \"%@\": %m"), path); } wd_files_move_comment(transfer->realdatapath, path, NULL, NULL); wd_files_move_label(transfer->realdatapath, path, NULL, NULL); if(wi_data_length(transfer->finderinfo) > 0) wi_fs_set_finder_info_for_path(transfer->finderinfo, path); wd_index_add_file(path); } else { wi_log_error(WI_STR("Could not move \"%@\" to \"%@\": %m"), transfer->realdatapath, path); } wd_accounts_add_upload_statistics(wd_user_account(user), true, transfer->actualtransferred); } else { wd_accounts_add_upload_statistics(wd_user_account(user), false, transfer->actualtransferred); } return result; }
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); }
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 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); }
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 void _wi_config_log_error(wi_config_t *config, wi_string_t *name) { wi_log_warn(WI_STR("Could not interpret the setting \"%@\" at %@ line %lu: %m"), name, config->path, config->line); }
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); }