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