1 /*
2  * uhub - A tiny ADC p2p connection hub
3  * Copyright (C) 2007-2014, Jan Vidar Krey
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "uhub.h"
21 
22 struct hub_info* g_hub = 0;
23 
24 /* FIXME: Flood control should be done in a plugin! */
25 #define CHECK_FLOOD(TYPE, WARN) \
26 	if (flood_control_check(&u->flood_ ## TYPE , hub->config->flood_ctl_  ## TYPE, hub->config->flood_ctl_interval, net_get_time()) &&  !auth_cred_is_unrestricted(u->credentials)) \
27 	{ \
28 		if (WARN) \
29 		{ \
30 			hub_send_flood_warning(hub, u, hub->config->msg_user_flood_ ## TYPE); \
31 		} \
32 		break; \
33 	}
34 
35 #define ROUTE_MSG \
36 	if (user_is_logged_in(u)) \
37 	{ \
38 		ret = route_message(hub, u, cmd); \
39 	} \
40 	else \
41 	{ \
42 		ret = -1; \
43 	} \
44 	break;
45 
hub_handle_message(struct hub_info * hub,struct hub_user * u,const char * line,size_t length)46 int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* line, size_t length)
47 {
48 	int ret = 0;
49 	struct adc_message* cmd = 0;
50 
51 	LOG_PROTO("recv %s: %s", sid_to_string(u->id.sid), line);
52 
53 	if (user_is_disconnecting(u))
54 		return -1;
55 
56 	cmd = adc_msg_parse_verify(u, line, length);
57 	if (cmd)
58 	{
59 		switch (cmd->cmd)
60 		{
61 			case ADC_CMD_HSUP:
62 				CHECK_FLOOD(extras, 0);
63 				ret = hub_handle_support(hub, u, cmd);
64 				break;
65 
66 			case ADC_CMD_HPAS:
67 				CHECK_FLOOD(extras, 0);
68 				ret = hub_handle_password(hub, u, cmd);
69 				break;
70 
71 			case ADC_CMD_BINF:
72 				CHECK_FLOOD(update, 1);
73 				ret = hub_handle_info(hub, u, cmd);
74 				break;
75 
76 			case ADC_CMD_DINF:
77 			case ADC_CMD_EINF:
78 			case ADC_CMD_FINF:
79 			case ADC_CMD_BQUI:
80 			case ADC_CMD_DQUI:
81 			case ADC_CMD_EQUI:
82 			case ADC_CMD_FQUI:
83 				/* these must never be allowed for security reasons, so we ignore them. */
84 				CHECK_FLOOD(extras, 1);
85 				break;
86 
87 			case ADC_CMD_EMSG:
88 			case ADC_CMD_DMSG:
89 			case ADC_CMD_BMSG:
90 			case ADC_CMD_FMSG:
91 				CHECK_FLOOD(chat, 1);
92 				ret = hub_handle_chat_message(hub, u, cmd);
93 				break;
94 
95 			case ADC_CMD_BSCH:
96 			case ADC_CMD_DSCH:
97 			case ADC_CMD_ESCH:
98 			case ADC_CMD_FSCH:
99 				cmd->priority = -1;
100 				if (plugin_handle_search(hub, u, cmd->cache) == st_deny)
101 					break;
102 				CHECK_FLOOD(search, 1);
103 				ROUTE_MSG;
104 
105 			case ADC_CMD_FRES: // spam
106 			case ADC_CMD_BRES: // spam
107 			case ADC_CMD_ERES: // pointless.
108 				CHECK_FLOOD(extras, 1);
109 				break;
110 
111 			case ADC_CMD_DRES:
112 				cmd->priority = -1;
113 				if (plugin_handle_search_result(hub, u, uman_get_user_by_sid(hub->users, cmd->target), cmd->cache) == st_deny)
114 					break;
115 				/* CHECK_FLOOD(search, 0); */
116 				ROUTE_MSG;
117 
118 			case ADC_CMD_DRCM:
119 				cmd->priority = -1;
120 				if (plugin_handle_revconnect(hub, u, uman_get_user_by_sid(hub->users, cmd->target)) == st_deny)
121 					break;
122 				CHECK_FLOOD(connect, 1);
123 				ROUTE_MSG;
124 
125 			case ADC_CMD_DCTM:
126 				cmd->priority = -1;
127 				if (plugin_handle_connect(hub, u, uman_get_user_by_sid(hub->users, cmd->target)) == st_deny)
128 					break;
129 				CHECK_FLOOD(connect, 1);
130 				ROUTE_MSG;
131 
132 			case ADC_CMD_BCMD:
133 			case ADC_CMD_DCMD:
134 			case ADC_CMD_ECMD:
135 			case ADC_CMD_FCMD:
136 			case ADC_CMD_HCMD:
137 				CHECK_FLOOD(extras, 1);
138 				break;
139 
140 			default:
141 				CHECK_FLOOD(extras, 1);
142 				ROUTE_MSG;
143 		}
144 		adc_msg_free(cmd);
145 	}
146 	else
147 	{
148 		if (!user_is_logged_in(u))
149 		{
150 			ret = -1;
151 		}
152 	}
153 
154 	return ret;
155 }
156 
157 
hub_handle_support(struct hub_info * hub,struct hub_user * u,struct adc_message * cmd)158 int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
159 {
160 	int ret = 0;
161 	int index = 0;
162 	int ok = 1;
163 	char* arg = adc_msg_get_argument(cmd, index);
164 
165 	if (hub->status == hub_status_disabled && u->state == state_protocol)
166 	{
167 		on_login_failure(hub, u, status_msg_hub_disabled);
168 		hub_free(arg);
169 		return -1;
170 	}
171 
172 	while (arg)
173 	{
174 		if (strlen(arg) == 6)
175 		{
176 			fourcc_t fourcc = FOURCC(arg[2], arg[3], arg[4], arg[5]);
177 			if (strncmp(arg, ADC_SUP_FLAG_ADD, 2) == 0)
178 			{
179 				user_support_add(u, fourcc);
180 			}
181 			else if (strncmp(arg, ADC_SUP_FLAG_REMOVE, 2) == 0)
182 			{
183 				user_support_remove(u, fourcc);
184 			}
185 			else
186 			{
187 				ok = 0;
188 			}
189 		}
190 		else
191 		{
192 			ok = 0;
193 		}
194 
195 		index++;
196 		hub_free(arg);
197 		arg = adc_msg_get_argument(cmd, index);
198 	}
199 
200 	if (u->state == state_protocol)
201 	{
202 		if (index == 0) ok = 0; /* Need to support *SOMETHING*, at least BASE */
203 		if (!ok)
204 		{
205 			/* disconnect user. Do not send crap during initial handshake! */
206 			hub_disconnect_user(hub, u, quit_logon_error);
207 			return -1;
208 		}
209 
210 		if (user_flag_get(u, feature_base))
211 		{
212 			/* User supports ADC/1.0 and a hash we know */
213 			if (user_flag_get(u, feature_tiger))
214 			{
215 				hub_send_handshake(hub, u);
216 				net_con_set_timeout(u->connection, TIMEOUT_HANDSHAKE);
217 			}
218 			else
219 			{
220 				// no common hash algorithm.
221 				hub_send_status(hub, u, status_msg_proto_no_common_hash, status_level_fatal);
222 				hub_disconnect_user(hub, u, quit_protocol_error);
223 			}
224 		}
225 		else if (user_flag_get(u, feature_bas0))
226 		{
227 			if (hub->config->obsolete_clients)
228 			{
229 				hub_send_handshake(hub, u);
230 				net_con_set_timeout(u->connection, TIMEOUT_HANDSHAKE);
231 			}
232 			else
233 			{
234 				/* disconnect user for using an obsolete client. */
235 				char* tmp = adc_msg_escape(hub->config->msg_proto_obsolete_adc0);
236 				struct adc_message* message = adc_msg_construct(ADC_CMD_IMSG, 6 + strlen(tmp));
237 				adc_msg_add_argument(message, tmp);
238 				hub_free(tmp);
239 				route_to_user(hub, u, message);
240 				adc_msg_free(message);
241 				hub_disconnect_user(hub, u, quit_protocol_error);
242 			}
243 		}
244 		else
245 		{
246 			/* Not speaking a compatible protocol - just disconnect. */
247 			hub_disconnect_user(hub, u, quit_logon_error);
248 		}
249 	}
250 
251 	return ret;
252 }
253 
254 
hub_handle_password(struct hub_info * hub,struct hub_user * u,struct adc_message * cmd)255 int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
256 {
257 	char* password = adc_msg_get_argument(cmd, 0);
258 	int ret = 0;
259 
260 	if (u->state == state_verify)
261 	{
262 		if (acl_password_verify(hub, u, password))
263 		{
264 			on_login_success(hub, u);
265 		}
266 		else
267 		{
268 			on_login_failure(hub, u, status_msg_auth_invalid_password);
269 			ret = -1;
270 		}
271 	}
272 
273 	hub_free(password);
274 	return ret;
275 }
276 
277 
hub_handle_chat_message(struct hub_info * hub,struct hub_user * u,struct adc_message * cmd)278 int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
279 {
280 	char* message = adc_msg_get_argument(cmd, 0);
281 	char* message_decoded = NULL;
282 	int ret = 0;
283 	int relay = 1;
284 	int broadcast;
285 	int private_msg;
286 	int command;
287 	int offset;
288 
289 	if (!message)
290 		return 0;
291 
292 	message_decoded = adc_msg_unescape(message);
293 	if (!message_decoded)
294 	{
295 		hub_free(message);
296 		return 0;
297 	}
298 
299 	if (!user_is_logged_in(u))
300 	{
301 		hub_free(message);
302 		return 0;
303 	}
304 
305 	broadcast = (cmd->cache[0] == 'B');
306 	private_msg = (cmd->cache[0] == 'D' || cmd->cache[0] == 'E');
307 	command = (message[0] == '!' || message[0] == '+');
308 
309 	if (broadcast && command)
310 	{
311 		/*
312 		 * A message such as "++message" is handled as "+message", by removing the first character.
313 		 * The first character is removed by memmoving the string one byte to the left.
314 		 */
315 		if (message[1] == message[0])
316 		{
317 			relay = 1;
318 			offset = adc_msg_get_arg_offset(cmd);
319 			memmove(cmd->cache+offset+1, cmd->cache+offset+2, cmd->length - offset);
320 			cmd->length--;
321 		}
322 		else
323 		{
324 			relay = command_invoke(hub->commands, u, message_decoded);
325 		}
326 	}
327 
328 	/* FIXME: Plugin should do this! */
329 	if (relay && (((hub->config->chat_is_privileged && !user_is_protected(u)) || (user_flag_get(u, flag_muted))) && broadcast))
330 	{
331 		relay = 0;
332 	}
333 
334 	if (relay)
335 	{
336 		plugin_st status = st_default;
337 		if (broadcast)
338 		{
339 			status = plugin_handle_chat_message(hub, u, message_decoded, 0);
340 		}
341 		else if (private_msg)
342 		{
343 			struct hub_user* target = uman_get_user_by_sid(hub->users, cmd->target);
344 			if (target)
345 				status = plugin_handle_private_message(hub, u, target, message_decoded, 0);
346 			else
347 				relay = 0;
348 		}
349 
350 		if (status == st_deny)
351 			relay = 0;
352 	}
353 
354 	if (relay)
355 	{
356 		/* adc_msg_remove_named_argument(cmd, "PM"); */
357 		if (broadcast)
358 		{
359 			plugin_log_chat_message(hub, u, message_decoded, 0);
360 		}
361 		ret = route_message(hub, u, cmd);
362 	}
363 	hub_free(message);
364 	hub_free(message_decoded);
365 	return ret;
366 }
367 
hub_send_support(struct hub_info * hub,struct hub_user * u)368 void hub_send_support(struct hub_info* hub, struct hub_user* u)
369 {
370 	if (user_is_connecting(u) || user_is_logged_in(u))
371 	{
372 		route_to_user(hub, u, hub->command_support);
373 	}
374 }
375 
376 
hub_send_sid(struct hub_info * hub,struct hub_user * u)377 void hub_send_sid(struct hub_info* hub, struct hub_user* u)
378 {
379 	sid_t sid;
380 	struct adc_message* command;
381 	if (user_is_connecting(u))
382 	{
383 		command = adc_msg_construct(ADC_CMD_ISID, 10);
384 		sid = uman_get_free_sid(hub->users, u);
385 		adc_msg_add_argument(command, (const char*) sid_to_string(sid));
386 		route_to_user(hub, u, command);
387 		adc_msg_free(command);
388 	}
389 }
390 
391 
hub_send_ping(struct hub_info * hub,struct hub_user * user)392 void hub_send_ping(struct hub_info* hub, struct hub_user* user)
393 {
394 	/* This will just send a newline, despite appearing to do more below. */
395 	struct adc_message* ping = adc_msg_construct(0, 0);
396 	ping->cache[0]     = '\n';
397 	ping->cache[1]     = 0;
398 	ping->length       = 1;
399 	ping->priority     = 1;
400 	route_to_user(hub, user, ping);
401 	adc_msg_free(ping);
402 }
403 
404 
hub_send_hubinfo(struct hub_info * hub,struct hub_user * u)405 void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u)
406 {
407 	struct adc_message* info = adc_msg_copy(hub->command_info);
408 	int value = 0;
409 	uint64_t size = 0;
410 
411 	if (user_flag_get(u, feature_ping))
412 	{
413 /*
414 		FIXME: These are missing:
415 		HH - Hub Host address ( DNS or IP )
416 		WS - Hub Website
417 		NE - Hub Network
418 		OW - Hub Owner name
419 */
420 		adc_msg_add_named_argument(info, "UC", uhub_itoa(hub_get_user_count(hub)));
421 		adc_msg_add_named_argument(info, "MC", uhub_itoa(hub_get_max_user_count(hub)));
422 		adc_msg_add_named_argument(info, "SS", uhub_ulltoa(hub_get_shared_size(hub)));
423 		adc_msg_add_named_argument(info, "SF", uhub_ulltoa(hub_get_shared_files(hub)));
424 
425 		/* Maximum/minimum share size */
426 		size = hub_get_max_share(hub);
427 		if (size) adc_msg_add_named_argument(info, "XS", uhub_ulltoa(size));
428 		size = hub_get_min_share(hub);
429 		if (size) adc_msg_add_named_argument(info, "MS", uhub_ulltoa(size));
430 
431 		/* Maximum/minimum upload slots allowed per user */
432 		value = hub_get_max_slots(hub);
433 		if (value) adc_msg_add_named_argument(info, "XL", uhub_itoa(value));
434 		value = hub_get_min_slots(hub);
435 		if (value) adc_msg_add_named_argument(info, "ML", uhub_itoa(value));
436 
437 		/* guest users must be on min/max hubs */
438 		value = hub_get_max_hubs_user(hub);
439 		if (value) adc_msg_add_named_argument(info, "XU", uhub_itoa(value));
440 		value = hub_get_min_hubs_user(hub);
441 		if (value) adc_msg_add_named_argument(info, "MU", uhub_itoa(value));
442 
443 		/* registered users must be on min/max hubs */
444 		value = hub_get_max_hubs_reg(hub);
445 		if (value) adc_msg_add_named_argument(info, "XR", uhub_itoa(value));
446 		value = hub_get_min_hubs_reg(hub);
447 		if (value) adc_msg_add_named_argument(info, "MR", uhub_itoa(value));
448 
449 		/* operators must be on min/max hubs */
450 		value = hub_get_max_hubs_op(hub);
451 		if (value) adc_msg_add_named_argument(info, "XO", uhub_itoa(value));
452 		value = hub_get_min_hubs_op(hub);
453 		if (value) adc_msg_add_named_argument(info, "MO", uhub_itoa(value));
454 
455 		/* uptime in seconds */
456 		adc_msg_add_named_argument(info, "UP", uhub_itoa((int) difftime(time(0), hub->tm_started)));
457 	}
458 
459 	if (user_is_connecting(u) || user_is_logged_in(u))
460 	{
461 		route_to_user(hub, u, info);
462 	}
463 	adc_msg_free(info);
464 
465 	/* Only send banner when connecting */
466 	if (hub->config->show_banner && user_is_connecting(u))
467 	{
468 		route_to_user(hub, u, hub->command_banner);
469 	}
470 }
471 
hub_send_handshake(struct hub_info * hub,struct hub_user * u)472 void hub_send_handshake(struct hub_info* hub, struct hub_user* u)
473 {
474 	user_flag_set(u, flag_pipeline);
475 	hub_send_support(hub, u);
476 	hub_send_sid(hub, u);
477 	hub_send_hubinfo(hub, u);
478 	route_flush_pipeline(hub, u);
479 
480 	if (!user_is_disconnecting(u))
481 	{
482 		user_set_state(u, state_identify);
483 	}
484 }
485 
hub_send_password_challenge(struct hub_info * hub,struct hub_user * u)486 void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u)
487 {
488 	struct adc_message* igpa;
489 	igpa = adc_msg_construct(ADC_CMD_IGPA, 38);
490 	adc_msg_add_argument(igpa, acl_password_generate_challenge(hub, u));
491 	user_set_state(u, state_verify);
492 	route_to_user(hub, u, igpa);
493 	adc_msg_free(igpa);
494 }
495 
hub_send_flood_warning(struct hub_info * hub,struct hub_user * u,const char * message)496 void hub_send_flood_warning(struct hub_info* hub, struct hub_user* u, const char* message)
497 {
498 	struct adc_message* msg;
499 	char* tmp;
500 
501 	if (user_flag_get(u, flag_flood))
502 		return;
503 
504 	msg = adc_msg_construct(ADC_CMD_ISTA, 128);
505 	if (msg)
506 	{
507 		tmp = adc_msg_escape(message);
508 		adc_msg_add_argument(msg, "110");
509 		adc_msg_add_argument(msg, tmp);
510 		hub_free(tmp);
511 
512 		route_to_user(hub, u, msg);
513 		user_flag_set(u, flag_flood);
514 		adc_msg_free(msg);
515 	}
516 }
517 
check_duplicate_logins_ok(struct hub_info * hub,struct hub_user * user)518 static int check_duplicate_logins_ok(struct hub_info* hub, struct hub_user* user)
519 {
520 	struct hub_user* lookup1;
521 	struct hub_user* lookup2;
522 
523 	lookup1 = uman_get_user_by_nick(hub->users, user->id.nick);
524 	if (lookup1)
525 		return status_msg_inf_error_nick_taken;
526 
527 	lookup2 = uman_get_user_by_cid(hub->users, user->id.cid);
528 	if (lookup2)
529 		return status_msg_inf_error_cid_taken;
530 
531 	return 0;
532 }
533 
hub_event_dispatcher(void * callback_data,struct event_data * message)534 static void hub_event_dispatcher(void* callback_data, struct event_data* message)
535 {
536 	int status;
537 	struct hub_info* hub = (struct hub_info*) callback_data;
538 	struct hub_user* user = (struct hub_user*) message->ptr;
539 	uhub_assert(hub != NULL);
540 
541 	switch (message->id)
542 	{
543 		case UHUB_EVENT_USER_JOIN:
544 		{
545 			if (user_is_disconnecting(user))
546 				break;
547 
548 			if (message->flags)
549 			{
550 				hub_send_password_challenge(hub, user);
551 			}
552 			else
553 			{
554 				/* Race condition, we could have two messages for two logins queued up.
555 				   So make sure we don't let the second client in. */
556 				status = check_duplicate_logins_ok(hub, user);
557 				if (!status)
558 				{
559 					on_login_success(hub, user);
560 				}
561 				else
562 				{
563 					on_login_failure(hub, user, (enum status_message) status);
564 				}
565 			}
566 			break;
567 		}
568 
569 		case UHUB_EVENT_USER_QUIT:
570 		{
571 			uman_remove(hub->users, user);
572 			uman_send_quit_message(hub, hub->users, user);
573 			on_logout_user(hub, user);
574 			hub_schedule_destroy_user(hub, user);
575 			break;
576 		}
577 
578 		case UHUB_EVENT_USER_DESTROY:
579 		{
580 			user_destroy(user);
581 			break;
582 		}
583 
584 		case UHUB_EVENT_HUB_SHUTDOWN:
585 		{
586 			struct hub_user* u = (struct hub_user*) list_get_first(hub->users->list);
587 			while (u)
588 			{
589 				uman_remove(hub->users, u);
590 				user_destroy(u);
591 				u = (struct hub_user*) list_get_first(hub->users->list);
592 			}
593 			break;
594 		}
595 
596 
597 		default:
598 			/* FIXME: ignored */
599 			break;
600 	}
601 }
602 
603 
hub_update_stats(struct hub_info * hub)604 static void hub_update_stats(struct hub_info* hub)
605 {
606 	const int factor = TIMEOUT_STATS;
607 	struct net_statistics* total;
608 	struct net_statistics* intermediate;
609 	net_stats_get(&intermediate, &total);
610 
611 	hub->stats.net_tx = (intermediate->tx / factor);
612 	hub->stats.net_rx = (intermediate->rx / factor);
613 	hub->stats.net_tx_peak = MAX(hub->stats.net_tx, hub->stats.net_tx_peak);
614 	hub->stats.net_rx_peak = MAX(hub->stats.net_rx, hub->stats.net_rx_peak);
615 	hub->stats.net_tx_total = total->tx;
616 	hub->stats.net_rx_total = total->rx;
617 
618 	net_stats_reset();
619 }
620 
hub_timer_statistics(struct timeout_evt * t)621 static void hub_timer_statistics(struct timeout_evt* t)
622 {
623 	struct hub_info* hub = (struct hub_info*) t->ptr;
624 	hub_update_stats(hub);
625 	timeout_queue_reschedule(net_backend_get_timeout_queue(), hub->stats.timeout, TIMEOUT_STATS);
626 }
627 
start_listening_socket(const char * bind_addr,uint16_t port,int backlog,struct hub_info * hub)628 static struct net_connection* start_listening_socket(const char* bind_addr, uint16_t port, int backlog, struct hub_info* hub)
629 {
630 	struct net_connection* server;
631 	struct sockaddr_storage addr;
632 	socklen_t sockaddr_size;
633 	int sd, ret;
634 
635 	if (ip_convert_address(bind_addr, port, (struct sockaddr*) &addr, &sockaddr_size) == -1)
636 	{
637 		return 0;
638 	}
639 
640 	sd = net_socket_create(addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
641 	if (sd == -1)
642 	{
643 		return 0;
644 	}
645 
646 	if ((net_set_reuseaddress(sd, 1) == -1) || (net_set_nonblocking(sd, 1) == -1))
647 	{
648 		net_close(sd);
649 		return 0;
650 	}
651 
652 	ret = net_bind(sd, (struct sockaddr*) &addr, sockaddr_size);
653 	if (ret == -1)
654 	{
655 		LOG_ERROR("hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
656 		net_close(sd);
657 		return 0;
658 	}
659 
660 	ret = net_listen(sd, backlog);
661 	if (ret == -1)
662 	{
663 		LOG_ERROR("hub_start_service(): Unable to listen to socket");
664 		net_close(sd);
665 		return 0;
666 	}
667 
668 	server = net_con_create();
669 	net_con_initialize(server, sd, net_on_accept, hub, NET_EVENT_READ);
670 
671 	return server;
672 }
673 
674 struct server_alt_port_data
675 {
676 	struct hub_info* hub;
677 	struct hub_config* config;
678 };
679 
server_alt_port_start_one(char * line,int count,void * ptr)680 static int server_alt_port_start_one(char* line, int count, void* ptr)
681 {
682 	struct server_alt_port_data* data = (struct server_alt_port_data*) ptr;
683 
684 	int port = uhub_atoi(line);
685 	struct net_connection* con = start_listening_socket(data->config->server_bind_addr, port, data->config->server_listen_backlog, data->hub);
686 	if (con)
687 	{
688 		list_append(data->hub->server_alt_ports, con);
689 		LOG_INFO("Listening on alternate port %d...", port);
690 		return 0;
691 	}
692 	return -1;
693 }
694 
server_alt_port_start(struct hub_info * hub,struct hub_config * config)695 static void server_alt_port_start(struct hub_info* hub, struct hub_config* config)
696 {
697 	struct server_alt_port_data data;
698 
699 	if (!config->server_alt_ports || !*config->server_alt_ports)
700 		return;
701 
702 	hub->server_alt_ports = (struct linked_list*) list_create();
703 
704 	data.hub = hub;
705 	data.config = config;
706 
707 	string_split(config->server_alt_ports, ",", &data, server_alt_port_start_one);
708 }
709 
server_alt_port_clear(void * ptr)710 static void server_alt_port_clear(void* ptr)
711 {
712 	struct net_connection* con = (struct net_connection*) ptr;
713 	if (con)
714 	{
715 		net_con_close(con);
716 		hub_free(con);
717 	}
718 }
719 
server_alt_port_stop(struct hub_info * hub)720 static void server_alt_port_stop(struct hub_info* hub)
721 {
722 	if (hub->server_alt_ports)
723 	{
724 		list_clear(hub->server_alt_ports, &server_alt_port_clear);
725 		list_destroy(hub->server_alt_ports);
726 	}
727 }
728 
729 #ifdef SSL_SUPPORT
load_ssl_certificates(struct hub_info * hub,struct hub_config * config)730 static int load_ssl_certificates(struct hub_info* hub, struct hub_config* config)
731 {
732 	if (config->tls_enable)
733 	{
734 		hub->ctx = net_ssl_context_create(config->tls_version, config->tls_ciphersuite);
735 
736 		if (!hub->ctx)
737 		  return 0;
738 
739 		if (ssl_load_certificate(hub->ctx, config->tls_certificate) &&
740 			ssl_load_private_key(hub->ctx, config->tls_private_key) &&
741 			ssl_check_private_key(hub->ctx))
742 		{
743 			LOG_INFO("Enabling TLS (%s), using certificate: %s, private key: %s", net_ssl_get_provider(), config->tls_certificate, config->tls_private_key);
744 			return 1;
745 		}
746 		return 0;
747 	}
748 	return 1;
749 }
750 
unload_ssl_certificates(struct hub_info * hub)751 static void unload_ssl_certificates(struct hub_info* hub)
752 {
753 	if (hub->ctx)
754 		net_ssl_context_destroy(hub->ctx);
755 }
756 #endif /* SSL_SUPPORT */
757 
hub_start_service(struct hub_config * config)758 struct hub_info* hub_start_service(struct hub_config* config)
759 {
760 	struct hub_info* hub = 0;
761 	int ipv6_supported;
762 
763 	hub = hub_malloc_zero(sizeof(struct hub_info));
764 	if (!hub)
765 	{
766 		LOG_FATAL("Unable to allocate memory for hub");
767 		return 0;
768 	}
769 
770 	hub->tm_started = time(0);
771 	ipv6_supported = net_is_ipv6_supported();
772 	if (ipv6_supported)
773 		LOG_DEBUG("IPv6 supported.");
774 	else
775 		LOG_DEBUG("IPv6 not supported.");
776 
777 	hub->server = start_listening_socket(config->server_bind_addr, config->server_port, config->server_listen_backlog, hub);
778 	if (!hub->server)
779 	{
780 		hub_free(hub);
781 		LOG_FATAL("Unable to start hub service");
782 		return 0;
783 	}
784 	LOG_INFO("Starting " PRODUCT "/" VERSION ", listening on %s:%d...", net_get_local_address(hub->server->sd), config->server_port);
785 
786 #ifdef SSL_SUPPORT
787 	if (!load_ssl_certificates(hub, config))
788 	{
789 		hub_free(hub);
790 		return 0;
791 	}
792 #endif
793 
794 	hub->config = config;
795 	hub->users = NULL;
796 
797 	hub->users = uman_init();
798 	if (!hub->users)
799 	{
800 		net_con_close(hub->server);
801 		hub_free(hub);
802 		return 0;
803 	}
804 
805 	if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1)
806 	{
807 		net_con_close(hub->server);
808 		uman_shutdown(hub->users);
809 		hub_free(hub);
810 		return 0;
811 	}
812 
813 	hub->recvbuf = hub_malloc(MAX_RECV_BUF);
814 	hub->sendbuf = hub_malloc(MAX_SEND_BUF);
815 	if (!hub->recvbuf || !hub->sendbuf)
816 	{
817 		net_con_close(hub->server);
818 		hub_free(hub->recvbuf);
819 		hub_free(hub->sendbuf);
820 		uman_shutdown(hub->users);
821 		hub_free(hub);
822 		return 0;
823 	}
824 
825 	hub->logout_info  = (struct linked_list*) list_create();
826 	server_alt_port_start(hub, config);
827 
828 	hub->status = hub_status_running;
829 
830 	g_hub = hub;
831 
832 	if (net_backend_get_timeout_queue())
833 	{
834 		hub->stats.timeout = hub_malloc_zero(sizeof(struct timeout_evt));
835 		timeout_evt_initialize(hub->stats.timeout, hub_timer_statistics, hub);
836 		timeout_queue_insert(net_backend_get_timeout_queue(), hub->stats.timeout, TIMEOUT_STATS);
837 	}
838 
839 	// Start the hub command sub-system
840 	hub->commands = command_initialize(hub);
841 	return hub;
842 }
843 
844 
hub_shutdown_service(struct hub_info * hub)845 void hub_shutdown_service(struct hub_info* hub)
846 {
847 	LOG_DEBUG("hub_shutdown_service()");
848 
849 	if (net_backend_get_timeout_queue())
850 	{
851 		timeout_queue_remove(net_backend_get_timeout_queue(), hub->stats.timeout);
852 		hub_free(hub->stats.timeout);
853 	}
854 
855 #ifdef SSL_SUPPORT
856 	unload_ssl_certificates(hub);
857 #endif
858 
859 	event_queue_shutdown(hub->queue);
860 	net_con_close(hub->server);
861 	server_alt_port_stop(hub);
862 	uman_shutdown(hub->users);
863 	hub->status = hub_status_stopped;
864 	hub_free(hub->sendbuf);
865 	hub_free(hub->recvbuf);
866 	list_clear(hub->logout_info, &hub_free);
867 	list_destroy(hub->logout_info);
868 	command_shutdown(hub->commands);
869 	hub_free(hub);
870 	hub = 0;
871 	g_hub = 0;
872 }
873 
hub_plugins_load(struct hub_info * hub)874 int hub_plugins_load(struct hub_info* hub)
875 {
876 	if (!hub->config->file_plugins || !*hub->config->file_plugins)
877 		return 0;
878 
879 	hub->plugins = hub_malloc_zero(sizeof(struct uhub_plugins));
880 	if (!hub->plugins)
881 		return -1;
882 
883 	if (plugin_initialize(hub->config, hub) < 0)
884 	{
885 		hub_free(hub->plugins);
886 		hub->plugins = 0;
887 		return -1;
888 	}
889 	return 0;
890 }
891 
hub_plugins_unload(struct hub_info * hub)892 void hub_plugins_unload(struct hub_info* hub)
893 {
894 	if (hub->plugins)
895 	{
896 		plugin_shutdown(hub->plugins);
897 		hub_free(hub->plugins);
898 		hub->plugins = 0;
899 	}
900 }
901 
hub_set_variables(struct hub_info * hub,struct acl_handle * acl)902 void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
903 {
904 	char* tmp;
905 	char* server = adc_msg_escape(PRODUCT_STRING); /* FIXME: OOM */
906 
907 	hub->acl = acl;
908 	hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15);
909 	if (hub->command_info)
910 	{
911 		adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_HUB);
912 		adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT_PRODUCT, PRODUCT);
913 		adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT_VERSION, GIT_VERSION);
914 
915 		tmp = adc_msg_escape(hub->config->hub_name);
916 		adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_NICK, tmp);
917 		hub_free(tmp);
918 
919 		tmp = adc_msg_escape(hub->config->hub_description);
920 		adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, tmp);
921 		hub_free(tmp);
922 	}
923 
924 	hub->command_support = adc_msg_construct(ADC_CMD_ISUP, 6 + strlen(ADC_PROTO_SUPPORT));
925 	if (hub->command_support)
926 	{
927 		adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT);
928 	}
929 
930 	hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 100 + strlen(server));
931 	if (hub->command_banner)
932 	{
933 		if (hub->config->show_banner_sys_info)
934 			tmp = adc_msg_escape("Powered by " PRODUCT_STRING " on " OPSYS "/" CPUINFO);
935 		else
936 			tmp = adc_msg_escape("Powered by " PRODUCT_STRING);
937 		adc_msg_add_argument(hub->command_banner, "000");
938 		adc_msg_add_argument(hub->command_banner, tmp);
939 		hub_free(tmp);
940 	}
941 
942 	if (hub_plugins_load(hub) < 0)
943 	{
944 		LOG_FATAL("Unable to load plugins.");
945 		hub->status = hub_status_shutdown;
946 	}
947 	else
948 
949 	hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
950 	hub_free(server);
951 }
952 
953 
hub_free_variables(struct hub_info * hub)954 void hub_free_variables(struct hub_info* hub)
955 {
956 	hub_plugins_unload(hub);
957 
958 	adc_msg_free(hub->command_info);
959 	adc_msg_free(hub->command_banner);
960 	adc_msg_free(hub->command_support);
961 }
962 
set_status_code(enum msg_status_level level,int code,char buffer[4])963 static void set_status_code(enum msg_status_level level, int code, char buffer[4])
964 {
965 	buffer[0] = ('0' + (int) level);
966 	buffer[1] = ('0' + (code / 10));
967 	buffer[2] = ('0' + (code % 10));
968 	buffer[3] = 0;
969 }
970 
971 /**
972  * @param hub The hub instance this message is sent from.
973  * @param user The user this message is sent to.
974  * @param msg See enum status_message
975  * @param level See enum status_level
976  */
hub_send_status(struct hub_info * hub,struct hub_user * user,enum status_message msg,enum msg_status_level level)977 void hub_send_status(struct hub_info* hub, struct hub_user* user, enum status_message msg, enum msg_status_level level)
978 {
979 	struct hub_config* cfg = hub->config;
980 	struct adc_message* cmd = adc_msg_construct(ADC_CMD_ISTA, 6);
981 	struct adc_message* qui = adc_msg_construct(ADC_CMD_IQUI, 512);
982 	char code[4];
983 	char buf[256];
984 	const char* text = 0;
985 	const char* flag = 0;
986 	char* escaped_text = 0;
987 	int reconnect_time = 0;
988 	int redirect = 0;
989 
990 	if (!cmd || !qui)
991 	{
992 		adc_msg_free(cmd);
993 		adc_msg_free(qui);
994 		return;
995 	}
996 
997 #define STATUS(CODE, MSG, FLAG, RCONTIME, REDIRECT) case status_ ## MSG : set_status_code(level, CODE, code); text = cfg->MSG; flag = FLAG; reconnect_time = RCONTIME; redirect = REDIRECT; break
998 	switch (msg)
999 	{
1000 		STATUS(11, msg_hub_full, 0, 600, 1); /* FIXME: Proper timeout? */
1001 		STATUS(12, msg_hub_disabled, 0, -1, 1);
1002 		STATUS(26, msg_hub_registered_users_only, 0, 0, 1);
1003 		STATUS(43, msg_inf_error_nick_missing, 0, 0, 0);
1004 		STATUS(43, msg_inf_error_nick_multiple, 0, 0, 0);
1005 		STATUS(21, msg_inf_error_nick_invalid, 0, 0, 0);
1006 		STATUS(21, msg_inf_error_nick_long, 0, 0, 0);
1007 		STATUS(21, msg_inf_error_nick_short, 0, 0, 0);
1008 		STATUS(21, msg_inf_error_nick_spaces, 0, 0, 0);
1009 		STATUS(21, msg_inf_error_nick_bad_chars, 0, 0, 0);
1010 		STATUS(21, msg_inf_error_nick_not_utf8, 0, 0, 0);
1011 		STATUS(22, msg_inf_error_nick_taken, 0, 0, 0);
1012 		STATUS(21, msg_inf_error_nick_restricted, 0, 0, 0);
1013 		STATUS(43, msg_inf_error_cid_invalid, "FBID", 0, 0);
1014 		STATUS(43, msg_inf_error_cid_missing, "FMID", 0, 0);
1015 		STATUS(24, msg_inf_error_cid_taken, 0, 0, 0);
1016 		STATUS(43, msg_inf_error_pid_missing, "FMPD", 0, 0);
1017 		STATUS(27, msg_inf_error_pid_invalid, "FBPD", 0, 0);
1018 		STATUS(31, msg_ban_permanently, 0, 0, 0);
1019 		STATUS(32, msg_ban_temporarily, "TL600", 600, 0); /* FIXME: Proper timeout? */
1020 		STATUS(23, msg_auth_invalid_password, 0, 0, 0);
1021 		STATUS(20, msg_auth_user_not_found, 0, 0, 0);
1022 		STATUS(30, msg_error_no_memory, 0, 0, 0);
1023 		STATUS(43, msg_user_share_size_low,   "FB" ADC_INF_FLAG_SHARED_SIZE, 0, 1);
1024 		STATUS(43, msg_user_share_size_high,  "FB" ADC_INF_FLAG_SHARED_SIZE, 0, 1);
1025 		STATUS(43, msg_user_slots_low,        "FB" ADC_INF_FLAG_UPLOAD_SLOTS, 0, 1);
1026 		STATUS(43, msg_user_slots_high,       "FB" ADC_INF_FLAG_UPLOAD_SLOTS, 0, 1);
1027 		STATUS(43, msg_user_hub_limit_low, 0, 0, 1);
1028 		STATUS(43, msg_user_hub_limit_high, 0, 0, 1);
1029 		STATUS(47, msg_proto_no_common_hash, 0, -1, 1);
1030 		STATUS(40, msg_proto_obsolete_adc0, 0, -1, 1);
1031 	}
1032 #undef STATUS
1033 
1034 	escaped_text = adc_msg_escape(text);
1035 
1036 	adc_msg_add_argument(cmd, code);
1037 	adc_msg_add_argument(cmd, escaped_text);
1038 
1039 	if (flag)
1040 	{
1041 		adc_msg_add_argument(cmd, flag);
1042 	}
1043 
1044 	route_to_user(hub, user, cmd);
1045 
1046 	if (level >= status_level_fatal)
1047 	{
1048 		adc_msg_add_argument(qui, sid_to_string(user->id.sid));
1049 
1050 		snprintf(buf, 230, "MS%s", escaped_text);
1051 		adc_msg_add_argument(qui, buf);
1052 
1053 		if (reconnect_time != 0)
1054 		{
1055 			snprintf(buf, 10, "TL%d", reconnect_time);
1056 			adc_msg_add_argument(qui, buf);
1057 		}
1058 
1059 		if (redirect && *hub->config->redirect_addr)
1060 		{
1061 			snprintf(buf, 255, "RD%s", hub->config->redirect_addr);
1062 			adc_msg_add_argument(qui, buf);
1063 		}
1064 		route_to_user(hub, user, qui);
1065 	}
1066 
1067 	hub_free(escaped_text);
1068 	adc_msg_free(cmd);
1069 	adc_msg_free(qui);
1070 }
1071 
hub_get_status_message(struct hub_info * hub,enum status_message msg)1072 const char* hub_get_status_message(struct hub_info* hub, enum status_message msg)
1073 {
1074 #define STATUS(MSG) case status_ ## MSG : return cfg->MSG; break
1075 	struct hub_config* cfg = hub->config;
1076 	switch (msg)
1077 	{
1078 		STATUS(msg_hub_full);
1079 		STATUS(msg_hub_disabled);
1080 		STATUS(msg_hub_registered_users_only);
1081 		STATUS(msg_inf_error_nick_missing);
1082 		STATUS(msg_inf_error_nick_multiple);
1083 		STATUS(msg_inf_error_nick_invalid);
1084 		STATUS(msg_inf_error_nick_long);
1085 		STATUS(msg_inf_error_nick_short);
1086 		STATUS(msg_inf_error_nick_spaces);
1087 		STATUS(msg_inf_error_nick_bad_chars);
1088 		STATUS(msg_inf_error_nick_not_utf8);
1089 		STATUS(msg_inf_error_nick_taken);
1090 		STATUS(msg_inf_error_nick_restricted);
1091 		STATUS(msg_inf_error_cid_invalid);
1092 		STATUS(msg_inf_error_cid_missing);
1093 		STATUS(msg_inf_error_cid_taken);
1094 		STATUS(msg_inf_error_pid_missing);
1095 		STATUS(msg_inf_error_pid_invalid);
1096 		STATUS(msg_ban_permanently);
1097 		STATUS(msg_ban_temporarily);
1098 		STATUS(msg_auth_invalid_password);
1099 		STATUS(msg_auth_user_not_found);
1100 		STATUS(msg_error_no_memory);
1101 		STATUS(msg_user_share_size_low);
1102 		STATUS(msg_user_share_size_high);
1103 		STATUS(msg_user_slots_low);
1104 		STATUS(msg_user_slots_high);
1105 		STATUS(msg_user_hub_limit_low);
1106 		STATUS(msg_user_hub_limit_high);
1107 		STATUS(msg_proto_no_common_hash);
1108 		STATUS(msg_proto_obsolete_adc0);
1109 	}
1110 #undef STATUS
1111 	return "Unknown";
1112 }
1113 
hub_get_status_message_log(struct hub_info * hub,enum status_message msg)1114 const char* hub_get_status_message_log(struct hub_info* hub, enum status_message msg)
1115 {
1116 #define STATUS(MSG) case status_ ## MSG : return #MSG; break
1117 	switch (msg)
1118 	{
1119 		STATUS(msg_hub_full);
1120 		STATUS(msg_hub_disabled);
1121 		STATUS(msg_hub_registered_users_only);
1122 		STATUS(msg_inf_error_nick_missing);
1123 		STATUS(msg_inf_error_nick_multiple);
1124 		STATUS(msg_inf_error_nick_invalid);
1125 		STATUS(msg_inf_error_nick_long);
1126 		STATUS(msg_inf_error_nick_short);
1127 		STATUS(msg_inf_error_nick_spaces);
1128 		STATUS(msg_inf_error_nick_bad_chars);
1129 		STATUS(msg_inf_error_nick_not_utf8);
1130 		STATUS(msg_inf_error_nick_taken);
1131 		STATUS(msg_inf_error_nick_restricted);
1132 		STATUS(msg_inf_error_cid_invalid);
1133 		STATUS(msg_inf_error_cid_missing);
1134 		STATUS(msg_inf_error_cid_taken);
1135 		STATUS(msg_inf_error_pid_missing);
1136 		STATUS(msg_inf_error_pid_invalid);
1137 		STATUS(msg_ban_permanently);
1138 		STATUS(msg_ban_temporarily);
1139 		STATUS(msg_auth_invalid_password);
1140 		STATUS(msg_auth_user_not_found);
1141 		STATUS(msg_error_no_memory);
1142 		STATUS(msg_user_share_size_low);
1143 		STATUS(msg_user_share_size_high);
1144 		STATUS(msg_user_slots_low);
1145 		STATUS(msg_user_slots_high);
1146 		STATUS(msg_user_hub_limit_low);
1147 		STATUS(msg_user_hub_limit_high);
1148 		STATUS(msg_proto_no_common_hash);
1149 		STATUS(msg_proto_obsolete_adc0);
1150 	}
1151 #undef STATUS
1152 	return "unknown";
1153 }
1154 
1155 
hub_get_user_count(struct hub_info * hub)1156 size_t hub_get_user_count(struct hub_info* hub)
1157 {
1158 	return hub->users->count;
1159 }
1160 
hub_get_max_user_count(struct hub_info * hub)1161 size_t hub_get_max_user_count(struct hub_info* hub)
1162 {
1163 	return hub->config->max_users;
1164 }
1165 
hub_get_shared_size(struct hub_info * hub)1166 uint64_t hub_get_shared_size(struct hub_info* hub)
1167 {
1168 	return hub->users->shared_size;
1169 }
1170 
hub_get_shared_files(struct hub_info * hub)1171 uint64_t hub_get_shared_files(struct hub_info* hub)
1172 {
1173 	return hub->users->shared_files;
1174 }
1175 
hub_get_min_share(struct hub_info * hub)1176 uint64_t hub_get_min_share(struct hub_info* hub)
1177 {
1178 	uint64_t size = hub->config->limit_min_share;
1179 	size *= (1024 * 1024);
1180 	return size;
1181 }
1182 
hub_get_max_share(struct hub_info * hub)1183 uint64_t hub_get_max_share(struct hub_info* hub)
1184 {
1185         uint64_t size = hub->config->limit_max_share;
1186         size *= (1024 * 1024);
1187         return size;
1188 }
1189 
hub_get_min_slots(struct hub_info * hub)1190 size_t hub_get_min_slots(struct hub_info* hub)
1191 {
1192 	return hub->config->limit_min_slots;
1193 }
1194 
hub_get_max_slots(struct hub_info * hub)1195 size_t hub_get_max_slots(struct hub_info* hub)
1196 {
1197 	return hub->config->limit_max_slots;
1198 }
1199 
hub_get_max_hubs_total(struct hub_info * hub)1200 size_t hub_get_max_hubs_total(struct hub_info* hub)
1201 {
1202 	return hub->config->limit_max_hubs;
1203 }
1204 
hub_get_max_hubs_user(struct hub_info * hub)1205 size_t hub_get_max_hubs_user(struct hub_info* hub)
1206 {
1207 	return hub->config->limit_max_hubs_user;
1208 }
1209 
hub_get_min_hubs_user(struct hub_info * hub)1210 size_t hub_get_min_hubs_user(struct hub_info* hub)
1211 {
1212 	return hub->config->limit_min_hubs_user;
1213 }
1214 
hub_get_max_hubs_reg(struct hub_info * hub)1215 size_t hub_get_max_hubs_reg(struct hub_info* hub)
1216 {
1217 	return hub->config->limit_max_hubs_reg;
1218 }
1219 
hub_get_min_hubs_reg(struct hub_info * hub)1220 size_t hub_get_min_hubs_reg(struct hub_info* hub)
1221 {
1222 	return hub->config->limit_min_hubs_reg;
1223 }
1224 
hub_get_max_hubs_op(struct hub_info * hub)1225 size_t hub_get_max_hubs_op(struct hub_info* hub)
1226 {
1227 	return hub->config->limit_max_hubs_op;
1228 }
1229 
hub_get_min_hubs_op(struct hub_info * hub)1230 size_t hub_get_min_hubs_op(struct hub_info* hub)
1231 {
1232 	return hub->config->limit_min_hubs_op;
1233 }
1234 
hub_schedule_destroy_user(struct hub_info * hub,struct hub_user * user)1235 void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user)
1236 {
1237 	struct event_data post;
1238 	memset(&post, 0, sizeof(post));
1239 	post.id = UHUB_EVENT_USER_DESTROY;
1240 	post.ptr = user;
1241 	event_queue_post(hub->queue, &post);
1242 
1243 	if (user->id.sid)
1244 	{
1245 		sid_free(hub->users->sids, user->id.sid);
1246 	}
1247 }
1248 
hub_disconnect_all(struct hub_info * hub)1249 void hub_disconnect_all(struct hub_info* hub)
1250 {
1251 	struct event_data post;
1252 	memset(&post, 0, sizeof(post));
1253 	post.id = UHUB_EVENT_HUB_SHUTDOWN;
1254 	post.ptr = 0;
1255 	event_queue_post(hub->queue, &post);
1256 }
1257 
hub_event_loop(struct hub_info * hub)1258 void hub_event_loop(struct hub_info* hub)
1259 {
1260 	do
1261 	{
1262 		net_backend_process();
1263 		event_queue_process(hub->queue);
1264 	}
1265 	while (hub->status == hub_status_running || hub->status == hub_status_disabled);
1266 
1267 
1268 	if (hub->status == hub_status_shutdown)
1269 	{
1270 		LOG_DEBUG("Removing all users...");
1271 		event_queue_process(hub->queue);
1272 		event_queue_process(hub->queue);
1273 		hub_disconnect_all(hub);
1274 		event_queue_process(hub->queue);
1275 		hub->status = hub_status_stopped;
1276 	}
1277 }
1278 
1279 
hub_disconnect_user(struct hub_info * hub,struct hub_user * user,int reason)1280 void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason)
1281 {
1282 	struct event_data post;
1283 	int need_notify = 0;
1284 
1285 	/* is user already being disconnected ? */
1286 	if (user_is_disconnecting(user))
1287 	{
1288 		return;
1289 	}
1290 
1291 	/* stop reading from user */
1292 	net_shutdown_r(net_con_get_sd(user->connection));
1293 	net_con_close(user->connection);
1294 	user->connection = 0;
1295 
1296 	LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state);
1297 
1298 	need_notify = user_is_logged_in(user) && hub->status == hub_status_running;
1299 	user->quit_reason = reason;
1300 	user_set_state(user, state_cleanup);
1301 
1302 	if (need_notify)
1303 	{
1304 		memset(&post, 0, sizeof(post));
1305 		post.id     = UHUB_EVENT_USER_QUIT;
1306 		post.ptr    = user;
1307 		event_queue_post(hub->queue, &post);
1308 	}
1309 	else
1310 	{
1311 		hub_schedule_destroy_user(hub, user);
1312 	}
1313 }
1314 
hub_logout_log(struct hub_info * hub,struct hub_user * user)1315 void hub_logout_log(struct hub_info* hub, struct hub_user* user)
1316 {
1317 	struct hub_logout_info* loginfo = hub_malloc_zero(sizeof(struct hub_logout_info));
1318 	if (!loginfo) return;
1319 	loginfo->time = time(NULL);
1320 	memcpy(loginfo->cid, user->id.cid, sizeof(loginfo->cid));
1321 	memcpy(loginfo->nick, user->id.nick, sizeof(loginfo->nick));
1322 	memcpy(&loginfo->addr, &user->id.addr, sizeof(struct ip_addr_encap));
1323 	loginfo->reason = user->quit_reason;
1324 
1325 	list_append(hub->logout_info, loginfo);
1326 	while (list_size(hub->logout_info) > (size_t) hub->config->max_logout_log)
1327 	{
1328 		list_remove_first(hub->logout_info, hub_free);
1329 	}
1330 }
1331 
1332