Пример #1
0
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);
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
0
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);
}
Пример #5
0
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;
}
Пример #6
0
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;
}