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_cmd_pass(wi_array_t *arguments) { wd_client_t *client = wd_client(); wi_string_t *password; wd_chat_t *chat; if(client->state != WD_CLIENT_STATE_GAVE_USER) return; client->account = wi_retain(wd_accounts_read_user_and_group(client->login)); if(!client->account) { wd_reply(510, WI_STR("Login Failed")); wi_log_info(WI_STR("Login from %@/%@/%@ failed: %@"), client->nick, client->login, client->ip, WI_STR("No such account")); return; } password = WI_ARRAY(arguments, 0); if(!wi_is_equal(client->account->password, password)) { wd_reply(510, WI_STR("Login Failed")); wi_log_info(WI_STR("Login from %@/%@/%@ failed: %@"), client->nick, client->login, client->ip, WI_STR("Wrong password")); return; } wi_log_info(WI_STR("Login from %@/%@/%@ succeeded"), client->nick, client->login, client->ip); wi_lock_lock(client->flag_lock); client->admin = (client->account->kick_users || client->account->ban_users); client->state = WD_CLIENT_STATE_LOGGED_IN; wi_lock_unlock(client->flag_lock); wi_lock_lock(wd_status_lock); wd_current_users++; wd_total_users++; wd_write_status(true); wi_lock_unlock(wd_status_lock); wd_reply(201, WI_STR("%u"), client->uid); chat = wd_chat_with_cid(WD_PUBLIC_CID); wd_chat_add_client(chat, client); }
static void wd_transfers_add_or_remove_transfer(wd_transfer_t *transfer, wi_boolean_t add) { wi_mutable_dictionary_t *dictionary; wi_integer_t number; wi_lock_lock(wd_transfers_status_lock); if(transfer->type == WD_TRANSFER_DOWNLOAD) wd_transfers_active_downloads += add ? 1 : -1; else wd_transfers_active_uploads += add ? 1 : -1; wi_lock_unlock(wd_transfers_status_lock); if(transfer->type == WD_TRANSFER_DOWNLOAD) dictionary = wd_transfers_user_downloads; else dictionary = wd_transfers_user_uploads; wi_dictionary_wrlock(dictionary); number = (wi_integer_t) wi_dictionary_data_for_key(dictionary, transfer->key); if(add) { wi_mutable_dictionary_set_data_for_key(dictionary, (void *) (number + 1), transfer->key); } else { if(number > 0) { wi_mutable_dictionary_set_data_for_key(dictionary, (void *) (number - 1), transfer->key); } else { wi_mutable_dictionary_remove_data_for_key(dictionary, transfer->key); } } wi_dictionary_unlock(dictionary); }
static void _wi_pool_add_poolstack(_wi_pool_stack_t *stack) { uint32_t index, capacity, length; index = wi_hash_pointer(stack->thread) % _WI_POOL_STACKS_BUCKETS; wi_lock_lock(_wi_pool_stacks_lock); capacity = _wi_pool_stacks_capacities[index]; length = _wi_pool_stacks_lengths[index]; if(length >= capacity) { capacity += capacity; if(capacity < _WI_POOL_STACKS_INITIAL_SIZE) capacity = _WI_POOL_STACKS_INITIAL_SIZE; _wi_pool_stacks[index] = wi_realloc(_wi_pool_stacks[index], capacity * sizeof(_wi_pool_stack_t)); _wi_pool_stacks_capacities[index] = capacity; } _wi_pool_stacks[index][length] = stack; _wi_pool_stacks_lengths[index] = ++length; wi_lock_unlock(_wi_pool_stacks_lock); }
static void wd_transfers_note_statistics(wd_transfer_type_t type, wd_transfers_statistics_type_t statistics, wi_file_offset_t bytes) { wi_lock_lock(wd_status_lock); if(type == WD_TRANSFER_DOWNLOAD) { if(statistics == WD_TRANSFER_STATISTICS_ADD) { wd_current_downloads++; wd_total_downloads++; } else if(statistics == WD_TRANSFER_STATISTICS_REMOVE) { wd_current_downloads--; } wd_downloads_traffic += bytes; } else { if(statistics == WD_TRANSFER_STATISTICS_ADD) { wd_current_uploads++; wd_total_uploads++; } else if(statistics == WD_TRANSFER_STATISTICS_REMOVE) { wd_current_uploads--; } wd_uploads_traffic += bytes; } wd_write_status((statistics != WD_TRANSFER_STATISTICS_DATA)); wi_lock_unlock(wd_status_lock); }
void wd_transfer_loop(wd_transfer_t *transfer) { if(transfer->timer) wd_transfer_remove_timer(transfer); wi_condition_lock_lock(transfer->state_lock); if(transfer->state == WD_TRANSFER_WAITING) { transfer->state = WD_TRANSFER_RUNNING; wi_condition_lock_unlock_with_condition(transfer->state_lock, transfer->state); if(transfer->type == WD_TRANSFER_DOWNLOAD) wd_transfer_download(transfer); else wd_transfer_upload(transfer); } else { wi_condition_lock_unlock(transfer->state_lock); } wi_lock_lock(wd_transfers_update_queue_lock); wi_array_wrlock(wd_transfers); wi_mutable_array_remove_data(wd_transfers, transfer); wi_array_unlock(wd_transfers); wd_transfers_update_queue(); wi_lock_unlock(wd_transfers_update_queue_lock); }
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); }
static void _wi_pool_remove_poolstack(_wi_pool_stack_t *stack, uint32_t stack_index) { _wi_pool_stack_t **stacks; uint32_t index, length; index = wi_hash_pointer(wi_thread_current_thread()) % _WI_POOL_STACKS_BUCKETS; wi_lock_lock(_wi_pool_stacks_lock); length = _wi_pool_stacks_lengths[index] - 1; stacks = _wi_pool_stacks[index]; stacks[stack_index] = NULL; _wi_pool_stacks_lengths[index] = length; if(stack_index < length) { memmove(&stacks[stack_index], &stacks[stack_index + 1], sizeof(_wi_pool_stack_t **) * length); } if(stack->pools) wi_free(stack->pools); wi_free(stack); wi_lock_unlock(_wi_pool_stacks_lock); }
void wt_server_stats_remove(wt_server_t *server) { 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); }
void wt_server_stats_add(wt_server_t *server) { 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); }
static void _wi_log_vlog(int priority, wi_string_t *fmt, va_list ap) { wi_string_t *string; FILE *fp; const char *cstring, *name, *path; char date[_WI_LOG_DATE_SIZE]; string = wi_string_init_with_format_and_arguments(wi_string_alloc(), fmt, ap); cstring = wi_string_cstring(string); wi_lock_lock(_wi_log_lock); name = wi_string_cstring(wi_process_name(wi_process())); _wi_log_date(date); if(wi_log_stdout || wi_log_stderr) fprintf(wi_log_stdout ? stdout : stderr, "%s %s[%d]: %s\n", date, name, getpid(), cstring); else if(wi_log_startup && priority < LOG_INFO) fprintf(stderr, "%s: %s\n", name, cstring); else if(wi_log_tool) fprintf((priority < LOG_INFO) ? stderr : stdout, "%s: %s\n", name, cstring); if(wi_log_syslog) syslog(priority, "%s", cstring); if(wi_log_file && wi_log_path) { path = wi_string_cstring(wi_full_path(wi_log_path)); fp = fopen(path, "a"); if(fp) { fprintf(fp, "%s %s[%d]: %s\n", date, name, getpid(), cstring); fclose(fp); if(_wi_log_lines > 0 && wi_log_limit > 0) { if(_wi_log_lines % (int) ((float) wi_log_limit / 10.0f) == 0) { _wi_log_truncate(path); _wi_log_lines = wi_log_limit; } } _wi_log_lines++; } else { fprintf(stderr, "%s: %s: %s\n", name, path, strerror(errno)); } } if(wi_log_callback) (*wi_log_callback)(string); if(wi_log_startup && priority == LOG_ERR) exit(1); wi_lock_unlock(_wi_log_lock); wi_release(string); }
wi_time_interval_t wi_config_time_interval_for_name(wi_config_t *config, wi_string_t *name) { wi_number_t *value; wi_lock_lock(config->lock); value = wi_autorelease(wi_retain(wi_dictionary_data_for_key(config->values, name))); wi_lock_unlock(config->lock); return value ? wi_number_double(value) : 0.0; }
wi_regexp_t * wi_config_regexp_for_name(wi_config_t *config, wi_string_t *name) { wi_regexp_t *value; wi_lock_lock(config->lock); value = wi_autorelease(wi_retain(wi_dictionary_data_for_key(config->values, name))); wi_lock_unlock(config->lock); return value; }
wi_uinteger_t wi_config_port_for_name(wi_config_t *config, wi_string_t *name) { wi_number_t *value; wi_lock_lock(config->lock); value = wi_autorelease(wi_retain(wi_dictionary_data_for_key(config->values, name))); wi_lock_unlock(config->lock); return value ? wi_number_integer(value) : 0; }
static void wt_cmd_servers(wi_array_t *arguments) { /* reply all servers */ wt_servers_reply_server_list(); /* update status */ wi_lock_lock(wt_status_lock); wt_total_clients++; wt_write_status(true); wi_lock_unlock(wt_status_lock); }
static void _wi_socket_ssl_locking_function(int mode, int n, const char *file, int line) { wi_lock_t *lock; lock = WI_ARRAY(_wi_socket_ssl_locks, n); if(mode & CRYPTO_LOCK) wi_lock_lock(lock); else wi_lock_unlock(lock); }
static wd_uid_t wd_user_next_id(void) { wd_uid_t id; wi_lock_lock(wd_users_id_lock); id = ++wd_users_current_id; wi_lock_unlock(wd_users_id_lock); return id; }
wt_server_t * wt_server_init(wt_server_t *server) { wi_list_wrlock(wt_servers); wi_list_append_data(wt_servers, server); wi_list_unlock(wt_servers); wi_lock_lock(wt_status_lock); wt_current_servers++; wt_write_status(true); wi_lock_unlock(wt_status_lock); return server; }
void wd_transfers_queue_upload(wi_string_t *path, wi_file_offset_t size, wi_string_t *checksum) { wd_user_t *user = wd_users_user_for_thread(); wi_string_t *realpath, *filechecksum; wd_transfer_t *transfer; wi_file_offset_t offset; 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)) { wd_reply(521, WI_STR("File or Directory Exists")); return; } if(!wi_string_has_suffix(realpath, WI_STR(WD_TRANSFERS_PARTIAL_EXTENSION))) realpath = wi_string_by_appending_path_extension(realpath, WI_STR(WD_TRANSFERS_PARTIAL_EXTENSION)); if(!wi_fs_stat_path(realpath, &sb)) { offset = 0; } else { offset = sb.size; if(sb.size >= WD_FILES_CHECKSUM_SIZE) { filechecksum = wi_fs_sha1_for_path(realpath, WD_FILES_CHECKSUM_SIZE); if(!wi_is_equal(filechecksum, checksum)) { wd_reply(522, WI_STR("Checksum Mismatch")); return; } } } transfer = wi_autorelease(wd_transfer_init_upload_with_user(wd_transfer_alloc(), user)); transfer->path = wi_retain(path); transfer->realpath = wi_retain(realpath); transfer->size = 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 wi_config_set_instance_for_name(wi_config_t *config, wi_runtime_instance_t *instance, wi_string_t *name) { wi_runtime_instance_t *copy; wi_lock_lock(config->lock); if(!wi_is_equal(instance, wi_dictionary_data_for_key(config->values, name))) wi_mutable_set_add_data(config->changes, name); copy = wi_copy(instance); wi_mutable_dictionary_set_data_for_key(config->values, copy, name); wi_release(copy); wi_lock_unlock(config->lock); }
wi_array_t * wi_dictionary_keys_sorted_by_value(wi_dictionary_t *dictionary, wi_compare_func_t *compare) { wi_mutable_array_t *array, *buckets; _wi_dictionary_bucket_t *bucket; wi_array_callbacks_t callbacks; void **data; wi_uinteger_t i; if(dictionary->key_count == 0) return wi_autorelease(wi_array_init(wi_array_alloc())); callbacks.retain = NULL; callbacks.release = NULL; callbacks.is_equal = NULL; callbacks.description = NULL; buckets = wi_array_init_with_capacity_and_callbacks(wi_mutable_array_alloc(), dictionary->key_count, callbacks); for(i = 0; i < dictionary->buckets_count; i++) { for(bucket = dictionary->buckets[i]; bucket; bucket = bucket->next) wi_mutable_array_add_data(buckets, bucket); } data = wi_malloc(sizeof(void *) * dictionary->key_count); wi_array_get_data(buckets, data); #ifdef _WI_DICTIONARY_USE_QSORT_R qsort_r(data, dictionary->key_count, sizeof(void *), compare, _wi_dictionary_compare_buckets); #else wi_lock_lock(_wi_dictionary_sort_lock); _wi_dictionary_sort_function = compare; qsort(data, dictionary->key_count, sizeof(void *), _wi_dictionary_compare_buckets); wi_lock_unlock(_wi_dictionary_sort_lock); #endif callbacks.retain = dictionary->key_callbacks.retain; callbacks.release = dictionary->key_callbacks.release; callbacks.is_equal = dictionary->key_callbacks.is_equal; callbacks.description = dictionary->key_callbacks.description; array = wi_array_init_with_capacity_and_callbacks(wi_mutable_array_alloc(), dictionary->key_count, callbacks); for(i = 0; i < dictionary->key_count; i++) wi_mutable_array_add_data(array, ((_wi_dictionary_bucket_t *) data[i])->key); wi_free(data); wi_release(buckets); wi_runtime_make_immutable(array); return wi_autorelease(array); }
static wd_uid_t wd_user_next_uid(void) { wd_uid_t uid; wi_lock_lock(wd_users_uid_lock); wi_dictionary_rdlock(wd_users); if(wi_dictionary_count(wd_users) == 0) wd_users_current_uid = 0; uid = ++wd_users_current_uid; wi_dictionary_unlock(wd_users); wi_lock_unlock(wd_users_uid_lock); return uid; }
wi_string_t * _wi_string_constant_string(const char *cstring) { wi_string_t *string; wi_lock_lock(_wi_string_constant_string_lock); string = wi_dictionary_data_for_key(_wi_string_constant_string_table, (void *) cstring); if(!string) { string = wi_string_init_with_cstring(wi_string_alloc(), cstring); wi_mutable_dictionary_set_data_for_key(_wi_string_constant_string_table, string, (void *) cstring); wi_release(string); } wi_lock_unlock(_wi_string_constant_string_lock); return string; }
void wd_transfers_remove_user(wd_user_t *user) { wd_transfer_t *transfer; wi_boolean_t update = false; wi_uinteger_t i, count; wd_transfer_state_t state; wi_lock_lock(wd_transfers_update_queue_lock); wi_array_wrlock(wd_transfers); count = wi_array_count(wd_transfers); for(i = 0; i < count; i++) { transfer = WI_ARRAY(wd_transfers, i); if(transfer->user == user) { state = wd_transfer_state(transfer); if(state == WD_TRANSFER_RUNNING) { wi_array_unlock(wd_transfers); wd_transfer_set_state(transfer, WD_TRANSFER_STOP); wi_condition_lock_lock_when_condition(transfer->state_lock, WD_TRANSFER_STOPPED, 1.0); wi_condition_lock_unlock(transfer->state_lock); wi_array_wrlock(wd_transfers); } else if(state == WD_TRANSFER_QUEUED || state == WD_TRANSFER_WAITING) { if(transfer->timer) wd_transfer_remove_timer(transfer); wi_mutable_array_remove_data_at_index(wd_transfers, i); count--; i--; update = true; } } } wi_array_unlock(wd_transfers); if(update) wd_transfers_update_queue(); wi_lock_unlock(wd_transfers_update_queue_lock); }
static void wd_transfer_expire_timer(wi_timer_t *timer) { wd_transfer_t *transfer; transfer = wi_timer_data(timer); wi_lock_lock(wd_transfers_update_queue_lock); wi_array_wrlock(wd_transfers); wi_mutable_array_remove_data(wd_transfers, transfer); wi_array_unlock(wd_transfers); wd_transfers_update_queue(); wi_lock_unlock(wd_transfers_update_queue_lock); wi_release(transfer); }
static void wd_cmd_ban(wi_array_t *arguments) { wd_client_t *client = wd_client(); wd_client_t *peer; wd_uid_t uid; if(!client->account->ban_users) { wd_reply(516, WI_STR("Permission Denied")); return; } uid = wi_string_uint32(WI_ARRAY(arguments, 0)); peer = wd_client_with_uid(uid); if(!peer) { wd_reply(512, WI_STR("Client Not Found")); return; } if(peer->account->cannot_be_kicked) { wd_reply(515, WI_STR("Cannot Be Disconnected")); return; } wd_broadcast_lock(); wd_broadcast(WD_PUBLIC_CID, 307, WI_STR("%u%c%u%c%#@"), peer->uid, WD_FIELD_SEPARATOR, client->uid, WD_FIELD_SEPARATOR, WI_ARRAY(arguments, 1)); wd_broadcast_unlock(); wi_log_ll(WI_STR("%@/%@/%@ banned %@/%@/%@"), client->nick, client->login, client->ip, peer->nick, peer->login, peer->ip); wd_tempban(peer->ip); wi_lock_lock(peer->flag_lock); peer->state = WD_CLIENT_STATE_DISCONNECTED; wi_lock_unlock(peer->flag_lock); }
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(); } } }
void wi_array_sort(wi_array_t *array, wi_compare_func_t *compare) { void **data; wi_uinteger_t i; if(array->data_count == 0) return; data = wi_malloc(sizeof(void *) * array->data_count); wi_array_get_data(array, data); #ifdef HAVE_QSORT_R qsort_r(data, array->data_count, sizeof(void *), compare, _wi_array_compare_data); #else wi_lock_lock(_wi_array_sort_lock); _wi_array_sort_function = compare; qsort(data, array->data_count, sizeof(void *), _wi_array_compare_data); wi_lock_unlock(_wi_array_sort_lock); #endif for(i = 0; i < array->data_count; i++) array->items[i]->data = data[i]; wi_free(data); }