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); }
static wi_boolean_t wd_transfers_run_download(wd_transfer_t *transfer, wd_user_t *user, wi_p7_message_t *message) { wi_p7_message_t *reply; wi_data_t *data; wi_p7_uint32_t transaction; wi_boolean_t result; data = wi_fs_finder_info_for_path(transfer->realdatapath); reply = wi_p7_message_with_name(WI_STR("wired.transfer.download"), 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->remainingdatasize, WI_STR("wired.transfer.data")); wi_p7_message_set_oobdata_for_name(reply, transfer->remainingrsrcsize, WI_STR("wired.transfer.rsrc")); wi_p7_message_set_data_for_name(reply, data ? data : wi_data(), WI_STR("wired.transfer.finderinfo")); 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; } wi_socket_set_interactive(wd_user_socket(user), false); result = wd_transfer_download(transfer); wi_socket_set_interactive(wd_user_socket(user), true); if(transfer->transferred == transfer->datasize + transfer->rsrcsize) wd_accounts_add_download_statistics(wd_user_account(user), true, transfer->actualtransferred); else wd_accounts_add_download_statistics(wd_user_account(user), false, transfer->actualtransferred); return result; }
void wd_reply(uint32_t n, wi_string_t *fmt, ...) { wd_user_t *user = wd_users_user_for_thread(); 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); 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_release(string); }
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 wi_boolean_t wd_transfer_download(wd_transfer_t *transfer) { wi_pool_t *pool; wi_socket_t *socket; wi_p7_socket_t *p7_socket; wd_account_t *account; char buffer[WD_TRANSFER_BUFFER_SIZE]; wi_socket_state_t state; wi_time_interval_t timeout, interval, speedinterval, statusinterval, accountinterval; wi_file_offset_t sendbytes, speedbytes, statsbytes; wi_uinteger_t i, transfers; ssize_t readbytes; int sd; wi_boolean_t data, result; wd_user_state_t user_state; interval = wi_time_interval(); speedinterval = interval; statusinterval = interval; accountinterval = interval; speedbytes = 0; statsbytes = 0; i = 0; socket = wd_user_socket(transfer->user); sd = wi_socket_descriptor(socket); p7_socket = wd_user_p7_socket(transfer->user); account = wd_user_account(transfer->user); data = true; result = true; wd_transfers_note_statistics(WD_TRANSFER_DOWNLOAD, WD_TRANSFER_STATISTICS_ADD, 0); wi_dictionary_rdlock(wd_transfers_user_downloads); transfers = (wi_integer_t) wi_dictionary_data_for_key(wd_transfers_user_downloads, transfer->key); wi_dictionary_unlock(wd_transfers_user_downloads); pool = wi_pool_init(wi_pool_alloc()); wd_user_lock_socket(transfer->user); while(wd_user_state(transfer->user) == WD_USER_LOGGED_IN) { if(data && transfer->remainingdatasize == 0) data = false; if(!data && transfer->remainingrsrcsize == 0) break; readbytes = read(data ? transfer->datafd : transfer->rsrcfd, buffer, sizeof(buffer)); if(readbytes <= 0) { if(readbytes < 0) { wi_log_error(WI_STR("Could not read download from \"%@\": %m"), data ? transfer->realdatapath : transfer->realrsrcpath, strerror(errno)); } result = false; break; } timeout = wi_time_interval(); do { user_state = wd_user_state(transfer->user); state = wi_socket_wait_descriptor(sd, 0.1, false, true); if(state == WI_SOCKET_TIMEOUT) { if(wi_time_interval() - timeout >= 30.0) break; } } while(state == WI_SOCKET_TIMEOUT && user_state == WD_USER_LOGGED_IN); if(state == WI_SOCKET_ERROR || wi_time_interval() - timeout >= 30.0) { wi_log_error(WI_STR("Could not wait for download to %@: %@"), wd_user_identifier(transfer->user), (state == WI_SOCKET_ERROR) ? wi_error_string() : WI_STR("Timed out")); result = false; break; } if(user_state != WD_USER_LOGGED_IN) { result = false; break; } if(data) { sendbytes = (transfer->remainingdatasize < (wi_file_offset_t) readbytes) ? transfer->remainingdatasize : (wi_file_offset_t) readbytes; } else { sendbytes = (transfer->remainingrsrcsize < (wi_file_offset_t) readbytes) ? transfer->remainingrsrcsize : (wi_file_offset_t) readbytes; } if(!wi_p7_socket_write_oobdata(p7_socket, 30.0, buffer, sendbytes)) { wi_log_error(WI_STR("Could not write download to %@: %m"), wd_user_identifier(transfer->user)); result = false; break; } if(data) transfer->remainingdatasize -= sendbytes; else transfer->remainingrsrcsize -= sendbytes; interval = wi_time_interval(); transfer->transferred += sendbytes; transfer->actualtransferred += sendbytes; speedbytes += sendbytes; statsbytes += sendbytes; transfer->speed = speedbytes / (interval - speedinterval); wd_transfer_limit_speed(transfer, wd_transfers_total_download_speed, wd_account_transfer_download_speed_limit(account), wd_current_downloads, transfers, speedbytes, interval, speedinterval); if(interval - speedinterval > 30.0) { speedbytes = 0; speedinterval = interval; } if(interval - statusinterval > wd_current_downloads) { wd_transfers_note_statistics(WD_TRANSFER_DOWNLOAD, WD_TRANSFER_STATISTICS_DATA, statsbytes); statsbytes = 0; statusinterval = interval; } if(interval - accountinterval > 15.0) { account = wd_user_account(transfer->user); accountinterval = interval; wi_dictionary_rdlock(wd_transfers_user_downloads); transfers = (wi_integer_t) wi_dictionary_data_for_key(wd_transfers_user_downloads, transfer->key); wi_dictionary_unlock(wd_transfers_user_downloads); } if(++i % 1000 == 0) wi_pool_drain(pool); } wd_user_unlock_socket(transfer->user); wi_release(pool); wd_transfers_note_statistics(WD_TRANSFER_DOWNLOAD, WD_TRANSFER_STATISTICS_REMOVE, statsbytes); return result; }
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; }