Beispiel #1
0
wi_p7_message_t * wi_p7_socket_read_message(wi_p7_socket_t *p7_socket, wi_time_interval_t timeout) {
	wi_p7_message_t		*p7_message;
	wi_string_t			*prefix = NULL;
	char				length_buffer[_WI_P7_SOCKET_LENGTH_SIZE];
	uint32_t			length;
	
	if(p7_socket->serialization == WI_P7_UNKNOWN || p7_socket->serialization == WI_P7_BINARY) {
		if(wi_socket_read_buffer(p7_socket->socket, timeout, length_buffer, sizeof(length_buffer)) <= 0)
			return NULL;
		
		length = wi_read_swap_big_to_host_int32(length_buffer, 0);
		
		if(p7_socket->serialization == WI_P7_UNKNOWN) {
			if(length == _WI_P7_SOCKET_XML_MAGIC) {
				p7_socket->serialization = WI_P7_XML;
				prefix = WI_STR("<?xm");
			}
			else if(length <= _WI_P7_SOCKET_BINARY_MAGIC_SIZE) {
				p7_socket->serialization = WI_P7_BINARY;
			}
		}
	}
	
	if(p7_socket->serialization == WI_P7_BINARY)
		p7_message = _wi_p7_socket_read_binary_message(p7_socket, timeout, length);
	else if(p7_socket->serialization == WI_P7_XML)
		p7_message = _wi_p7_socket_read_xml_message(p7_socket, timeout, prefix);
	else {
		wi_error_set_libwired_p7_error(WI_ERROR_P7_HANDSHAKEFAILED,
			WI_STR("Invalid data from remote host"));
		
		return NULL;
	}
	
	if(!p7_message)
		return NULL;

	if(p7_message->binary_size == 0) {
		wi_error_set_libwired_p7_error(WI_ERROR_P7_INVALIDMESSAGE,
			WI_STR("Invalid data from remote host"));
		
		return NULL;
	}
	
	wi_p7_message_deserialize(p7_message);
	
	wi_log_info(WI_STR("Received %@"), p7_message);

	wi_log_info(WI_STR("Received %llu raw bytes, %llu processed bytes, compressed to %.2f%%"),
		p7_socket->read_raw_bytes,
		p7_socket->read_processed_bytes,
		((double) p7_socket->read_raw_bytes / (double) p7_socket->read_processed_bytes) * 100.0);

	return p7_message;
}
Beispiel #2
0
void wt_control_thread(wi_runtime_instance_t *argument) {
	wi_pool_t			*pool;
	wt_client_t			*client = argument;
	wi_string_t			*string;
	wi_socket_state_t	state;
	wi_uinteger_t		i = 0;
	
	pool = wi_pool_init(wi_pool_alloc());

	wt_client_set(client);

	while(client->state <= WT_CLIENT_STATE_SAID_HELLO) {
		do {
			state = wi_socket_wait(client->socket, 0.1);
		} while(state == WI_SOCKET_TIMEOUT && client->state <= WT_CLIENT_STATE_SAID_HELLO);

		if(client->state > WT_CLIENT_STATE_SAID_HELLO) {
			/* invalid state */
			break;
		}

		if(state == WI_SOCKET_ERROR) {
			if(wi_error_code() == EINTR) {
				/* got a signal */
				continue;
			} else {
				/* error in TCP communication */
				wi_log_err(WI_STR("Could not read from %@: %m"), client->ip);

				break;
			}
		}

		string = wi_socket_read_to_string(client->socket, 0.0, WI_STR(WT_MESSAGE_SEPARATOR_STR));

		if(!string || wi_string_length(string) == 0) {
			if(!string)
				wi_log_info(WI_STR("Could not read from %@: %m"), client->ip);
			
			break;
		}

		wt_parse_command(string);
		
		if(++i % 10 == 0)
			wi_pool_drain(pool);
	}

	wi_log_info(WI_STR("Disconnect from %@ after %.2fs"),
		client->ip,
		wi_time_interval() - client->connect_time);
	
	wi_release(pool);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
}
Beispiel #5
0
wi_boolean_t wi_settings_read_file(wi_settings_t *settings) {
	wi_file_t		*file;
	wi_string_t		*string;
	
	file = wi_file_for_reading(wi_settings_config_path);
	
	if(!file) {
		wi_log_err(WI_STR("Could not open %@: %s"),
			wi_settings_config_path, strerror(errno));
		
		return false;
	}
	
	wi_log_info(WI_STR("Reading %@"), wi_settings_config_path);
	_wi_settings_clear(settings);
	
	settings->file		= wi_settings_config_path;
	settings->line		= 0;
	
	while((string = wi_file_read_line(file))) {
		settings->line++;

		if(wi_string_length(string) > 0 && !wi_string_has_prefix(string, WI_STR("#")))
			_wi_settings_parse_setting(settings, string);
	}

	settings->file = NULL;

	return true;
}
Beispiel #6
0
void wi_tests_start(void) {
	_wi_tests_start_date = wi_date_init(wi_date_alloc());
	
	wi_tests_passed = wi_tests_failed = 0;
	
	wi_log_info(WI_STR("Tests started at %@"), wi_date_string_with_format(_wi_tests_start_date, WI_STR("%Y-%m-%d %H:%M:%S")));
}
Beispiel #7
0
static void wd_cmd_hello(wi_array_t *arguments) {
	wd_client_t		*client = wd_client();
	wi_string_t		*string;

	if(client->state != WD_CLIENT_STATE_CONNECTED)
		return;

	if(wd_ip_is_banned(client->ip)) {
		wd_reply(511, WI_STR("Banned"));
		wi_log_info(WI_STR("Connection from %@ denied, host is banned"),
			client->ip);

		client->state = WD_CLIENT_STATE_DISCONNECTED;
		return;
	}

	string = wi_date_iso8601_string(wd_start_date);

	wd_reply(200, WI_STR("%#@%c%#@%c%#@%c%#@%c%#@%c%u%c%llu"),
			 wd_server_version_string,		WD_FIELD_SEPARATOR,
			 wd_protocol_version_string,	WD_FIELD_SEPARATOR,
			 wd_settings.name,				WD_FIELD_SEPARATOR,
			 wd_settings.description,		WD_FIELD_SEPARATOR,
			 string,						WD_FIELD_SEPARATOR,
			 wd_files_count,				WD_FIELD_SEPARATOR,
			 wd_files_size);
	
	client->state = WD_CLIENT_STATE_SAID_HELLO;
}
Beispiel #8
0
wi_boolean_t wi_settings_read_file(wi_settings_t *settings, wi_boolean_t chroot) {
	wi_file_t		*file;
	wi_string_t		*path, *string;
	wi_boolean_t	result = true;
	
	path = wi_full_path(wi_settings_config_path);
	file = wi_file_for_reading(path);
	
	if(!file) {
		wi_log_err(WI_STR("Could not open %@: %s"),
			path, strerror(errno));
		
		return false;
	}
	
	wi_log_info(WI_STR("Reading %@"), path);
	_wi_settings_clear(settings);
	
	settings->file		= path;
	settings->line		= 0;
	settings->chroot	= chroot;
	
	while((string = wi_file_read_line(file))) {
		settings->line++;

		if(wi_string_length(string) > 0 && !wi_string_has_prefix(string, WI_STR("#"))) {
			if(!_wi_settings_parse_setting(settings, string))
				result = false;
		}
	}

	settings->file = NULL;

	return result;
}
Beispiel #9
0
void wi_tests_run_test(const char *name, wi_run_test_func_t *function) {
    wi_pool_t                   *pool;
    wi_assert_handler_func_t    *handler;
    wi_time_interval_t          interval;
    
    if(_wi_tests_name) {
        if(wi_string_index_of_string(wi_string_with_utf8_string(name), _wi_tests_name, 0) == WI_NOT_FOUND)
            return;
    }
    
    if(wi_string_has_suffix(wi_string_with_utf8_string(name), WI_STR("initialize"))) {
        (*function)();
    } else {
        _wi_tests_current_test = _wi_test_init_with_function(_wi_test_alloc(), wi_string_with_utf8_string(name), function);
        
        handler = wi_assert_handler;
        wi_assert_handler = _wi_tests_assert_handler;
        
        interval = wi_time_interval();
        
        pool = wi_pool_init(wi_pool_alloc());

        if(setjmp(_wi_tests_jmp_buf) == 0)
            (*_wi_tests_current_test->function)();

        wi_release(pool);
        
        _wi_tests_current_test->interval = wi_time_interval() - interval;
        
        wi_assert_handler = handler;

        if(_wi_tests_current_test->passed) {
            wi_log_info(WI_STR("Test \"%@\" passed (%.3f seconds)"),
                _wi_tests_current_test->name, _wi_tests_current_test->interval);
            
            wi_tests_passed++;
        } else {
            wi_log_info(WI_STR("Test \"%@\" failed (%.3f seconds)"),
                _wi_tests_current_test->name, _wi_tests_current_test->interval);
            
            wi_tests_failed++;
        }
        
        wi_release(_wi_tests_current_test);
    }
}
Beispiel #10
0
void wi_tests_stop_and_report(void) {
	wi_uinteger_t	tests;
	
	tests = wi_tests_passed + wi_tests_failed;
	
	wi_log_info(WI_STR("Tests stopped at %@"), wi_date_string_with_format(_wi_tests_start_date, WI_STR("%Y-%m-%d %H:%M:%S")));
	wi_log_info(WI_STR("%lu %@ passed (%.1f%%), %lu failed (%.1f%%) in %.3f seconds"),
		wi_tests_passed,
		wi_tests_passed == 1
			? WI_STR("test")
			: WI_STR("tests"),
		tests > 0 ? ((double) wi_tests_passed / (double) tests) * 100.0 : 0.0,
		wi_tests_failed,
		tests > 0 ? ((double) wi_tests_failed / (double) tests) * 100.0 : 0.0,
		wi_date_time_interval_since_now(_wi_tests_start_date));

	wi_release(_wi_tests_start_date);
}
Beispiel #11
0
void wd_banlist_initialize(void) {
	wd_banlist_create_tables();
	
	if(wi_fs_path_exists(WI_STR("banlist"), NULL)) {
		if(wd_banlist_convert_banlist(WI_STR("banlist"))) {
			wi_log_info(WI_STR("Migrated banlist to database"));
			wi_fs_delete_path(WI_STR("banlist"));
		}
	}
}
Beispiel #12
0
void wr_client_reconnect(void) {
    wr_connected 	= false;
    wr_reconnecting = true;

    wi_log_info(WI_STR("Reconnecting in 10 seconds..."));

    sleep(10);

    wr_client_connect(wb_hostname, wb_port, wb_login, wb_password);

    wr_reconnecting = false;
}
Beispiel #13
0
void wd_trackers_register(wi_boolean_t update) {
	if(wi_array_count(wd_trackers) > 0) {
		wi_release(wd_trackers_guest_account);
		
		wd_trackers_guest_account = wi_retain(wd_accounts_read_user_and_group(WI_STR("guest")));
		
		wi_log_info(WI_STR("Registering with trackers..."));

		if(!wi_thread_create_thread(wd_trackers_register_thread, wi_number_with_bool(update)))
			wi_log_err(WI_STR("Could not create a register thread: %m"));
	}
}
Beispiel #14
0
wi_boolean_t wi_p7_socket_write_message(wi_p7_socket_t *p7_socket, wi_time_interval_t timeout, wi_p7_message_t *p7_message) {
	wi_boolean_t	result;
	
	wi_p7_message_serialize(p7_message);
	
	wi_log_info(WI_STR("Sending %@"), p7_message);
	
	if(p7_socket->serialization == WI_P7_BINARY)
		result = _wi_p7_socket_write_binary_message(p7_socket, timeout, p7_message);
	else
		result = _wi_p7_socket_write_xml_message(p7_socket, timeout, p7_message);
	
	if(!result)
		return false;
	
	wi_log_info(WI_STR("Sent %llu raw bytes, %llu processed bytes, compressed to %.2f%%"),
		p7_socket->sent_raw_bytes,
		p7_socket->sent_processed_bytes,
		((double) p7_socket->sent_raw_bytes / (double) p7_socket->sent_processed_bytes) * 100.0);
	
	return true;
}
Beispiel #15
0
static void wd_control_listen_thread(wi_runtime_instance_t *argument) {
	wi_pool_t			*pool;
	wi_socket_t			*socket;
	wi_address_t		*address;
	wi_string_t			*ip;
	wd_user_t			*user;
	
	pool = wi_pool_init(wi_pool_alloc());

	while(wd_running) {
		wi_pool_drain(pool);

		/* accept new user */
		socket = wi_socket_accept_multiple(wd_control_sockets, wd_control_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;
		}
		
		wi_socket_set_direction(socket, WI_SOCKET_READ);
		
		wi_log_info(WI_STR("Connect from %@"), ip);
		
		/* spawn a user thread */
		user = wd_user_with_socket(socket);

		if(!wi_thread_create_thread(wd_control_thread, user))
			wi_log_err(WI_STR("Could not create a thread for %@: %m"), ip);
	}
	
	wi_release(pool);
}
Beispiel #16
0
void wr_client_disconnect(void) {
    if(wr_connected) {
        wi_log_info(WI_STR("Connection to %@ closed"),
                    wi_address_string(wi_socket_address(wr_socket)));

        wr_connected = false;
    }

    wr_runloop_remove_socket(wr_socket);
    wi_socket_close(wr_socket);
    wi_release(wr_p7_socket);
    wi_release(wr_socket);

    wi_release(wr_server);

    wi_release(wr_password);

    wr_chats_clear();
    wr_users_clear();
}
Beispiel #17
0
int main(int argc, const char **argv) {
	wi_pool_t			*pool;
	wi_string_t			*string;
	int					ch, facility;
	wi_boolean_t		no_chroot, test_config;

	/* init libwired */
	wi_initialize();
	wi_load(argc, argv);
	
	pool					= wi_pool_init(wi_pool_alloc());
	wi_log_startup			= true;
	wi_log_syslog			= true;
	wi_log_syslog_facility	= LOG_DAEMON;

	/* init core systems */
	wt_init_version();
	wt_status_lock			= wi_lock_init(wi_lock_alloc());
	wt_start_date			= wi_date_init(wi_date_alloc());
	
	/* set defaults */
	wi_root_path			= wi_string_init_with_cstring(wi_string_alloc(), WT_ROOT);
	wi_settings_config_path	= wi_string_init_with_cstring(wi_string_alloc(), WT_CONFIG_PATH);
	no_chroot				= false;
	test_config				= false;

	/* parse command line switches */
	while((ch = getopt(argc, (char * const *) argv, "46Dd:f:hi:L:ls:tuVv")) != -1) {
		switch(ch) {
			case '4':
				wt_address_family = WI_ADDRESS_IPV4;
				break;

			case '6':
				wt_address_family = WI_ADDRESS_IPV6;
				break;

			case 'D':
				wt_daemonize = false;
				wi_log_stderr = true;
				break;

			case 'd':
				wi_release(wi_root_path);
				wi_root_path = wi_string_init_with_cstring(wi_string_alloc(), optarg);
				break;

			case 'f':
				wi_release(wi_settings_config_path);
				wi_settings_config_path = wi_string_init_with_cstring(wi_string_alloc(), optarg);
				break;

			case 'i':
				wi_log_limit = wi_string_uint32(wi_string_with_cstring(optarg));
				break;

			case 'L':
				wi_log_syslog = false;
				wi_log_file = true;

				wi_release(wi_log_path);
				wi_log_path = wi_string_init_with_cstring(wi_string_alloc(), optarg);
				break;

			case 'l':
				wi_log_level++;
				break;

			case 's':
				string = wi_string_with_cstring(optarg);
				facility = wi_log_syslog_facility_with_name(string);
				
				if(facility < 0) {
					wi_log_err(WI_STR("Could not find syslog facility \"%@\": %m"),
						string);
				}
				
				wi_log_syslog_facility = facility;
				break;

			case 't':
				test_config = true;
				break;

			case 'u':
				no_chroot = true;
				break;

			case 'V':
			case 'v':
				wt_version();
				break;

			case '?':
			case 'h':
			default:
				wt_usage();
				break;
		}
	}
	
	/* open log */
	wi_log_open();

	/* init subsystems */
	wt_init_ssl();
	wt_init_clients();
	wt_init_servers();

	/* read the config file */
	wt_settings_chroot = !no_chroot;
	wt_init_settings();

	if(!wt_read_config())
		exit(1);

	/* change root directory */
	if(!no_chroot) {
		if(!wi_change_root())
			wi_log_err(WI_STR("Could not change root to %@: %m"), wi_root_path);
	}

	/* apply config */
	wt_apply_config();

	if(test_config) {
		printf("Config OK\n");

		exit(0);
	}

	/* dump command line */
	if(wi_log_level >= WI_LOG_DEBUG) {
		wi_log_debug(WI_STR("Started as %@ %@"),
			wi_process_path(wi_process()),
			wi_array_components_joined_by_string(wi_process_arguments(wi_process()), WI_STR(" ")));
	}

	/* init tracker */
	wi_log_info(WI_STR("Starting Wired Tracker version %@"), wt_version_string);
	wt_init_tracker();

	/* detach (don't chdir, don't close i/o channels) */
	if(wt_daemonize) {
		if(!wi_daemon())
			wi_log_err(WI_STR("Could not become a daemon: %m"));
	}

	/* switch user/group */
	wi_switch_user(wt_settings.user, wt_settings.group);
		
	/* create tracker threads after privilege drop */
	wt_init_signals();
	wt_block_signals();
	wt_schedule_servers();
	wt_fork_tracker();
	wt_write_pid();
	wt_write_status(true);
	wi_log_startup = false;
	
	wi_release(pool);
	pool = wi_pool_init(wi_pool_alloc());
	
	/* enter the signal handling thread in the main thread */
	wt_signal_thread(NULL);

	/* dropped out */
	wt_cleanup();
	wi_log_close();
	wi_release(pool);

	return 0;
}
Beispiel #18
0
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);
}
Beispiel #19
0
void wd_control_thread(wi_runtime_instance_t *argument) {
	wi_pool_t		*pool;
	wd_client_t		*client = argument;
	wi_string_t		*string;
	unsigned int	i = 0;
	int				state;
	
	pool = wi_pool_init(wi_pool_alloc());

	wd_clients_add_client(client);
	wd_client_set(client);

	while(client->state <= WD_CLIENT_STATE_LOGGED_IN) {
		if(!pool)
			pool = wi_pool_init(wi_pool_alloc());
		
		if(client->buffer_offset == 0) {
			do {
				state = wi_socket_wait(client->socket, 0.1);
			} while(state == 0 && client->state <= WD_CLIENT_STATE_LOGGED_IN);
			
			if(client->state > WD_CLIENT_STATE_LOGGED_IN) {
				/* invalid state */
				break;
			}

			if(state < 0) {
				if(wi_error_code() == EINTR) {
					/* got a signal */
					continue;
				} else {
					/* error in TCP communication */
					wi_log_err(WI_STR("Could not read from %@: %m"), client->ip);

					break;
				}
			}
		}

		wd_client_lock_socket(client);
		string = wi_socket_read_to_string(client->socket, 0.0, WI_STR(WD_MESSAGE_SEPARATOR_STR));
		wd_client_unlock_socket(client);
		
		if(!string || wi_string_length(string) == 0) {
			if(!string)
				wi_log_info(WI_STR("Could not read from %@: %m"), client->ip);
			
			break;
		}

		wd_parse_command(string);
		
		if(++i % 10 == 0) {
			wi_release(pool);
			pool = NULL;
		}
	}
	
	/* announce parting if client disconnected by itself */
	if(client->state == WD_CLIENT_STATE_LOGGED_IN) {
		client->state = WD_CLIENT_STATE_DISCONNECTED;

		wd_broadcast_lock();
		wd_client_broadcast_leave(client, WD_PUBLIC_CID);
		wd_broadcast_unlock();
	}

	/* update status for clients logged in and above */
	if(client->state >= WD_CLIENT_STATE_LOGGED_IN) {
		wi_lock_lock(wd_status_lock);
		wd_current_users--;
		wd_write_status(true);
		wi_lock_unlock(wd_status_lock);
	}

	wi_log_info(WI_STR("Disconnect from %@"), client->ip);
	
	wi_socket_close(client->socket);
	
	wd_clients_remove_client(client);
	
	wi_release(pool);
}
Beispiel #20
0
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);
}
Beispiel #21
0
void wr_client_connect(wi_string_t *hostname, wi_uinteger_t port, wi_string_t *login, wi_string_t *password) {
    wi_enumerator_t		*enumerator;
    wi_array_t			*addresses;
    wi_address_t		*address;
    wi_p7_socket_t		*p7_socket;
    wi_p7_message_t		*message;
    wi_socket_t			*socket;
    wi_string_t			*ip;
    wr_server_t			*server;

    wi_log_info(WI_STR("Connecting to %@..."), hostname);

    if(port == 0)
        port = WR_PORT;

    if(!login)
        login = WI_STR("guest");

    if(!password)
        password = WI_STR("");

    addresses = wi_host_addresses(wi_host_with_string(hostname));

    if(!addresses) {
        wi_log_info(WI_STR("Could not resolve \"%@\": %m"),
                    hostname);

        return;
    }

    enumerator = wi_array_data_enumerator(addresses);

    while((address = wi_enumerator_next_data(enumerator))) {
        ip = wi_address_string(address);

        wi_log_info(WI_STR("Trying %@ at port %u..."), ip, port);

        wi_address_set_port(address, port);

        socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP));

        if(!socket) {
            wi_log_info(WI_STR("Could not open a socket to %@: %m"), ip);

            continue;
        }

        wi_socket_set_interactive(socket, true);

        if(!wi_socket_connect(socket, 10.0)) {
            wi_log_info(WI_STR("Could not connect to %@: %m"), ip);

            continue;
        }

        p7_socket = wi_autorelease(wi_p7_socket_init_with_socket(wi_p7_socket_alloc(), socket, wr_p7_spec));

        if(!wi_p7_socket_connect(p7_socket,
                                 10.0,
                                 WI_P7_COMPRESSION_DEFLATE | WI_P7_ENCRYPTION_RSA_AES256_SHA1 | WI_P7_CHECKSUM_SHA1,
                                 WI_P7_BINARY,
                                 login,
                                 wi_string_sha1(password))) {
            wi_log_info(WI_STR("Could not connect to %@: %m"), ip);

            continue;
        }

        wi_log_info(WI_STR("Connected using %@/%u bits, logging in..."),
                    wi_cipher_name(wi_p7_socket_cipher(p7_socket)),
                    wi_cipher_bits(wi_p7_socket_cipher(p7_socket)));

        server = wr_client_login(p7_socket, login, password);

        if(!server)
            break;

        wi_log_info(WI_STR("Logged in, welcome to %@"), wr_server_name(server));

        message = wi_p7_message_with_name(WI_STR("wired.chat.join_chat"), wr_p7_spec);
        wi_p7_message_set_uint32_for_name(message, wr_chat_id(wr_public_chat), WI_STR("wired.chat.id"));
        wr_client_write_message(p7_socket, message);

        wr_connected	= true;
        wr_socket		= wi_retain(socket);
        wr_p7_socket	= wi_retain(p7_socket);
        wr_server		= wi_retain(server);
        wr_password		= wi_retain(password);

        wi_socket_set_direction(wr_socket, WI_SOCKET_READ);
        wr_runloop_add_socket(wr_socket, &wr_runloop_server_callback);

        // suscribe bot watchers
        wb_bot_subscribe_watchers(wb_bot);

        break;
    }
}
Beispiel #22
0
int main(int argc, const char **argv) {
	wi_mutable_array_t		*arguments;
	wi_pool_t				*pool;
	wi_string_t				*string, *root_path;
	int						ch, facility;
	wi_boolean_t			test_config, daemonize, change_directory, switch_user;

	/* init libwired */
	wi_initialize();
	wi_load(argc, argv);
	
	pool					= wi_pool_init(wi_pool_alloc());
	wi_log_syslog			= true;
	wi_log_syslog_facility	= LOG_DAEMON;

	/* init core systems */
	wt_version_init();
	wt_status_lock			= wi_lock_init(wi_lock_alloc());
	wt_start_date			= wi_date_init(wi_date_alloc());
	
	/* set defaults */
	root_path				= WI_STR(WT_ROOT);
	wi_settings_config_path	= wi_string_init_with_cstring(wi_string_alloc(), WT_CONFIG_PATH);
	test_config				= false;
	daemonize				= true;
	change_directory		= true;
	switch_user				= true;

	/* init reexec argument list */
	arguments				= wi_array_init(wi_mutable_array_alloc());

	/* parse command line switches */
	while((ch = getopt(argc, (char * const *) argv, "46Dd:f:hi:L:ls:tuVvXx")) != -1) {
		switch(ch) {
			case '4':
				wt_address_family = WI_ADDRESS_IPV4;
				break;

			case '6':
				wt_address_family = WI_ADDRESS_IPV6;
				break;

			case 'D':
				daemonize = false;
				wi_log_stderr = true;
				break;

			case 'd':
				root_path = wi_string_with_cstring(optarg);
				break;

			case 'f':
				wi_release(wi_settings_config_path);
				wi_settings_config_path = wi_string_init_with_cstring(wi_string_alloc(), optarg);
				break;

			case 'i':
				wi_log_limit = wi_string_uint32(wi_string_with_cstring(optarg));
				break;

			case 'L':
				wi_log_syslog = false;
				wi_log_file = true;

				wi_release(wi_log_path);
				wi_log_path = wi_string_init_with_cstring(wi_string_alloc(), optarg);
				break;

			case 'l':
				wi_log_level++;
				break;

			case 's':
				string = wi_string_with_cstring(optarg);
				facility = wi_log_syslog_facility_with_name(string);
				
				if(facility < 0)
					wi_log_fatal(WI_STR("Could not find syslog facility \"%@\": %m"), string);
				
				wi_log_syslog_facility = facility;
				break;

			case 't':
				test_config = true;
				break;

			case 'u':
				break;

			case 'V':
			case 'v':
				wt_version();
				break;
				
			case 'X':
				daemonize = false;
				break;
				
			case 'x':
				daemonize = false;
				change_directory = false;
				switch_user = false;
				break;
			
			case '?':
			case 'h':
			default:
				wt_usage();
				break;
		}
		
		wi_mutable_array_add_data(arguments, wi_string_with_format(WI_STR("-%c"), ch));
		
		if(optarg)
			wi_mutable_array_add_data(arguments, wi_string_with_cstring(optarg));
	}
	
	/* detach */
	if(daemonize) {
		wi_mutable_array_add_data(arguments, WI_STR("-X"));
		
		switch(wi_fork()) {
			case -1:
				wi_log_fatal(WI_STR("Could not fork: %m"));
				break;
				
			case 0:
				if(!wi_execv(wi_string_with_cstring(argv[0]), arguments))
					wi_log_fatal(WI_STR("Could not execute %s: %m"), argv[0]);
				break;
				
				default:
				_exit(0);
				break;
		}
	}
	
	wi_release(arguments);
	
	/* change directory */
	if(change_directory) {
		if(!wi_fs_change_directory(root_path))
			wi_log_error(WI_STR("Could not change directory to %@: %m"), root_path);
	}
	
	/* open log */
	wi_log_open();

	/* init subsystems */
	wt_ssl_init();
	wt_clients_init();
	wt_servers_init();

	/* read the config file */
	wt_settings_init();

	if(!wt_settings_read_config())
		exit(1);

	/* apply settings */
	wt_settings_apply_settings();

	if(test_config) {
		printf("Config OK\n");

		exit(0);
	}

	/* dump command line */
	wi_log_info(WI_STR("Started as %@ %@"),
		wi_process_path(wi_process()),
		wi_array_components_joined_by_string(wi_process_arguments(wi_process()), WI_STR(" ")));

	/* init tracker */
	wi_log_info(WI_STR("Starting Wired Tracker version %@"), wt_version_string);
	wt_tracker_init();

	/* switch user/group */
	if(switch_user)
		wi_switch_user(wt_settings.user, wt_settings.group);
		
	/* create tracker threads after privilege drop */
	wt_signals_init();
	wt_block_signals();
	wt_servers_schedule();
	wt_tracker_create_threads();
	wt_write_pid();
	wt_write_status(true);
	
	/* clean up pool after startup */
	wi_pool_drain(pool);
	
	/* enter the signal handling thread in the main thread */
	wt_signal_thread(NULL);

	/* dropped out */
	wt_cleanup();
	wi_log_close();
	wi_release(pool);

	return 0;
}
Beispiel #23
0
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
}
Beispiel #24
0
static void wd_server_register_dnssd_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErrorType error, const char *name, const char *regtype, const char *domain, void *context) {
	wi_log_info(WI_STR("DNS service discovery reply for %s.%s%s: %d"), name, regtype, domain, error);
}
Beispiel #25
0
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"));
		}
	}
}
Beispiel #26
0
wi_boolean_t wi_config_read_file(wi_config_t *config) {
	wi_enumerator_t				*enumerator;
	wi_runtime_instance_t		*instance;
	wi_file_t					*file;
	wi_mutable_array_t			*array;
	wi_mutable_dictionary_t		*previous_values;
	wi_string_t					*string, *name, *value;
	wi_config_type_t			type;
	
	file = wi_file_for_reading(config->path);
	
	if(!file) {
		wi_log_err(WI_STR("Could not open %@: %m"),
			config->path);
		
		return false;
	}
	
	wi_log_info(WI_STR("Reading %@"), config->path);
	
	config->line = 0;
	
	wi_lock_lock(config->lock);
	
	previous_values = config->values;
	
	config->values = wi_dictionary_init(wi_mutable_dictionary_alloc());
	
	if(config->defaults) {
		enumerator = wi_dictionary_key_enumerator(config->defaults);
		
		while((name = wi_enumerator_next_data(enumerator))) {
//			instance = wi_mutable_copy(wi_dictionary_data_for_key(config->defaults, name));
			instance = wi_dictionary_data_for_key(config->defaults, name);
			if(wi_runtime_id(instance) == wi_array_runtime_id())
				instance = wi_autorelease(wi_mutable_copy(instance));
			wi_mutable_dictionary_set_data_for_key(config->values, instance, name);
//			wi_release(instance);
		}
	}
	
	while((string = wi_file_read_line(file))) {
		config->line++;

		if(wi_string_length(string) > 0 && !wi_string_has_prefix(string, WI_STR("#"))) {
			if(_wi_config_parse_string(config, string, &name, &value)) {
				instance = _wi_config_instance_for_setting(config, name, value, &type);
				
				if(instance) {
					wi_log_debug(WI_STR("  %@ = %@"), name, value);
					
					if(type == WI_CONFIG_STRINGLIST) {
						array = wi_dictionary_data_for_key(config->values, name);
						
						if(!array) {
							array = wi_mutable_array();
							
							wi_mutable_dictionary_set_data_for_key(config->values, array, name);
						}
						
						wi_mutable_array_add_data(array, instance);
					} else {
						wi_mutable_dictionary_set_data_for_key(config->values, instance, name);
					}
				} else {
					_wi_config_log_error(config, name);
				}
			} else {
				wi_error_set_libwired_error(WI_ERROR_SETTINGS_SYNTAXERROR);
				
				_wi_config_log_error(config, string);
			}
		}
	}
	
	enumerator = wi_dictionary_key_enumerator(config->values);
	
	while((name = wi_enumerator_next_data(enumerator))) {
		instance = wi_dictionary_data_for_key(config->values, name);
		
		if(!previous_values || !wi_is_equal(instance, wi_dictionary_data_for_key(previous_values, name)))
			wi_mutable_set_add_data(config->changes, name);
	}
	
	wi_release(previous_values);

	wi_lock_unlock(config->lock);

	return true;
}
Beispiel #27
0
static void wd_tracker_register(wd_tracker_t *tracker) {
	wi_enumerator_t		*enumerator;
	wi_address_t		*address;
	wi_array_t			*arguments;
	wi_string_t			*ip, *string;
	uint32_t			message;
	wi_boolean_t		fatal = false;
	
	if(!wi_lock_trylock(tracker->register_lock))
		return;

	enumerator = wi_array_data_enumerator(tracker->addresses);
	
	while((address = wi_enumerator_next_data(enumerator))) {
		tracker->active		= false;
		tracker->address	= NULL;
		ip					= wi_address_string(address);
		
		wi_log_info(WI_STR("Trying %@ for tracker %@..."),
			ip, tracker->host);
		
		tracker->socket = wi_autorelease(wi_socket_init_with_address(wi_socket_alloc(), address, WI_SOCKET_TCP));

		if(!tracker->socket) {
			wi_log_err(WI_STR("Could not create socket for tracker %@: %m"),
				tracker->host);
			
			continue;
		}

		if(!wi_socket_connect(tracker->socket, 30.0)) {
			wi_log_err(WI_STR("Could not connect to tracker %@: %m"),
				tracker->host);
			
			continue;
		}
		
		if(!wi_socket_connect_tls(tracker->socket, tracker->tls, 30.0)) {
			wi_log_err(WI_STR("Could not connect to tracker %@: %m"),
				tracker->host);
			
			continue;
		}
		
		if(!wd_tracker_write(tracker, WI_STR("HELLO")))
			continue;
		
		if(!wd_tracker_read(tracker, &message, &arguments))
			continue;
		
		if(message != 200) {
			string = wi_array_components_joined_by_string(arguments, WI_STR(" "));
			wi_log_err(WI_STR("Could not register with tracker %@: Unexpected reply \"%u %@\""),
				tracker->host, message, string);
			
			fatal = true;
			continue;
		}
		
		if(!wd_tracker_write(tracker, WI_STR("CLIENT %#@"), wd_server_version_string))
			continue;
		
		if(!wd_tracker_write(tracker, WI_STR("REGISTER %#@%c%#@%c%#@%c%u%c%#@"),
							 tracker->category,			WD_FIELD_SEPARATOR,
							 wd_settings.url,			WD_FIELD_SEPARATOR,
							 wd_settings.name,			WD_FIELD_SEPARATOR,
							 wd_settings.bandwidth,		WD_FIELD_SEPARATOR,
							 wd_settings.description))
			continue;
		
		
		if(!wd_tracker_read(tracker, &message, &arguments))
			continue;
		
		if(message != 700 || wi_array_count(arguments) < 1) {
			string = wi_array_components_joined_by_string(arguments, WI_STR(" "));
			wi_log_err(WI_STR("Could not register with tracker %@: Unexpected reply \"%u %@\""),
				tracker->host, message, string);
			
			break;
		}
		
		wi_release(tracker->key);
		tracker->key = wi_retain(WI_ARRAY(arguments, 0));
		
		tracker->public_key = wi_retain(wi_socket_ssl_public_key(tracker->socket));

		if(!tracker->public_key) {
			wi_log_err(WI_STR("Could not get public key from the tracker %@: %m"),
				tracker->host);
			
			break;
		}
		
		wi_log_info(WI_STR("Registered with the tracker %@"),
			tracker->host);
		
		tracker->active		= true;
		tracker->address	= address;
		
		break;
	}
	
	wi_lock_unlock(tracker->register_lock);
}
Beispiel #28
0
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);
}