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 "tools/adcclient.h"
21 
22 #define ADC_HANDSHAKE "HSUP ADBASE ADTIGR ADPING\n"
23 #define ADC_CID_SIZE 39
24 #define BIG_BUFSIZE 32768
25 #define TIGERSIZE 24
26 #define MAX_RECV_BUFFER 65536
27 
28 // #define ADCC_DEBUG
29 // #define ADC_CLIENT_DEBUG_PROTO
30 
31 struct ADC_client_global
32 {
33 	size_t references;
34 #ifdef SSL_SUPPORT
35 	struct ssl_context_handle* ctx;
36 #endif
37 };
38 
39 static struct ADC_client_global* g_adc_client = NULL;
40 
41 
42 enum ADC_client_state
43 {
44 	ps_none, /* Not connected */
45 	ps_conn, /* Connecting... */
46 	ps_conn_ssl, /* SSL handshake */
47 	ps_protocol, /* Have sent HSUP */
48 	ps_identify, /* Have sent BINF */
49 	ps_verify, /* Have sent HPAS */
50 	ps_normal, /* Are fully logged in */
51 };
52 
53 enum ADC_client_flags
54 {
55 	cflag_none = 0,
56 	cflag_ssl = 1,
57 	cflag_choke = 2,
58 	cflag_pipe = 4,
59 };
60 
61 struct ADC_client_address
62 {
63 	enum Protocol { ADC, ADCS } protocol;
64 	char* hostname;
65 	uint16_t port;
66 };
67 
68 struct ADC_client
69 {
70 	sid_t sid;
71 	enum ADC_client_state state;
72 	struct adc_message* info;
73 	struct ioq_recv* recv_queue;
74 	struct ioq_send* send_queue;
75 	adc_client_cb callback;
76 	size_t s_offset;
77 	size_t r_offset;
78 	size_t timeout;
79 	struct net_connection* con;
80 	struct net_timer* timer;
81 	struct sockaddr_storage addr;
82 	struct net_connect_handle* connect_job;
83 	struct ADC_client_address address;
84 	char* nick;
85 	char* desc;
86 	int flags;
87 	void* ptr;
88 };
89 
90 
91 static ssize_t ADC_client_recv(struct ADC_client* client);
92 static void ADC_client_send_info(struct ADC_client* client);
93 static void ADC_client_on_connected(struct ADC_client* client);
94 #ifdef SSL_SUPPORT
95 static void ADC_client_on_connected_ssl(struct ADC_client* client);
96 #endif
97 static void ADC_client_on_disconnected(struct ADC_client* client);
98 static void ADC_client_on_login(struct ADC_client* client);
99 static int ADC_client_parse_address(struct ADC_client* client, const char* arg);
100 static int ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length);
101 static int ADC_client_send_queue(struct ADC_client* client);
102 
ADC_client_debug(struct ADC_client * client,const char * format,...)103 static void ADC_client_debug(struct ADC_client* client, const char* format, ...)
104 {
105 	char logmsg[1024];
106 	va_list args;
107 	va_start(args, format);
108 	vsnprintf(logmsg, 1024, format, args);
109 	va_end(args);
110 	fprintf(stdout, "* [%p] %s\n", client, logmsg);
111 }
112 
113 #ifdef ADCC_DEBUG
114 #define ADC_TRACE fprintf(stderr, "TRACE: %s\n", __PRETTY_FUNCTION__)
115 #else
116 #define ADC_TRACE do { } while(0)
117 #endif
118 
119 #ifdef ADCC_DEBUG
120 static const char* ADC_client_state_string[] =
121 {
122 	"ps_none",
123 	"ps_conn",
124 	"ps_conn_ssl",
125 	"ps_protocol",
126 	"ps_identify",
127 	"ps_verify",
128 	"ps_normal",
129 	0
130 };
131 #endif
132 
ADC_client_set_state(struct ADC_client * client,enum ADC_client_state state)133 static void ADC_client_set_state(struct ADC_client* client, enum ADC_client_state state)
134 {
135 	ADC_TRACE;
136 	if (client->state != state)
137 	{
138 #ifdef ADCC_DEBUG
139 		ADC_client_debug(client, "Set state %s (was %s)", ADC_client_state_string[(int) state], ADC_client_state_string[(int) client->state]);
140 #endif
141 		client->state = state;
142 	}
143 }
144 
145 
adc_cid_pid(struct ADC_client * client)146 static void adc_cid_pid(struct ADC_client* client)
147 {
148 	ADC_TRACE;
149 	char seed[64];
150 	char pid[64];
151 	char cid[64];
152 	uint64_t tiger_res1[3];
153 	uint64_t tiger_res2[3];
154 
155 	/* create cid+pid pair */
156 	memset(seed, 0, 64);
157 	snprintf(seed, 64, VERSION "%p", client);
158 
159 	tiger((uint64_t*) seed, strlen(seed), tiger_res1);
160 	base32_encode((unsigned char*) tiger_res1, TIGERSIZE, pid);
161 	tiger((uint64_t*) tiger_res1, TIGERSIZE, tiger_res2);
162 	base32_encode((unsigned char*) tiger_res2, TIGERSIZE, cid);
163 	cid[ADC_CID_SIZE] = 0;
164 	pid[ADC_CID_SIZE] = 0;
165 
166 	adc_msg_add_named_argument(client->info, ADC_INF_FLAG_PRIVATE_ID, pid);
167 	adc_msg_add_named_argument(client->info, ADC_INF_FLAG_CLIENT_ID, cid);
168 }
169 
event_callback(struct net_connection * con,int events,void * arg)170 static void event_callback(struct net_connection* con, int events, void *arg)
171 {
172 	ADC_TRACE;
173 	struct ADC_client* client = (struct ADC_client*) net_con_get_ptr(con);
174 
175 	switch (client->state)
176 	{
177 		case ps_conn:
178 			if (events == NET_EVENT_TIMEOUT)
179 			{
180 				client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
181 				return;
182 			}
183 			break;
184 
185 #ifdef SSL_SUPPORT
186 		case ps_conn_ssl:
187 			if (events == NET_EVENT_TIMEOUT)
188 			{
189 				client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
190 				return;
191 			}
192 
193 			if (events == NET_EVENT_ERROR)
194 			{
195 				ADC_client_on_disconnected(client);
196 				client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
197 				return;
198 			}
199 			else
200 			{
201 				ADC_client_on_connected_ssl(client);
202 			}
203 			break;
204 #endif
205 
206 		default:
207 			if (events & NET_EVENT_READ)
208 			{
209 				if (ADC_client_recv(client) == -1)
210 				{
211 					ADC_client_on_disconnected(client);
212 				}
213 			}
214 
215 			if (events & NET_EVENT_WRITE)
216 			{
217 				ADC_client_send_queue(client);
218 			}
219 	}
220 }
221 
222 #define UNESCAPE_ARG(TMP, TARGET) \
223 		if (TMP) \
224 			TARGET = adc_msg_unescape(TMP); \
225 		else \
226 			TARGET = NULL; \
227 		hub_free(TMP);
228 
229 #define UNESCAPE_ARG_X(TMP, TARGET, SIZE) \
230 		if (TMP) \
231 			adc_msg_unescape_to_target(TMP, TARGET, SIZE); \
232 		else \
233 			TARGET[0] = '\0'; \
234 		hub_free(TMP);
235 
236 #define EXTRACT_NAMED_ARG(MSG, NAME, TARGET) \
237 		do { \
238 			char* tmp = adc_msg_get_named_argument(MSG, NAME); \
239 			UNESCAPE_ARG(tmp, TARGET); \
240 		} while (0)
241 
242 #define EXTRACT_NAMED_ARG_X(MSG, NAME, TARGET, SIZE) \
243 		do { \
244 			char* tmp = adc_msg_get_named_argument(MSG, NAME); \
245 			UNESCAPE_ARG_X(tmp, TARGET, SIZE); \
246 		} while(0)
247 
248 #define EXTRACT_POS_ARG(MSG, POS, TARGET) \
249 		do { \
250 			char* tmp = adc_msg_get_argument(MSG, POS); \
251 			UNESCAPE_ARG(tmp, TARGET); \
252 		} while (0)
253 
254 
ADC_client_on_recv_line(struct ADC_client * client,const char * line,size_t length)255 static int ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length)
256 {
257 	struct ADC_chat_message chat;
258 	struct ADC_client_callback_data data;
259 
260 	ADC_TRACE;
261 #ifdef ADC_CLIENT_DEBUG_PROTO
262 	ADC_client_debug(client, "- LINE: '%s'", line);
263 #endif
264 
265 	/* Parse message */
266 	struct adc_message* msg = adc_msg_parse(line, length);
267 	if (!msg)
268 	{
269 		ADC_client_debug(client, "WARNING: Message cannot be decoded: \"%s\"", line);
270 		return -1;
271 	}
272 
273 	if (length < 4)
274 	{
275 		ADC_client_debug(client, "Unexpected response from hub: '%s'", line);
276 		return -1;
277 	}
278 
279 	switch (msg->cmd)
280 	{
281 		case ADC_CMD_ISUP:
282 			break;
283 
284 		case ADC_CMD_ISID:
285 			if (client->state == ps_protocol)
286 			{
287 				client->sid = string_to_sid(&line[5]);
288 				client->callback(client, ADC_CLIENT_LOGGING_IN, 0);
289 				ADC_client_set_state(client, ps_identify);
290 				ADC_client_send_info(client);
291 			}
292 			break;
293 
294 		case ADC_CMD_BMSG:
295 		case ADC_CMD_EMSG:
296 		case ADC_CMD_DMSG:
297 		case ADC_CMD_IMSG:
298 		{
299 			chat.from_sid       = msg->source;
300 			chat.to_sid         = msg->target;
301 			data.chat = &chat;
302 			EXTRACT_POS_ARG(msg, 0, chat.message);
303 			chat.flags = 0;
304 
305 			if (adc_msg_has_named_argument(msg, ADC_MSG_FLAG_ACTION))
306 				chat.flags |= chat_flags_action;
307 
308 			if (adc_msg_has_named_argument(msg, ADC_MSG_FLAG_PRIVATE))
309 				chat.flags |= chat_flags_private;
310 
311 			client->callback(client, ADC_CLIENT_MESSAGE, &data);
312 			hub_free(chat.message);
313 			break;
314 		}
315 
316 		case ADC_CMD_IINF:
317 		{
318 			struct ADC_hub_info hubinfo;
319 			EXTRACT_NAMED_ARG(msg, "NI", hubinfo.name);
320 			EXTRACT_NAMED_ARG(msg, "DE", hubinfo.description);
321 			EXTRACT_NAMED_ARG(msg, "VE", hubinfo.version);
322 
323 			struct ADC_client_callback_data data;
324 			data.hubinfo = &hubinfo;
325 			client->callback(client, ADC_CLIENT_HUB_INFO, &data);
326 			hub_free(hubinfo.name);
327 			hub_free(hubinfo.description);
328 			hub_free(hubinfo.version);
329 			break;
330 		}
331 
332 		case ADC_CMD_BSCH:
333 		case ADC_CMD_FSCH:
334 		{
335 			client->callback(client, ADC_CLIENT_SEARCH_REQ, 0);
336 			break;
337 		}
338 
339 		case ADC_CMD_BINF:
340 		{
341 			if (msg->source == client->sid)
342 			{
343 				if (client->state == ps_verify || client->state == ps_identify)
344 				{
345 					ADC_client_on_login(client);
346 				}
347 			}
348 			else
349 			{
350 				if (adc_msg_has_named_argument(msg, "ID"))
351 				{
352 					struct ADC_user user;
353 					user.sid = msg->source;
354 					EXTRACT_NAMED_ARG_X(msg, "NI", user.name, sizeof(user.name));
355 					EXTRACT_NAMED_ARG_X(msg, "DE", user.description, sizeof(user.description));
356 					EXTRACT_NAMED_ARG_X(msg, "VE", user.version, sizeof(user.version));
357 					EXTRACT_NAMED_ARG_X(msg, "ID", user.cid, sizeof(user.cid));
358 					EXTRACT_NAMED_ARG_X(msg, "I4", user.address, sizeof(user.address));
359 
360 					struct ADC_client_callback_data data;
361 					data.user = &user;
362 					client->callback(client, ADC_CLIENT_USER_JOIN, &data);
363 				}
364 			}
365 		}
366 		break;
367 
368 		case ADC_CMD_IQUI:
369 		{
370 			struct ADC_client_quit_reason reason;
371 			memset(&reason, 0, sizeof(reason));
372 			reason.sid = string_to_sid(&line[5]);
373 
374 			if (adc_msg_has_named_argument(msg, ADC_QUI_FLAG_DISCONNECT))
375 				reason.flags |= 1;
376 
377 			data.quit = &reason;
378 			client->callback(client, ADC_CLIENT_USER_QUIT, &data);
379 			break;
380 		}
381 
382 		case ADC_CMD_ISTA:
383 			/*
384 			if (strncmp(line, "ISTA 000", 8))
385 			{
386 				ADC_client_debug(client, "status: '%s'\n", (start + 9));
387 			}
388 			*/
389 			break;
390 
391 		default:
392 			break;
393 	}
394 
395 	adc_msg_free(msg);
396 	return 0;
397 }
398 
ADC_client_recv(struct ADC_client * client)399 static ssize_t ADC_client_recv(struct ADC_client* client)
400 {
401 	static char buf[BIG_BUFSIZE];
402 	struct ioq_recv* q = client->recv_queue;
403 	size_t buf_size = ioq_recv_get(q, buf, BIG_BUFSIZE);
404 	ssize_t size;
405 
406 	ADC_TRACE;
407 
408 	if (client->flags & cflag_choke)
409 		buf_size = 0;
410 	size = net_con_recv(client->con, buf + buf_size, BIG_BUFSIZE - buf_size);
411 
412 	if (size > 0)
413 		buf_size += size;
414 
415 	if (size < 0)
416 		return -1;
417 	else if (size == 0)
418 		return 0;
419 	else
420 	{
421 		char* lastPos = 0;
422 		char* start = buf;
423 		char* pos = 0;
424 		size_t remaining = buf_size;
425 
426 		while ((pos = memchr(start, '\n', remaining)))
427 		{
428 			lastPos = pos+1;
429 			pos[0] = '\0';
430 
431 #ifdef DEBUG_SENDQ
432 			LOG_DUMP("PROC: \"%s\" (%d)\n", start, (int) (pos - start));
433 #endif
434 
435 			if (client->flags & cflag_choke)
436 				client->flags &= ~cflag_choke;
437 			else
438 			{
439 				if (((pos - start) > 0) && MAX_RECV_BUFFER > (pos - start))
440 				{
441 					if (ADC_client_on_recv_line(client, start, pos - start) == -1)
442 						return -1;
443 				}
444 			}
445 
446 			pos[0] = '\n'; /* FIXME: not needed */
447 			pos ++;
448 			remaining -= (pos - start);
449 			start = pos;
450 		}
451 
452 		if (lastPos || remaining)
453 		{
454 			if (remaining < (size_t) MAX_RECV_BUFFER)
455 			{
456 				ioq_recv_set(q, lastPos ? lastPos : buf, remaining);
457 			}
458 			else
459 			{
460 				ioq_recv_set(q, 0, 0);
461 				client->flags |= cflag_choke;
462 				LOG_WARN("Received message past MAX_RECV_BUFFER (%d), dropping message.", MAX_RECV_BUFFER);
463 			}
464 		}
465 		else
466 		{
467 			ioq_recv_set(q, 0, 0);
468 		}
469 	}
470 	return 0;
471 }
472 
ADC_client_send_queue(struct ADC_client * client)473 static int ADC_client_send_queue(struct ADC_client* client)
474 {
475 	int ret = 0;
476 	while (ioq_send_get_bytes(client->send_queue))
477 	{
478 		ret = ioq_send_send(client->send_queue, client->con);
479 		if (ret <= 0)
480 			break;
481 	}
482 
483 	if (ret < 0)
484 		return quit_socket_error;
485 
486 	if (ioq_send_get_bytes(client->send_queue))
487 	{
488 		net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
489 	}
490 	else
491 	{
492 		net_con_update(client->con, NET_EVENT_READ);
493 	}
494 	return 0;
495 }
496 
497 
ADC_client_send(struct ADC_client * client,struct adc_message * msg)498 void ADC_client_send(struct ADC_client* client, struct adc_message* msg)
499 {
500 	ADC_TRACE;
501 
502 	uhub_assert(client->con != NULL);
503 	uhub_assert(msg->cache && *msg->cache);
504 
505 	if (ioq_send_is_empty(client->send_queue) && !(client->flags & cflag_pipe))
506 	{
507 		/* Perform oportunistic write */
508 		ioq_send_add(client->send_queue, msg);
509 		ADC_client_send_queue(client);
510 	}
511 	else
512 	{
513 		ioq_send_add(client->send_queue, msg);
514 		if (!(client->flags & cflag_pipe))
515 			net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
516 	}
517 }
518 
ADC_client_send_info(struct ADC_client * client)519 void ADC_client_send_info(struct ADC_client* client)
520 {
521 	ADC_TRACE;
522 	client->info = adc_msg_construct_source(ADC_CMD_BINF, client->sid, 96);
523 
524 
525 	adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_NICK, client->nick);
526 
527 	if (client->desc)
528 	{
529 		adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_DESCRIPTION, client->desc);
530 	}
531 
532 	adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_USER_AGENT_PRODUCT, PRODUCT);
533 	adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_USER_AGENT_VERSION, VERSION);
534 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_UPLOAD_SLOTS, 0);
535 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_SHARED_SIZE, 0);
536 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_SHARED_FILES, 0);
537 
538 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_COUNT_HUB_NORMAL, 1);
539 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_COUNT_HUB_REGISTER, 0);
540 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_COUNT_HUB_OPERATOR, 0);
541 
542 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_DOWNLOAD_SPEED, 5 * 1024 * 1024);
543 	adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_UPLOAD_SPEED, 10 * 1024 * 1024);
544 
545 	adc_cid_pid(client);
546 
547 	ADC_client_send(client, client->info);
548 }
549 
550 
ADC_client_create(const char * nickname,const char * description,void * ptr)551 struct ADC_client* ADC_client_create(const char* nickname, const char* description, void* ptr)
552 {
553 	ADC_TRACE;
554 	struct ADC_client* client = (struct ADC_client*) hub_malloc_zero(sizeof(struct ADC_client));
555 
556 	ADC_client_set_state(client, ps_none);
557 
558 	client->nick = hub_strdup(nickname);
559 	client->desc = hub_strdup(description);
560 
561 	client->send_queue = ioq_send_create();
562 	client->recv_queue = ioq_recv_create();
563 
564 	client->ptr = ptr;
565 
566 	if (!g_adc_client)
567 	{
568 		g_adc_client = (struct ADC_client_global*) hub_malloc_zero(sizeof(struct ADC_client_global));
569 #ifdef SSL_SUPPORT
570 		g_adc_client->ctx = net_ssl_context_create("1.2", "HIGH");
571 
572 #endif
573 	}
574 	g_adc_client->references++;
575 
576 	return client;
577 }
578 
ADC_client_destroy(struct ADC_client * client)579 void ADC_client_destroy(struct ADC_client* client)
580 {
581 	ADC_TRACE;
582 	ADC_client_disconnect(client);
583 	ioq_send_destroy(client->send_queue);
584 	ioq_recv_destroy(client->recv_queue);
585 	hub_free(client->timer);
586 	adc_msg_free(client->info);
587 	hub_free(client->nick);
588 	hub_free(client->desc);
589 	hub_free(client->address.hostname);
590 	hub_free(client);
591 
592 	if (g_adc_client && g_adc_client->references > 0)
593 	{
594 		g_adc_client->references--;
595 		if (!g_adc_client->references)
596 		{
597 #ifdef SSL_SUPPORT
598 			net_ssl_context_destroy(g_adc_client->ctx);
599 			g_adc_client->ctx = NULL;
600 #endif
601 			hub_free(g_adc_client);
602 			g_adc_client = NULL;
603 		}
604 	}
605 }
606 
connect_callback(struct net_connect_handle * handle,enum net_connect_status status,struct net_connection * con,void * ptr)607 static void connect_callback(struct net_connect_handle* handle, enum net_connect_status status, struct net_connection* con, void* ptr)
608 {
609 	struct ADC_client* client = (struct ADC_client*) ptr;
610 	client->connect_job = NULL;
611 	switch (status)
612 	{
613 		case net_connect_status_ok:
614 			client->con = con;
615 			net_con_reinitialize(client->con, event_callback, client, 0);
616 			ADC_client_on_connected(client);
617 			break;
618 
619 		case net_connect_status_host_not_found:
620 		case net_connect_status_no_address:
621 		case net_connect_status_dns_error:
622 		case net_connect_status_refused:
623 		case net_connect_status_unreachable:
624 		case net_connect_status_timeout:
625 		case net_connect_status_socket_error:
626 			ADC_client_disconnect(client);
627 			break;
628 	}
629 }
630 
ADC_client_connect(struct ADC_client * client,const char * address)631 int ADC_client_connect(struct ADC_client* client, const char* address)
632 {
633 	ADC_TRACE;
634 	if (client->state == ps_none)
635 	{
636 		if (!ADC_client_parse_address(client, address))
637 			return 0;
638 	}
639 
640 	ADC_client_set_state(client, ps_conn);
641 	client->connect_job = net_con_connect(client->address.hostname, client->address.port, connect_callback, client);
642 	if (!client->connect_job)
643 	{
644 		ADC_client_on_disconnected(client);
645 		return 0;
646 	}
647 	return 1;
648 }
649 
ADC_client_send_handshake(struct ADC_client * client)650 static void ADC_client_send_handshake(struct ADC_client* client)
651 {
652 	ADC_TRACE;
653 	struct adc_message* handshake = adc_msg_create(ADC_HANDSHAKE);
654 
655 	client->callback(client, ADC_CLIENT_CONNECTED, 0);
656 	net_con_update(client->con, NET_EVENT_READ);
657 	ADC_client_send(client, handshake);
658 	ADC_client_set_state(client, ps_protocol);
659 	adc_msg_free(handshake);
660 }
661 
ADC_client_on_connected(struct ADC_client * client)662 static void ADC_client_on_connected(struct ADC_client* client)
663 {
664 	ADC_TRACE;
665 #ifdef SSL_SUPPORT
666 	if (client->flags & cflag_ssl)
667 	{
668 		net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
669 		client->callback(client, ADC_CLIENT_SSL_HANDSHAKE, 0);
670 		ADC_client_set_state(client, ps_conn_ssl);
671 		net_con_ssl_handshake(client->con, net_con_ssl_mode_client, g_adc_client->ctx);
672 	}
673 	else
674 #endif
675 	ADC_client_send_handshake(client);
676 
677 }
678 
679 #ifdef SSL_SUPPORT
ADC_client_on_connected_ssl(struct ADC_client * client)680 static void ADC_client_on_connected_ssl(struct ADC_client* client)
681 {
682 	ADC_TRACE;
683 	struct ADC_client_callback_data data;
684 	struct ADC_client_tls_info tls_info;
685 	data.tls_info = &tls_info;
686 
687 	tls_info.version = net_ssl_get_tls_version(client->con);
688 	tls_info.cipher = net_ssl_get_tls_cipher(client->con);
689 
690 	client->callback(client, ADC_CLIENT_SSL_OK, &data);
691 	ADC_client_send_handshake(client);
692 }
693 #endif
694 
ADC_client_on_disconnected(struct ADC_client * client)695 static void ADC_client_on_disconnected(struct ADC_client* client)
696 {
697 	ADC_TRACE;
698 	net_con_close(client->con);
699 	client->con = 0;
700 	ADC_client_set_state(client, ps_none);
701 }
702 
ADC_client_on_login(struct ADC_client * client)703 static void ADC_client_on_login(struct ADC_client* client)
704 {
705 	ADC_TRACE;
706 	ADC_client_set_state(client, ps_normal);
707 	client->callback(client, ADC_CLIENT_LOGGED_IN, 0);
708 }
709 
ADC_client_disconnect(struct ADC_client * client)710 void ADC_client_disconnect(struct ADC_client* client)
711 {
712 	ADC_TRACE;
713 	if (client->con && net_con_get_sd(client->con) != -1)
714 	{
715 		net_con_close(client->con);
716 		client->con = 0;
717 	}
718 }
719 
ADC_client_parse_address(struct ADC_client * client,const char * arg)720 static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
721 {
722 	ADC_TRACE;
723 	const char* hub_address = arg;
724 	char* split;
725 	int ssl = 0;
726 
727 	if (!arg)
728 		return 0;
729 
730 	/* Minimum length of a valid address */
731 	if (strlen(arg) < 9)
732 		return 0;
733 
734 	/* Check for ADC or ADCS */
735 	if (!strncmp(arg, "adc://", 6))
736 	{
737 		client->flags &= ~cflag_ssl;
738 		client->address.protocol = ADC;
739 	}
740 	else if (!strncmp(arg, "adcs://", 7))
741 	{
742 		client->flags |= cflag_ssl;
743 		ssl = 1;
744 		client->address.protocol = ADCS;
745 	}
746 	else
747 		return 0;
748 
749 	/* Split hostname and port (if possible) */
750 	hub_address = arg + 6 + ssl;
751 	split = strrchr(hub_address, ':');
752 	if (split == 0 || strlen(split) < 2 || strlen(split) > 6)
753 		return 0;
754 
755 	/* Ensure port number is valid */
756 	client->address.port = strtol(split+1, NULL, 10);
757 	if (client->address.port <= 0 || client->address.port > 65535)
758 		return 0;
759 
760 	client->address.hostname = strndup(hub_address, &split[0] - &hub_address[0]);
761 
762 	return 1;
763 }
764 
ADC_client_set_callback(struct ADC_client * client,adc_client_cb cb)765 void ADC_client_set_callback(struct ADC_client* client, adc_client_cb cb)
766 {
767 	ADC_TRACE;
768 	client->callback = cb;
769 }
770 
ADC_client_get_sid(const struct ADC_client * client)771 sid_t ADC_client_get_sid(const struct ADC_client* client)
772 {
773 	return client->sid;
774 }
775 
ADC_client_get_nick(const struct ADC_client * client)776 const char* ADC_client_get_nick(const struct ADC_client* client)
777 {
778 	return client->nick;
779 }
780 
ADC_client_get_description(const struct ADC_client * client)781 const char* ADC_client_get_description(const struct ADC_client* client)
782 {
783 	return client->desc;
784 }
785 
ADC_client_get_ptr(const struct ADC_client * client)786 void* ADC_client_get_ptr(const struct ADC_client* client)
787 {
788 	return client->ptr;
789 }
790