TRIP Routing Daemon
TRIP (RFC 3219) Location Server Implementation
Loading...
Searching...
No Matches
manager.c
Go to the documentation of this file.
1/*
2
3 trip: Modern TRIP LS implementation
4 Copyright (C) 2025 arf20 (Ángel Ruiz Fernandez)
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19 manager.c: location server session manager
20
21*/
22
31
32#include "manager.h"
33
34#include "locator.h"
35#include <logging/logging.h>
36#include <protocol/protocol.h>
37#include "session.h"
38#include <util/util.h>
39
40#include <netinet/in.h>
41
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <errno.h>
46#include <sys/param.h>
47
48#include <pthread.h>
49
50#include <arpa/inet.h>
51#include <unistd.h>
52
53#define _COMPONENT_ "manager"
54
55#ifndef MAX_BACKOFF_CONNECT_RETRY
56 #define MAX_BACKOFF_CONNECT_RETRY 3600
57#endif /* MAX_BACKOFF_CONNECT_RETRY */
58
59
60static void *connect_loop(void *arg);
61
62
64static session_t *
65manager_session_lookup_itad_id(const manager_t *m, uint32_t itad,
66 uint32_t id)
67{
68 for (size_t i = 0; i < m->sessions_size; i++)
69 if (m->sessions[i]->peer->itad == itad &&
70 m->sessions[i]->id == id)
71 {
72 return m->sessions[i];
73 }
74 return NULL;
75}
76
78static session_t *
79manager_session_lookup_peer(const manager_t *m, const peer_t *peer)
80{
81 for (size_t i = 0; i < m->sessions_size; i++)
82 if (m->sessions[i]->peer == peer && !m->sessions[i]->mark_stop_init)
83 {
84 return m->sessions[i];
85 }
86 return NULL;
87}
88
92 const struct sockaddr_in6 *addr)
93{
94 for (size_t i = 0; i < m->sessions_size; i++)
95 if (!m->sessions[i]->mark_stop_init &&
96 memcmp(&m->sessions[i]->peer->addr.sin6_addr, &addr->sin6_addr,
97 sizeof(struct in6_addr)) == 0)
98 {
99 return m->sessions[i];
100 }
101 return NULL;
102}
103
108static int
109send_notification_res(int fd, int res)
110{
111 uint8_t code = NOTIF_CODE_ERROR_OPEN, subcode = 0;
112 switch (res) {
113 case ERROR_MSGTYPE:
114 code = NOTIF_CODE_ERROR_MSG;
115 subcode = NOTIF_SUBCODE_MSG_BAD_TYPE;
116 break;
117 case ERROR_VERSION: subcode = NOTIF_SUBCODE_OPEN_UNSUP_VERSION; break;
118 case ERROR_ITAD: subcode = NOTIF_SUBCODE_OPEN_BAD_ITAD; break;
119 case ERROR_OPT: subcode = NOTIF_SUBCODE_OPEN_UNSUP_OPT; break;
120 case ERROR_HOLD: subcode = NOTIF_SUBCODE_OPEN_BAD_HOLD; break;
121 case ERROR_CAPINFO_CODE: subcode = NOTIF_SUBCODE_OPEN_UNSUP_CAP; break;
122 }
123
124 if (subcode)
125 if(send_notification(fd, code, subcode) < 0)
126 return -1;
127
128 return 0;
129}
130
132static void
133manager_session_add(manager_t *m, session_t *s)
134{
135 if (m->sessions_size + 1 > m->sessions_capacity) {
136 m->sessions = realloc(m->sessions,
137 2 * sizeof(session_t) * m->sessions_capacity);
138 m->sessions_capacity *= 2;
139 }
140
141 m->sessions[m->sessions_size++] = s;
142}
143
145static void
146manager_session_remove(manager_t *m, session_t *s)
147{
148 int s_idx = -1;
149 for (int i = 0; i < m->sessions_size; i++)
150 if (m->sessions[i] == s)
151 s_idx = i;
152
154 memcpy(&m->sessions[s_idx], &m->sessions[s_idx + 1],
155 sizeof(session_t*) * (m->sessions_size - s_idx));
156 m->sessions_size--;
157}
158
163static int
164compare_itad_id(uint32_t itad1, uint32_t id1, uint32_t itad2, uint32_t id2)
165{
166 return (id1 < id2) || (id1 == id2 && (itad1 < itad2));
167}
168
176static int
177manager_collision_sessions_compare(const manager_t *m, const session_t *s1,
178 const session_t *s2)
179{
180 if (s1->initiated == s2->initiated) {
181 ERROR("colliding connections initiated by same ID");
182 return 1;
183 } else if (s1->initiated) {
184 /* new session initiated by local
185 * return local < s2 peer */
186 return compare_itad_id(m->itad, m->id, s2->peer->itad, s2->id);
187 } else {
188 /* old connection initiated by local
189 * return s1 peer < local */
190 return compare_itad_id(s1->peer->itad, s1->id, m->itad, m->id);
191 }
192}
193
194/* =================== REQUEST HANDLING ===================================== */
195
197static int
198handle_open(manager_t *m, session_t *s, const msg_t *msg,
199 void *recv_wnd)
200{
201 int res = 0, toread = 0;
202 SOCK_TRY_RECV(s->fd, recv_wnd, msg_open_t, goto sock_error);
203
204 const msg_open_t *open = NULL;
205 PROTO_TRY(
206 parse_msg_open(msg->msg_val, res, &open),
207 res, goto proto_error
208 );
209
210 DEBUG("OPEN(ver %d, hold %d, itad %d, id %s, opts len %d)",
211 open->open_ver, open->open_hold, open->open_itad,
212 id_str(open->open_id), open->open_opts_len);
213
214 /* check received OPEN fields */
215 if (open->open_itad != s->peer->itad) {
216 ERROR("peer ITAD mismatch");
217 send_notification(s->fd, NOTIF_CODE_ERROR_OPEN,
218 NOTIF_SUBCODE_OPEN_BAD_ITAD);
219 return -1;
220 }
221
222 /* duplicate ID in ITAD peer collision detection */
223 if ((open->open_itad == m->itad) && (open->open_id == m->id)) {
224 ERROR("duplicate ID in ITAD detected, colliding peer rejected");
225 send_notification(s->fd, NOTIF_CODE_ERROR_OPEN,
226 NOTIF_SUBCODE_OPEN_BAD_ID);
227 return -1;
228 }
229
230 /* section 6.8 collision detection */
231 session_t *coll_s = manager_session_lookup_itad_id(m, open->open_itad,
232 open->open_id);
233 if (coll_s) {
234 WARNING("collision detected with peer (%d,%d)", open->open_itad,
235 open->open_id);
236 if (coll_s->state == STATE_OPENCONFIRM) {
237 WARNING("collision resolved: kept higher ID or ITAD");
238 if (manager_collision_sessions_compare(m, s, coll_s)) {
239 send_notification(s->fd, NOTIF_CODE_CEASE, 0);
240 return -1;
241 } else {
242 /* cease, close and destroy old session, remove from vector */
243 send_notification(coll_s->fd, NOTIF_CODE_CEASE, 0);
244 session_shutdown(coll_s);
245 manager_session_remove(m, coll_s);
246 }
247 } else if (coll_s->state == STATE_ESTABLISHED) {
248 WARNING("collision resolved: kept established connection");
249 send_notification(s->fd, NOTIF_CODE_CEASE, 0);
250 return -1;
251 }
252 }
253
254 /* find old still initiating session pre-openconfirm if exists and stop it*/
255 session_t *init_s = manager_session_lookup_peer(m, s->peer);
256 if (init_s && (init_s->initiated == 1) && (init_s != s)) {
257 INFO("closing old initiating session");
258 init_s->mark_stop_init = 1;
259 }
260
261
262 s->id = open->open_id;
263 s->hold = MIN(s->peer->hold, open->open_hold);
264 s->keepalive = s->hold / 3;
265
266 /* now add session to manager */
267 if (!s->initiated)
268 manager_session_add(m, s);
269
270 size_t opts_toread = open->open_opts_len;
271 const void *opt_cur = open->open_opts;
272 while (opts_toread) {
273 SOCK_TRY_RECV(s->fd, recv_wnd, msg_open_opt_t,
274 goto sock_error);
275
276 const msg_open_opt_t *opt = NULL;
277 PROTO_TRY(
278 parse_msg_open_opt(opt_cur, res, &opt),
279 res, goto proto_error
280 );
281
282 opts_toread -= res;
283
284 DEBUG(" option: %s[%d]", open_opt_type_strs[opt->opt_type],
285 opt->opt_len);
286
287 switch (opt->opt_type) {
288 case OPEN_OPT_TYPE_CAPABILITY_INFO: {
289 size_t capinfos_toread = opt->opt_len;
290 const void *capinfo_cur = opt->opt_val;
291 while (capinfos_toread) {
292 SOCK_TRY_RECV(s->fd, recv_wnd, capinfo_t,
293 goto sock_error);
294
295 const capinfo_t *capinfo = NULL;
296 PROTO_TRY(
297 parse_capinfo(capinfo_cur, res, &capinfo),
298 res, goto proto_error
299 );
300
301 opts_toread -= res;
302 capinfos_toread -= res;
303
304 DEBUG(" capability info: %s[%d]",
305 capinfo_code_strs[capinfo->capinfo_code],
306 capinfo->capinfo_len);
307
308
309 switch (capinfo->capinfo_code) {
310 case CAPINFO_CODE_ROUTETYPE: {
311 size_t routetypes_toread = capinfo->capinfo_len;
312 const void *routetype_cur = capinfo->capinfo_val;
313
314 s->routetypes_count = routetypes_toread /
315 sizeof(capinfo_routetype_t);
316 s->routetypes = malloc(routetypes_toread);
317 void *crt_cur = s->routetypes;
318
319 while (routetypes_toread) {
320 SOCK_TRY_RECV(s->fd, recv_wnd,
321 capinfo_routetype_t, goto sock_error);
322
323 const capinfo_routetype_t *routetype = NULL;
324 PROTO_TRY(
325 parse_capinfo_routetype(routetype_cur, res,
326 &routetype),
327 res, goto proto_error
328 );
329
330 routetype_cur += res;
331 opts_toread -= res;
332 capinfos_toread -= res;
333 routetypes_toread -= res;
334
335 DEBUG(" route type: %s:%s",
336 af_strs[routetype->routetype_af],
337 app_proto_str(routetype->routetype_app_proto));
338
339 memcpy(crt_cur, routetype, res);
340 crt_cur += res;
341 }
342 } break;
343 case CAPINFO_CODE_TRANSMODE: {
344 SOCK_TRY_RECV(s->fd, recv_wnd,
345 capinfo_transmode_t, goto sock_error);
346
347 const capinfo_transmode_t *transmode = NULL;
348 PROTO_TRY(
349 parse_capinfo_transmode(capinfo->capinfo_val,
350 res, &transmode),
351 res, goto proto_error
352 );
353
354 opts_toread -= res;
355 capinfos_toread -= res;
356
357 DEBUG(" transmission mode: %s",
358 capinfo_transmode_strs[*transmode]);
359
360 if (*transmode != CAPINFO_TRANS_SEND_RECV &&
361 (*transmode == s->peer->transmode))
362 {
363 WARNING(" transmission mode mismatch");
364 send_notification(s->fd, NOTIF_CODE_ERROR_OPEN,
365 NOTIF_SUBCODE_OPEN_CAP_MISMATCH);
366 return -1;
367 }
368
369 s->transmode = *transmode;
370 } break;
371 }
372
373 capinfo_cur += sizeof(capinfo_t) + capinfo->capinfo_len;
374 }
375 } break;
376 }
377
378 opt_cur += sizeof(msg_open_opt_t) + opt->opt_len;
379 }
380
381 return 0;
382
383proto_error:
384 send_notification_res(s->fd, res);
385
386sock_error:
387 return -1;
388}
389
390
399static void *
400peer_handshake(void *arg)
401{
402 manager_t *m = ((void**)arg)[0];
403 session_t *s = ((void**)arg)[1];
404
405 int res = 0, toread = 0;
406 char buff[MAX_MSG_SIZE];
407
408 /* send OPEN */
409 PROTO_TRY(
410 new_msg_open(buff, MAX_MSG_SIZE,
411 s->peer->hold, m->itad, m->id,
413 s->peer->transmode),
414 res, goto proto_error
415 );
416
417 SOCK_TRY_SEND(
418 send(s->fd, buff, res, 0),
419 goto sock_error
420 );
421 session_change_state(s, STATE_OPENSENT);
422
423
424 /* receive OPEN */
425 while (1) {
426 void *recv_wnd = buff;
427 /* receive and decode message header */
428 SOCK_TRY_RECV(s->fd, recv_wnd, msg_t, goto sock_error);
429
430 const msg_t *msg = NULL;
431 PROTO_TRY(
432 parse_msg(buff, res, &msg),
433 res, goto proto_error
434 );
435
436 DEBUG("received msg: %s[%d]", msg_type_strs[msg->msg_type],
437 msg->msg_len);
438
439 switch (msg->msg_type) {
440 case MSG_TYPE_OPEN: {
441 if (handle_open(m, s, msg, recv_wnd) < 0)
442 goto sock_error;
443
444 PROTO_TRY(
445 new_msg_keepalive(buff, MAX_MSG_SIZE),
446 res, goto proto_error
447 );
448
449 SOCK_TRY_SEND(
450 send(s->fd, buff, res, 0),
451 goto sock_error
452 );
453
454 session_change_state(s, STATE_OPENCONFIRM);
455 } break;
456 case MSG_TYPE_NOTIFICATION: {
457 SOCK_TRY_RECV(s->fd, recv_wnd, msg_notif_t, goto sock_error);
458
459 const msg_notif_t *notif= NULL;
460 PROTO_TRY(
461 parse_msg_notif(msg->msg_val, res, &notif),
462 res, goto proto_error
463 );
464
465 DEBUG("error code: %s, error subcode: %s",
466 notif_code_strs[notif->notif_error_code],
467 notif_code_subcodes_strs[notif->notif_error_code]
468 [notif->notif_error_subcode]);
469 } break;
470 case MSG_TYPE_KEEPALIVE: {
471 if (s->state == STATE_OPENCONFIRM)
472 session_change_state(s, STATE_ESTABLISHED);
473 time_t now = time(NULL);
474 s->established_time = s->last_read_time = now;
475
476 /* Hand newly established session off to session_loop */
477 session_loop(arg);
478
479 if (s->mark_stop_init) {
480 close(s->fd);
481 free(arg);
482 return NULL;
483 }
484
485 /* If peer disconnects going back to idle, start connect loop */
486 s->initiated = 1;
487 connect_loop(arg);
488 } break;
489 default:
490 ERROR("unexpected %s message");
491 goto sock_error;
492 }
493 }
494
495
496proto_error:
497 send_notification_res(s->fd, res);
498
499sock_error:
500 if (s->mark_stop_init)
501 return NULL;
502 close(s->fd);
503 session_change_state(s, STATE_IDLE);
504 return NULL;
505}
506
507/* =================== CONNECTION HANDLING ================================= */
508
510static void *
511listen_loop(void *arg)
512{
513 manager_t *m = arg;
514
515 struct sockaddr_in6 peer_addr = { 0 };
516 socklen_t peer_addr_size = sizeof(struct sockaddr_in6);
517
518 while (m->run) {
519 /* accept connection (block) */
520 int request_fd = accept(m->fd, (struct sockaddr*)&peer_addr,
521 &peer_addr_size);
522 if (request_fd < 0) {
523 ERROR("could not accept() peer: %s", strerror(errno));
524 return NULL;
525 }
526
527 /* check that connection comes from peer, and that this peer does not
528 * have an active session */
529 const peer_t *peer = locator_lookup(m->locator, &peer_addr);
530 if (!peer) {
531 INFO("rejecting unknown peer connection: %s",
532 sockaddr_str((struct sockaddr *)&peer_addr));
533 close(request_fd);
534 continue;
535 }
536
537 DEBUG("accepted connection from %s, initiating peer",
538 sockaddr_str((struct sockaddr*)&peer_addr));
539
540
541 /* hand off connection to handshake handler on a new thread */
542 session_t *s = malloc(sizeof(session_t));
543 memset(s, 0, sizeof(session_t));
544 s->peer = peer;
545 s->fd = request_fd;
546 s->initiated = 0;
547
548 void **handshake_data = malloc(2 * sizeof(void*));
549 handshake_data[0] = m;
550 handshake_data[1] = s;
551
552 pthread_create(&s->thread, NULL, &peer_handshake, handshake_data);
553 }
554
555 return NULL;
556}
557
558
560static void *
561maintenance_loop(void *arg)
562{
563 manager_t *m = arg;
564 char buff[MAX_MSG_SIZE];
565
566 while (m->run) {
567 time_t now = time(NULL);
568
569 for (int i = 0; i < m->sessions_size; i++) {
570 session_t *s = m->sessions[i];
571 if (s->state != STATE_ESTABLISHED || s->hold == 0)
572 continue;
573
574 if (now - s->last_write_time > s->keepalive) {
575 int n = new_msg_keepalive(buff, sizeof(buff));
576
577 DEBUG("sending KEEPALIVE");
578 SOCK_TRY_SEND(send(s->fd, buff, n, 0), session_shutdown(s));
579 s->last_write_time = now;
580 }
581
582 if (now - s->last_read_time > s->hold) {
583 int n = new_msg_notif(buff, sizeof(buff),
584 NOTIF_CODE_ERROR_EXPIRED, 0, 0, NULL);
585
586 ERROR("session %s hold timer expired %ld",
587 sockaddr6_str(&s->peer->addr), s->last_read_time);
588 SOCK_TRY_SEND(send(s->fd, buff, n, 0), session_shutdown(s));
590 }
591
592 }
593
594 usleep(100000);
595 }
596
597
598 return NULL;
599}
600
601
602
603manager_t *
604manager_new(const struct sockaddr_in6 *listen_addr)
605{
606 static manager_t manager = { 0 };
607
608 if (manager.itad)
609 return NULL;
610
611 manager_t *m = &manager;
612 memset(m, 0, sizeof(manager_t));
613
614 /* init values */
615 m->run = 0;
616 m->listen_thread = 0;
617 m->maintenance_thread = 0;
618 m->fd = 0;
619
620 m->itad = 0;
621 m->id = 0;
622
623 m->locator = locator_new();
624
625 m->sessions_size = 0;
626 m->sessions_capacity = 16;
627 m->sessions = malloc(m->sessions_capacity * sizeof(session_t*));
628 memset(m->sessions, 0, m->sessions_capacity * sizeof(session_t*));
629
630 m->connect_retry = TIMER_CONNECT_RETRY;
631 m->hold = TIMER_HOLD_TIME;
632 m->keepalive = TIMER_KEEPALIVE;
633 m->max_purge_time = TIMER_MAX_PURGE_TIME;
634 m->disable_time = TIMER_DISABLE_TIME;
635 m->min_itad_orig_int = TIMER_MIN_ITAD_ORIG_INT;
636 m->min_route_advert_int = TIMER_MIN_ROUTE_ADVERT_INT;
637
638 /* create listen socket */
639 m->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
640 if (m->fd < 0) {
641 ERROR("could not create listen socket: %s", strerror(errno));
642 return NULL;
643 }
644
645 if (bind(m->fd, (const struct sockaddr*)listen_addr,
646 sizeof(struct sockaddr_in6)) < 0)
647 {
648 ERROR("could not bind() listen socket: %s", strerror(errno));
649 return NULL;
650 }
651
652 if (listen(m->fd, SOMAXCONN) < 0) {
653 ERROR("could not listen() listen socket: %s", strerror(errno));
654 return NULL;
655 }
656
657 DEBUG("started session manager, listening at [%s]:%d",
658 sockaddr_str((struct sockaddr *)listen_addr),
659 ntohs(listen_addr->sin6_port));
660
661 return m;
662}
663
664
665/* ===================== SESSION INITIATION ================================= */
666
671static void *
672connect_loop(void *arg)
673{
674 manager_t *m = ((void**)arg)[0];
675 session_t *s = ((void**)arg)[1];
676
677 /* create socket every time we try to connect */
678 s->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
679
680 time_t connect_retry = m->connect_retry;
681
682 while (1) {
683 if (s->mark_stop_init) {
684 manager_session_remove(m, s);
685 return NULL;
686 }
687
688 session_change_state(s, STATE_CONNECT);
689
690 int res = connect(s->fd, (struct sockaddr*)&s->peer->addr,
691 sizeof(struct sockaddr_in6));
692
693 if (res < 0) {
694 ERROR("connect(): %s", strerror(errno));
695 session_change_state(s, STATE_IDLE);
696
697 uint64_t retry_left = connect_retry * 1e6;
698 while (retry_left && !s->mark_stop_init) {
699 usleep(100e3);
700 retry_left -= 100e3;
701 }
702
703 if (connect_retry < MAX_BACKOFF_CONNECT_RETRY)
704 connect_retry *= 2;
705 continue;
706 }
707
708 break;
709 }
710
711 /* TCP channel established, hand off to request handler */
712 peer_handshake(arg);
713 return NULL;
714}
715
716
717void
718manager_add_peer(manager_t *manager, const struct sockaddr_in6 *addr,
719 uint32_t itad)
720{
721 /* add peer to peer locator */
722 const peer_t *peer = locator_add(manager->locator, addr, itad,
723 manager->hold, CAPINFO_TRANS_SEND_RECV);
724
725 /* create session object and hand off to connect loop */
726 session_t *s = malloc(sizeof(session_t));
727 memset(s, 0, sizeof(session_t));
728 s->peer = peer;
729 s->state = STATE_IDLE;
730 s->initiated = 1;
731
732 /* add session to manager session vector */
733 manager_session_add(manager, s);
734
735 void **connect_data = malloc(2 * sizeof(void*));
736 connect_data[0] = manager;
737 connect_data[1] = s;
738
739 pthread_create(&s->thread, NULL, &connect_loop, connect_data);
740}
741
742void
744{
745 manager->run = 1;
746 pthread_create(&manager->listen_thread, NULL, &listen_loop, manager);
747 pthread_create(&manager->maintenance_thread, NULL, &maintenance_loop,
748 manager);
749}
750
751void
753{
754 manager->run = 0;
755 shutdown(manager->fd, SHUT_RDWR);
756 pthread_join(manager->listen_thread, NULL);
757 pthread_join(manager->maintenance_thread, NULL);
758}
759
760void
762{
763 DEBUG("beginning shutdown");
764
765 for (size_t i = 0; i < manager->sessions_size; i++) {
766 if (!manager->sessions[i])
767 continue;
768 session_shutdown(manager->sessions[i]);
769 manager->sessions[i]->mark_stop_init = 1;
770 }
771
772 for (size_t i = 0; i < manager->sessions_size; i++) {
773 if (!manager->sessions[i])
774 continue;
775 pthread_join(manager->sessions[i]->thread, NULL);
776 }
777
778 for (size_t i = 0; i < manager->sessions_size; i++) {
779 if (!manager->sessions[i])
780 continue;
781 session_destroy(manager->sessions[i]);
782 }
783
784 manager_stop(manager);
785
786 DEBUG("shutdown complete");
787}
788
789void
791{
792 locator_destroy(manager->locator);
793 free(manager->sessions);
794 manager->itad = 0;
795}
796
const peer_t * locator_lookup(locator_t *locator, const struct sockaddr_in6 *addr)
Lookup peer by its address.
Definition locator.c:66
const peer_t * locator_add(locator_t *locator, const struct sockaddr_in6 *addr, uint32_t itad, uint16_t hold, capinfo_transmode_t transmode)
Add a known peer.
Definition locator.c:47
void locator_destroy(locator_t *locator)
Destroy locator object.
Definition locator.c:85
locator_t * locator_new()
Initialize singleton locator known peer list.
Definition locator.c:37
Peer locator.
logging utilities
#define DEBUG(format,...)
log for debugging purposes
Definition logging.h:65
#define ERROR(format,...)
log an error
Definition logging.h:56
#define INFO(format,...)
log informational event
Definition logging.h:62
#define WARNING(format,...)
log a warning
Definition logging.h:59
void manager_stop(manager_t *manager)
Stop accept loop.
Definition manager.c:752
manager_t * manager_new(const struct sockaddr_in6 *listen_addr)
Create manager and bind socket.
Definition manager.c:604
void manager_destroy(manager_t *manager)
Destroy manager object.
Definition manager.c:790
session_t * manager_session_lookup_address(const manager_t *m, const struct sockaddr_in6 *addr)
Lookup session by locator peer.
Definition manager.c:91
void manager_shutdown(manager_t *manager)
Shut down manager and all sessions.
Definition manager.c:761
void manager_run(manager_t *manager)
Run accept loop in thread.
Definition manager.c:743
void manager_add_peer(manager_t *manager, const struct sockaddr_in6 *addr, uint32_t itad)
Add known peer to underlaying locator.
Definition manager.c:718
Session manager.
const char * notif_code_strs[]
NOTIFICATION error code strings.
Definition protocol.c:75
runtime_error_t new_msg_notif(void *buff, size_t len, uint8_t error_code, uint8_t error_subcode, size_t datalen, const void *data)
Serialize NOTIFICATION message.
Definition protocol.c:651
const size_t supported_routetypes_size
Supported routetypes constant size.
Definition protocol.c:178
runtime_error_t parse_msg_open_opt(const void *buff, size_t len, const msg_open_opt_t **opt_out)
Deserialize message OPEN optional parameter.
Definition protocol.c:733
runtime_error_t parse_msg_open(const void *buff, size_t len, const msg_open_t **open_out)
Deserialize message OPEN.
Definition protocol.c:710
const char ** notif_code_subcodes_strs[]
subcode strings per code class
Definition protocol.c:112
runtime_error_t parse_capinfo_transmode(const void *buff, size_t len, const capinfo_transmode_t **transmode_out)
Deserialize option transmission mode.
Definition protocol.c:797
runtime_error_t parse_capinfo(const void *buff, size_t len, const capinfo_t **capinfo_out)
Deserialize option capability information.
Definition protocol.c:750
const char * af_strs[]
Address family strings.
Definition protocol.c:65
const capinfo_routetype_t supported_routetypes[]
Supported routetypes constant.
Definition protocol.c:164
runtime_error_t parse_msg_notif(const void *buff, size_t len, const msg_notif_t **notif_out)
Deserialize NOTIFICATION message.
Definition protocol.c:1021
const char * app_proto_str(int app_proto)
Application protocol to string.
Definition protocol.c:122
const char * capinfo_transmode_strs[]
Capability information transmission mode types strings.
Definition protocol.c:58
runtime_error_t new_msg_keepalive(void *buff, size_t len)
Serialize KEEPALIVE message.
Definition protocol.c:632
runtime_error_t new_msg_open(void *buff, size_t len, uint16_t hold, uint32_t itad, uint32_t id, const capinfo_routetype_t *capinfo_routetypes, size_t routetypes_size, capinfo_transmode_t capinfo_transmode)
Serialize OPEN message.
Definition protocol.c:234
const char * open_opt_type_strs[]
Message type strings.
Definition protocol.c:45
runtime_error_t parse_capinfo_routetype(const void *buff, size_t len, const capinfo_routetype_t **routetype_out)
Deserialize option route type.
Definition protocol.c:770
const char * msg_type_strs[]
Message type strings.
Definition protocol.c:37
runtime_error_t parse_msg(const void *buff, size_t len, const msg_t **msg_out)
Deserialize message.
Definition protocol.c:690
const char * capinfo_code_strs[]
Capability information option type strings.
Definition protocol.c:51
Protocol definition header.
uint32_t capinfo_transmode_t
Capability information transmission mode.
Definition protocol.h:124
@ ERROR_ITAD
Definition protocol.h:431
@ ERROR_OPT
Definition protocol.h:438
@ ERROR_CAPINFO_CODE
Definition protocol.h:439
@ ERROR_MSGTYPE
Definition protocol.h:436
@ ERROR_HOLD
Definition protocol.h:430
@ ERROR_VERSION
Definition protocol.h:437
#define PROTO_TRY(o, res, a)
Try-Catch macro for serialization/deserialization functions.
Definition protocol.h:480
void session_shutdown(session_t *session)
Shutdown socket, terminate connection and thread.
Definition session.c:204
int send_notification(int fd, int code, int subcode)
Send notification helper.
Definition session.c:87
const char * id_str(uint32_t id)
LSID string.
Definition session.c:70
void session_change_state(session_t *s, session_state_t new_state)
Change session state.
Definition session.c:78
void * session_loop(void *arg)
Session loop.
Definition session.c:136
void session_destroy(session_t *session)
Destroy session object.
Definition session.c:213
Session logic.
Manager object.
Definition manager.h:38
int run
Definition manager.h:39
Known peer info object.
Definition locator.h:36
Session object.
Definition session.h:53
pthread_t thread
Definition session.h:54
int mark_stop_init
Definition session.h:57
const peer_t * peer
Definition session.h:66
time_t last_read_time
Definition session.h:71
time_t last_write_time
Definition session.h:72
time_t established_time
Definition session.h:70
uint16_t hold
Definition session.h:62
capinfo_routetype_t * routetypes
Definition session.h:76
int fd
Definition session.h:59
session_state_t state
Definition session.h:55
int initiated
Definition session.h:56
uint16_t keepalive
Definition session.h:63
uint32_t id
Definition session.h:67
size_t routetypes_count
Definition session.h:77
capinfo_transmode_t transmode
Definition session.h:75