void wd_broadcast(wd_chat_t *chat, uint32_t n, wi_string_t *fmt, ...) { wi_enumerator_t *enumerator; wi_string_t *string; wi_array_t *users; wd_user_t *user; va_list ap; va_start(ap, fmt); string = wi_string_init_with_format_and_arguments(wi_string_alloc(), fmt, ap); va_end(ap); users = wd_chat_users(chat); wi_array_rdlock(users); enumerator = wi_array_data_enumerator(users); while((user = wi_enumerator_next_data(enumerator))) { if(wd_user_state(user) == WD_USER_LOGGED_IN) { wd_user_lock_socket(user); wi_socket_write_format(wd_user_socket(user), 0.0, WI_STR("%u %@%c"), n, string, WD_MESSAGE_SEPARATOR); wd_user_unlock_socket(user); } } wi_array_unlock(users); wi_release(string); }
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 wd_trackers_register_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wi_enumerator_t *enumerator; wi_number_t *number = argument; wd_tracker_t *tracker; wi_boolean_t update; pool = wi_pool_init(wi_pool_alloc()); update = wi_number_bool(number); wi_array_rdlock(wd_trackers); enumerator = wi_array_data_enumerator(wd_trackers); while((tracker = wi_enumerator_next_data(enumerator))) { wd_tracker_register(tracker); if(update && tracker->active) wd_tracker_update(tracker); } wi_array_unlock(wd_trackers); if(update) wi_timer_reschedule(wd_trackers_update_timer, WD_TRACKERS_UPDATE_INTERVAL); wi_release(pool); }
static void _wi_timer_invalidate(wi_timer_t *timer) { wi_array_wrlock(_wi_timers); wi_mutable_array_remove_data(_wi_timers, timer); wi_array_unlock(_wi_timers); timer->scheduled = false; }
void wd_chat_reply_user_list(wd_chat_t *chat) { wi_enumerator_t *enumerator; wd_user_t *user; wi_array_rdlock(chat->users); enumerator = wi_array_data_enumerator(chat->users); while((user = wi_enumerator_next_data(enumerator))) { if(wd_user_state(user) == WD_USER_LOGGED_IN) { wd_reply(310, WI_STR("%u%c%u%c%u%c%u%c%u%c%#@%c%#@%c%#@%c%#@%c%#@%c%#@"), chat->cid, WD_FIELD_SEPARATOR, wd_user_uid(user), WD_FIELD_SEPARATOR, wd_user_is_idle(user), WD_FIELD_SEPARATOR, wd_user_is_admin(user), WD_FIELD_SEPARATOR, wd_user_icon(user), WD_FIELD_SEPARATOR, wd_user_nick(user), WD_FIELD_SEPARATOR, wd_user_login(user), WD_FIELD_SEPARATOR, wd_user_ip(user), WD_FIELD_SEPARATOR, wd_user_host(user), WD_FIELD_SEPARATOR, wd_user_status(user), WD_FIELD_SEPARATOR, wd_user_image(user)); } } wi_array_unlock(chat->users); wd_reply(311, WI_STR("%u"), chat->cid); }
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 _wi_timer_schedule(wi_timer_t *timer) { timer->fire = wi_time_interval() + timer->interval; wi_array_wrlock(_wi_timers); wi_mutable_array_add_data_sorted(_wi_timers, timer, _wi_timer_compare); wi_array_unlock(_wi_timers); timer->scheduled = true; }
static wi_timer_t * _wi_timer_first_timer(void) { wi_timer_t *timer; wi_array_rdlock(_wi_timers); timer = wi_autorelease(wi_retain(wi_array_first_data(_wi_timers))); wi_array_unlock(_wi_timers); return timer; }
wi_boolean_t wd_chat_contains_user(wd_chat_t *chat, wd_user_t *user) { wi_boolean_t contains; wi_array_rdlock(chat->users); contains = wi_array_contains_data(chat->users, user); wi_array_unlock(chat->users); return contains; }
wi_boolean_t wd_transfers_run_transfer(wd_transfer_t *transfer, wd_user_t *user, wi_p7_message_t *message) { wi_boolean_t result = false; wi_array_wrlock(wd_transfers); wi_mutable_array_add_data(wd_transfers, transfer); wi_array_unlock(wd_transfers); wi_condition_lock_lock(wd_transfers_queue_lock); wi_condition_lock_unlock_with_condition(wd_transfers_queue_lock, 1); if(wd_transfers_wait_until_ready(transfer, user, message)) { wi_condition_lock_lock(transfer->queue_lock); transfer->state = WD_TRANSFER_RUNNING; wi_condition_lock_unlock(transfer->queue_lock); if(transfer->type == WD_TRANSFER_DOWNLOAD) result = wd_transfers_run_download(transfer, user, message); else result = wd_transfers_run_upload(transfer, user, message); wi_condition_lock_lock(transfer->finished_lock); wi_condition_lock_unlock_with_condition(transfer->finished_lock, 1); } else { wi_log_error(WI_STR("Could not process %@ for %@: %m"), (transfer->type == WD_TRANSFER_DOWNLOAD) ? WI_STR("download") : WI_STR("upload"), wd_user_identifier(user)); } if(transfer->queue == 0) wd_transfers_add_or_remove_transfer(transfer, false); wi_array_wrlock(wd_transfers); wi_mutable_array_remove_data(wd_transfers, transfer); wi_array_unlock(wd_transfers); wi_condition_lock_lock(wd_transfers_queue_lock); wi_condition_lock_unlock_with_condition(wd_transfers_queue_lock, 1); return result; }
void wd_chat_remove_user(wd_chat_t *chat, wd_user_t *user) { wi_array_wrlock(chat->users); wi_mutable_array_remove_data(chat->users, user); wi_array_unlock(chat->users); if(chat != wd_public_chat && wi_array_count(chat->users) == 0) { wi_dictionary_wrlock(wd_chats); wi_mutable_dictionary_remove_data_for_key(wd_chats, wi_number_with_int32(chat->cid)); wi_dictionary_unlock(wd_chats); } }
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); }
static void wd_trackers_update(void) { wi_enumerator_t *enumerator; wd_tracker_t *tracker; wi_array_rdlock(wd_trackers); enumerator = wi_array_data_enumerator(wd_trackers); while((tracker = wi_enumerator_next_data(enumerator))) { if(tracker->active) wd_tracker_update(tracker); } wi_array_unlock(wd_trackers); }
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); }
void wd_chat_add_user_and_broadcast(wd_chat_t *chat, wd_user_t *user) { wd_broadcast(chat, 302, WI_STR("%u%c%u%c%u%c%u%c%u%c%#@%c%#@%c%#@%c%#@%c%#@%c%#@"), chat->cid, WD_FIELD_SEPARATOR, wd_user_uid(user), WD_FIELD_SEPARATOR, wd_user_is_idle(user), WD_FIELD_SEPARATOR, wd_user_is_admin(user), WD_FIELD_SEPARATOR, wd_user_icon(user), WD_FIELD_SEPARATOR, wd_user_nick(user), WD_FIELD_SEPARATOR, wd_user_login(user), WD_FIELD_SEPARATOR, wd_user_ip(user), WD_FIELD_SEPARATOR, wd_user_host(user), WD_FIELD_SEPARATOR, wd_user_status(user), WD_FIELD_SEPARATOR, wd_user_image(user)); wi_array_wrlock(chat->users); wi_mutable_array_add_data(chat->users, user); wi_array_unlock(chat->users); }
void wd_chats_remove_user(wd_user_t *user) { wi_enumerator_t *enumerator; wd_chat_t *chat; void *key; wi_dictionary_wrlock(wd_chats); enumerator = wi_array_data_enumerator(wi_dictionary_all_keys(wd_chats)); while((key = wi_enumerator_next_data(enumerator))) { chat = wi_dictionary_data_for_key(wd_chats, key); wi_array_wrlock(chat->users); wi_mutable_array_remove_data(chat->users, user); wi_array_unlock(chat->users); if(chat != wd_public_chat && wi_array_count(chat->users) == 0) wi_mutable_dictionary_remove_data_for_key(wd_chats, key); } wi_dictionary_unlock(wd_chats); }
wd_transfer_t * wd_transfers_transfer_with_path(wd_transfer_type_t type, wi_string_t *path) { wd_transfer_t *transfer, *value = NULL; wi_uinteger_t i, count; wi_array_rdlock(wd_transfers); count = wi_array_count(wd_transfers); for(i = 0; i < count; i++) { transfer = WI_ARRAY(wd_transfers, i); if(transfer->type == type && wi_is_equal(transfer->path, path)) { value = wi_autorelease(wi_retain(transfer)); break; } } wi_array_unlock(wd_transfers); return value; }
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_transfers_update_queue(void) { wi_mutable_set_t *users; wi_mutable_array_t *sorted_users, *transfers_queue, *failed_transfers; wd_transfer_t *transfer; wd_user_t *user; wi_uinteger_t position; wi_uinteger_t i, count; wi_uinteger_t total_downloads, total_uploads, user_downloads, user_uploads, active_downloads, active_uploads; wi_boolean_t queue; wi_array_rdlock(wd_transfers); total_downloads = wd_settings.totaldownloads; user_downloads = wd_settings.clientdownloads; total_uploads = wd_settings.totaluploads; user_uploads = wd_settings.clientuploads; active_downloads = 0; active_uploads = 0; failed_transfers = wi_array_init(wi_mutable_array_alloc()); users = wi_set_init(wi_mutable_set_alloc()); count = wi_array_count(wd_transfers); for(i = 0; i < count; i++) { transfer = WI_ARRAY(wd_transfers, i); if(wd_transfer_state(transfer) == WD_TRANSFER_QUEUED) { wi_mutable_array_add_data(wd_user_transfers_queue(transfer->user), transfer); wi_mutable_set_add_data(users, transfer->user); } wd_user_clear_downloads(transfer->user); wd_user_clear_uploads(transfer->user); } for(i = 0; i < count; i++) { transfer = WI_ARRAY(wd_transfers, i); if(wd_transfer_state(transfer) == WD_TRANSFER_RUNNING) { if(transfer->type == WD_TRANSFER_DOWNLOAD) { active_downloads++; wd_user_increase_downloads(transfer->user); } else { active_uploads++; wd_user_increase_uploads(transfer->user); } } } count = wi_set_count(users); if(count > 0) { sorted_users = wi_autorelease(wi_mutable_copy(wi_set_all_data(users))); wi_mutable_array_sort(sorted_users, wd_transfers_compare_user); position = 1; while(count > 0) { for(i = 0; i < count; i++) { user = WI_ARRAY(sorted_users, i); transfers_queue = wd_user_transfers_queue(user); transfer = WI_ARRAY(transfers_queue, 0); if(transfer->type == WD_TRANSFER_DOWNLOAD) { queue = ((total_downloads > 0 && active_downloads >= total_downloads) || (user_downloads > 0 && wd_user_downloads(transfer->user) >= user_downloads)); } else { queue = ((total_uploads > 0 && active_uploads >= total_uploads) || (user_uploads > 0 && wd_user_uploads(transfer->user) >= user_uploads)); } if(queue) { if(transfer->queue != position) { transfer->queue = position; wd_user_lock_socket(transfer->user); wd_sreply(wd_user_socket(transfer->user), 401, WI_STR("%#@%c%u"), transfer->path, WD_FIELD_SEPARATOR, transfer->queue); wd_user_unlock_socket(transfer->user); } position++; } else { transfer->queue = 0; transfer->waiting_time = wi_time_interval(); wd_transfer_set_state(transfer, WD_TRANSFER_WAITING); if(wd_transfer_open(transfer)) { wd_transfer_create_timer(transfer); wd_user_lock_socket(transfer->user); wd_sreply(wd_user_socket(transfer->user), 400, WI_STR("%#@%c%llu%c%#@"), transfer->path, WD_FIELD_SEPARATOR, transfer->offset, WD_FIELD_SEPARATOR, transfer->hash); wd_user_unlock_socket(transfer->user); } else { wd_user_lock_socket(transfer->user); wd_sreply(wd_user_socket(transfer->user), 500, WI_STR("Command Failed")); wd_user_unlock_socket(transfer->user); wi_mutable_array_add_data(failed_transfers, transfer); } } wi_mutable_array_remove_data_at_index(transfers_queue, 0); if(wi_array_count(transfers_queue) == 0) { wi_mutable_array_remove_data_at_index(sorted_users, i); i--; count--; } } } } wi_mutable_array_remove_data_in_array(wd_transfers, failed_transfers); wi_array_unlock(wd_transfers); wi_release(users); wi_release(failed_transfers); }
static void wd_transfers_queue_thread(wi_runtime_instance_t *argument) { wi_pool_t *pool; wi_enumerator_t *enumerator; wi_mutable_dictionary_t *key_queues; wi_mutable_array_t *key_queue, *keys; wi_string_t *key; wd_transfer_t *transfer; wd_account_t *account; wi_uinteger_t user_downloads, user_uploads, user_transfers; wi_uinteger_t new_position, position, queue, i, count, longest_queue; pool = wi_pool_init(wi_pool_alloc()); key_queues = wi_dictionary_init(wi_mutable_dictionary_alloc()); while(true) { wi_mutable_dictionary_remove_all_data(key_queues); wi_condition_lock_lock_when_condition(wd_transfers_queue_lock, 1, 0.0); wi_array_rdlock(wd_transfers); longest_queue = 0; enumerator = wi_array_data_enumerator(wd_transfers); while((transfer = wi_enumerator_next_data(enumerator))) { wi_condition_lock_lock(transfer->queue_lock); if(transfer->state == WD_TRANSFER_QUEUED && transfer->queue != 0) { key_queue = wi_dictionary_data_for_key(key_queues, transfer->key); if(!key_queue) { key_queue = wi_mutable_array(); wi_mutable_dictionary_set_data_for_key(key_queues, key_queue, transfer->key); } wi_mutable_array_add_data(key_queue, transfer); if(wi_array_count(key_queue) > longest_queue) longest_queue = wi_array_count(key_queue); } wi_condition_lock_unlock(transfer->queue_lock); } keys = wi_autorelease(wi_mutable_copy(wi_dictionary_keys_sorted_by_value(key_queues, wd_transfers_queue_compare))); position = 1; count = wi_array_count(keys); while(longest_queue > 0) { for(i = 0; i < count; i++) { key = WI_ARRAY(keys, i); key_queue = wi_dictionary_data_for_key(key_queues, key); if(wi_array_count(key_queue) > 0) { transfer = WI_ARRAY(key_queue, 0); account = wd_user_account(transfer->user); wi_lock_lock(wd_transfers_status_lock); if(transfer->type == WD_TRANSFER_DOWNLOAD) { wi_dictionary_rdlock(wd_transfers_user_downloads); user_downloads = wd_account_transfer_download_limit(account); user_transfers = (wi_integer_t) wi_dictionary_data_for_key(wd_transfers_user_downloads, transfer->key); queue = ((wd_transfers_total_downloads > 0 && wd_transfers_active_downloads >= wd_transfers_total_downloads) || (user_downloads > 0 && user_transfers >= user_downloads)); wi_dictionary_unlock(wd_transfers_user_downloads); } else { wi_dictionary_rdlock(wd_transfers_user_uploads); user_uploads = wd_account_transfer_upload_limit(account); user_transfers = (wi_integer_t) wi_dictionary_data_for_key(wd_transfers_user_uploads, transfer->key); queue = ((wd_transfers_total_uploads > 0 && wd_transfers_active_uploads >= wd_transfers_total_uploads) || (user_uploads > 0 && user_transfers >= user_uploads)); wi_dictionary_unlock(wd_transfers_user_uploads); } wi_lock_unlock(wd_transfers_status_lock); if(queue) new_position = position++; else new_position = 0; if(new_position != (wi_uinteger_t) transfer->queue) { if(new_position == 0) wd_transfers_add_or_remove_transfer(transfer, true); wi_condition_lock_lock(transfer->queue_lock); transfer->queue = new_position; wi_condition_lock_unlock_with_condition(transfer->queue_lock, 1); } wi_mutable_array_remove_data_at_index(key_queue, 0); } } longest_queue--; } wi_array_unlock(wd_transfers); wi_condition_lock_unlock_with_condition(wd_transfers_queue_lock, 0); wi_pool_drain(pool); } wi_release(key_queues); wi_release(pool); }
void wd_transfers_remove_user(wd_user_t *user, wi_boolean_t removingallusers) { wi_enumerator_t *enumerator; wi_string_t *key; wd_user_t *each_user; wd_transfer_t *transfer; wi_uinteger_t i, count; wi_boolean_t update = false, present = false; key = wd_transfers_transfer_key_for_user(user); if(!key) return; if(!removingallusers) { wi_dictionary_rdlock(wd_users); enumerator = wi_dictionary_data_enumerator(wd_users); while((each_user = wi_enumerator_next_data(enumerator))) { if(wd_user_state(each_user) == WD_USER_LOGGED_IN && wi_is_equal(wd_transfers_transfer_key_for_user(each_user), key)) { present = true; break; } } wi_dictionary_unlock(wd_users); } if(!present) { wi_array_wrlock(wd_transfers); count = wi_array_count(wd_transfers); for(i = 0; i < count; i++) { transfer = WI_ARRAY(wd_transfers, i); if(wi_is_equal(key, transfer->key)) { wd_user_set_state(transfer->user, WD_USER_DISCONNECTED); if(transfer->state == WD_TRANSFER_RUNNING) { if(wi_condition_lock_lock_when_condition(transfer->finished_lock, 1, 1.0)) wi_condition_lock_unlock(transfer->finished_lock); } else { wi_mutable_array_remove_data_at_index(wd_transfers, i); i--; count--; update = true; } } } if(update) { wi_condition_lock_lock(wd_transfers_queue_lock); wi_condition_lock_unlock_with_condition(wd_transfers_queue_lock, 1); } wi_array_unlock(wd_transfers); } }
wi_socket_t * wi_socket_wait_multiple(wi_array_t *array, wi_time_interval_t timeout) { wi_enumerator_t *enumerator; wi_socket_t *socket, *waiting_socket = NULL; struct timeval tv; fd_set rfds, wfds; int state, max_sd; tv = wi_dtotv(timeout); max_sd = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); wi_array_rdlock(array); enumerator = wi_array_data_enumerator(array); while((socket = wi_enumerator_next_data(enumerator))) { if(wi_string_length(socket->buffer) > 0) { waiting_socket = socket; break; } if(socket->direction & WI_SOCKET_READ) FD_SET(socket->sd, &rfds); if(socket->direction & WI_SOCKET_WRITE) FD_SET(socket->sd, &wfds); if(socket->sd > max_sd) max_sd = socket->sd; } wi_array_unlock(array); if(waiting_socket) return waiting_socket; state = select(max_sd + 1, &rfds, &wfds, NULL, (timeout > 0.0) ? &tv : NULL); if(state < 0) { wi_error_set_errno(errno); return NULL; } wi_array_rdlock(array); enumerator = wi_array_data_enumerator(array); while((socket = wi_enumerator_next_data(enumerator))) { if(FD_ISSET(socket->sd, &rfds) || FD_ISSET(socket->sd, &wfds)) { waiting_socket = socket; break; } } wi_array_unlock(array); return waiting_socket; }
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 }