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 <db/trib.h>
39#include <db/pib.h>
40#include <util/util.h>
41
42#include <netinet/in.h>
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <errno.h>
48#include <sys/param.h>
49
50
51#include <arpa/inet.h>
52#include <unistd.h>
53
54#define _COMPONENT_ "manager"
55
56#ifndef MAX_BACKOFF_CONNECT_RETRY
57 #define MAX_BACKOFF_CONNECT_RETRY 3600
58#endif /* MAX_BACKOFF_CONNECT_RETRY */
59
60
61static void *connect_loop(void *arg);
62
63
65static session_t *
66manager_session_lookup_itad_id(const manager_t *m, uint32_t itad,
67 uint32_t id)
68{
69 for (size_t i = 0; i < m->sessions_size; i++)
70 if (m->sessions[i]->peer->itad == itad &&
71 m->sessions[i]->id == id)
72 {
73 return m->sessions[i];
74 }
75 return NULL;
76}
77
79static session_t *
80manager_session_lookup_peer(const manager_t *m, const peer_t *peer)
81{
82 for (size_t i = 0; i < m->sessions_size; i++)
83 if (m->sessions[i]->peer == peer && !m->sessions[i]->mark_stop_init)
84 {
85 return m->sessions[i];
86 }
87 return NULL;
88}
89
93 const struct sockaddr_in6 *addr)
94{
95 for (size_t i = 0; i < m->sessions_size; i++)
96 if (!m->sessions[i]->mark_stop_init &&
97 memcmp(&m->sessions[i]->peer->addr.sin6_addr, &addr->sin6_addr,
98 sizeof(struct in6_addr)) == 0)
99 {
100 return m->sessions[i];
101 }
102 return NULL;
103}
104
109static int
110send_notification_res(int fd, int res)
111{
112 uint8_t code = NOTIF_CODE_ERROR_OPEN, subcode = 0;
113 switch (res) {
114 case ERROR_MSGTYPE:
115 code = NOTIF_CODE_ERROR_MSG;
116 subcode = NOTIF_SUBCODE_MSG_BAD_TYPE;
117 break;
118 case ERROR_VERSION: subcode = NOTIF_SUBCODE_OPEN_UNSUP_VERSION; break;
119 case ERROR_ITAD: subcode = NOTIF_SUBCODE_OPEN_BAD_ITAD; break;
120 case ERROR_OPT: subcode = NOTIF_SUBCODE_OPEN_UNSUP_OPT; break;
121 case ERROR_HOLD: subcode = NOTIF_SUBCODE_OPEN_BAD_HOLD; break;
122 case ERROR_CAPINFO_CODE: subcode = NOTIF_SUBCODE_OPEN_UNSUP_CAP; break;
123 }
124
125 if (subcode)
126 if(send_notification(fd, code, subcode) < 0)
127 return -1;
128
129 return 0;
130}
131
133static void
134manager_session_add(manager_t *m, session_t *s)
135{
136 if (m->sessions_size + 1 > m->sessions_capacity) {
137 m->sessions = realloc(m->sessions,
138 2 * sizeof(session_t) * m->sessions_capacity);
139 m->sessions_capacity *= 2;
140 }
141
142 m->sessions[m->sessions_size++] = s;
143}
144
146static void
147manager_session_remove(manager_t *m, session_t *s)
148{
149 int s_idx = -1;
150 for (int i = 0; i < m->sessions_size; i++)
151 if (m->sessions[i] == s)
152 s_idx = i;
153
154 trib_adj_pair_remove(m->trib, &s->adj_trib_in, &s->adj_trib_out);
156 memcpy(&m->sessions[s_idx], &m->sessions[s_idx + 1],
157 sizeof(session_t*) * (m->sessions_size - s_idx - 1));
158 m->sessions_size--;
159}
160
165static int
166compare_itad_id(uint32_t itad1, uint32_t id1, uint32_t itad2, uint32_t id2)
167{
168 return (id1 < id2) || (id1 == id2 && (itad1 < itad2));
169}
170
178static int
179manager_collision_sessions_compare(const manager_t *m, const session_t *s1,
180 const session_t *s2)
181{
182 if (s1->initiated == s2->initiated) {
183 ERROR("colliding connections initiated by same ID");
184 return 1;
185 } else if (s1->initiated) {
186 /* new session initiated by local
187 * return local < s2 peer */
188 return compare_itad_id(m->itad, m->id, s2->peer->itad, s2->id);
189 } else {
190 /* old connection initiated by local
191 * return s1 peer < local */
192 return compare_itad_id(s1->peer->itad, s1->id, m->itad, m->id);
193 }
194}
195
196/* =================== REQUEST HANDLING ===================================== */
197
199static int
200handle_open(manager_t *m, session_t *s, const msg_t *msg,
201 void *recv_wnd)
202{
203 int res = 0, toread = 0;
204 SOCK_TRY_RECV(s->fd, recv_wnd, msg_open_t, goto sock_error);
205
206 const msg_open_t *open = NULL;
207 PROTO_TRY(
208 parse_msg_open(msg->msg_val, res, &open),
209 res, goto proto_error
210 );
211
212 DEBUG("OPEN(ver %d, hold %d, itad %d, id %s, opts len %d)",
213 open->open_ver, open->open_hold, open->open_itad,
214 id_str(open->open_id), open->open_opts_len);
215
216 /* check received OPEN fields */
217 if (open->open_itad != s->peer->itad) {
218 ERROR("peer ITAD mismatch");
219 send_notification(s->fd, NOTIF_CODE_ERROR_OPEN,
220 NOTIF_SUBCODE_OPEN_BAD_ITAD);
221 return -1;
222 }
223
224 /* duplicate ID in ITAD peer collision detection */
225 if ((open->open_itad == m->itad) && (open->open_id == m->id)) {
226 ERROR("duplicate ID in ITAD detected, colliding peer rejected");
227 send_notification(s->fd, NOTIF_CODE_ERROR_OPEN,
228 NOTIF_SUBCODE_OPEN_BAD_ID);
229 return -1;
230 }
231
232 /* section 6.8 collision detection */
233 session_t *coll_s = manager_session_lookup_itad_id(m, open->open_itad,
234 open->open_id);
235 if (coll_s) {
236 WARNING("collision detected with peer (%d, %s)", open->open_itad,
237 inaddr_str(open->open_id));
238 if (coll_s->state == STATE_OPENCONFIRM) {
239 WARNING("collision resolved: kept higher ID or ITAD");
240 if (manager_collision_sessions_compare(m, s, coll_s)) {
241 send_notification(s->fd, NOTIF_CODE_CEASE, 0);
242 return -1;
243 } else {
244 /* cease, close and destroy old session, remove from vector */
245 session_shutdown(coll_s);
246 manager_session_remove(m, coll_s);
247 }
248 } else if (coll_s->state == STATE_ESTABLISHED) {
249 WARNING("collision resolved: kept established connection");
250 send_notification(s->fd, NOTIF_CODE_CEASE, 0);
251 return -1;
252 }
253 }
254
255 /* find old still initiating session pre-openconfirm if exists and stop it*/
256 session_t *init_s = manager_session_lookup_peer(m, s->peer);
257 if (init_s && (init_s->initiated == 1) && (init_s != s)) {
258 INFO("closing old initiating session");
259 init_s->mark_stop_init = 1;
260 pthread_join(init_s->thread, NULL);
261 }
262
263
264 s->id = open->open_id;
265 s->hold = MIN(s->peer->hold, open->open_hold);
266 s->keepalive = s->hold / 3;
267
268 /* now add session to manager */
269 if (!s->initiated) {
270 pthread_mutex_lock(&m->sessions_mutex);
271 manager_session_add(m, s);
272 pthread_mutex_unlock(&m->sessions_mutex);
273 }
274
275 size_t opts_toread = open->open_opts_len;
276 const void *opt_cur = open->open_opts;
277 while (opts_toread) {
278 SOCK_TRY_RECV(s->fd, recv_wnd, msg_open_opt_t,
279 goto sock_error);
280
281 const msg_open_opt_t *opt = NULL;
282 PROTO_TRY(
283 parse_msg_open_opt(opt_cur, res, &opt),
284 res, goto proto_error
285 );
286
287 opts_toread -= res;
288
289 DEBUG(" option: %s[%d]", open_opt_type_strs[opt->opt_type],
290 opt->opt_len);
291
292 switch (opt->opt_type) {
293 case OPEN_OPT_TYPE_CAPABILITY_INFO: {
294 size_t capinfos_toread = opt->opt_len;
295 const void *capinfo_cur = opt->opt_val;
296 while (capinfos_toread) {
297 SOCK_TRY_RECV(s->fd, recv_wnd, capinfo_t,
298 goto sock_error);
299
300 const capinfo_t *capinfo = NULL;
301 PROTO_TRY(
302 parse_capinfo(capinfo_cur, res, &capinfo),
303 res, goto proto_error
304 );
305
306 opts_toread -= res;
307 capinfos_toread -= res;
308
309 DEBUG(" capability info: %s[%d]",
310 capinfo_code_strs[capinfo->capinfo_code],
311 capinfo->capinfo_len);
312
313
314 switch (capinfo->capinfo_code) {
315 case CAPINFO_CODE_ROUTETYPE: {
316 size_t routetypes_toread = capinfo->capinfo_len;
317 const void *routetype_cur = capinfo->capinfo_val;
318
319 s->routetypes_count = routetypes_toread /
320 sizeof(capinfo_routetype_t);
321 s->routetypes = malloc(routetypes_toread);
322 void *crt_cur = s->routetypes;
323
324 while (routetypes_toread) {
325 SOCK_TRY_RECV(s->fd, recv_wnd,
326 capinfo_routetype_t, goto sock_error);
327
328 const capinfo_routetype_t *routetype = NULL;
329 PROTO_TRY(
330 parse_capinfo_routetype(routetype_cur, res,
331 &routetype),
332 res, goto proto_error
333 );
334
335 routetype_cur += res;
336 opts_toread -= res;
337 capinfos_toread -= res;
338 routetypes_toread -= res;
339
340 DEBUG(" route type: %s:%s",
341 af_strs[routetype->routetype_af],
342 app_proto_str(routetype->routetype_app_proto));
343
344 memcpy(crt_cur, routetype, res);
345 crt_cur += res;
346 }
347 } break;
348 case CAPINFO_CODE_TRANSMODE: {
349 SOCK_TRY_RECV(s->fd, recv_wnd,
350 capinfo_transmode_t, goto sock_error);
351
352 const capinfo_transmode_t *transmode = NULL;
353 PROTO_TRY(
354 parse_capinfo_transmode(capinfo->capinfo_val,
355 res, &transmode),
356 res, goto proto_error
357 );
358
359 opts_toread -= res;
360 capinfos_toread -= res;
361
362 DEBUG(" transmission mode: %s",
363 capinfo_transmode_strs[*transmode]);
364
365 if (*transmode != CAPINFO_TRANS_SEND_RECV &&
366 (*transmode == s->peer->transmode))
367 {
368 WARNING(" transmission mode mismatch");
369 send_notification(s->fd, NOTIF_CODE_ERROR_OPEN,
370 NOTIF_SUBCODE_OPEN_CAP_MISMATCH);
371 return -1;
372 }
373
374 s->transmode = *transmode;
375 } break;
376 }
377
378 capinfo_cur += sizeof(capinfo_t) + capinfo->capinfo_len;
379 }
380 } break;
381 }
382
383 opt_cur += sizeof(msg_open_opt_t) + opt->opt_len;
384 }
385
386 return 0;
387
388proto_error:
389 send_notification_res(s->fd, res);
390
391sock_error:
392 return -1;
393}
394
395
404static void *
405peer_handshake(void *arg)
406{
407 manager_t *m = ((void**)arg)[0];
408 session_t *s = ((void**)arg)[1];
409
410 int res = 0, toread = 0;
411 char buff[MAX_MSG_SIZE];
412
413 /* send OPEN */
414 PROTO_TRY(
415 new_msg_open(buff, MAX_MSG_SIZE,
416 s->peer->hold, m->itad, m->id,
418 s->peer->transmode),
419 res, goto proto_error
420 );
421
422 SOCK_TRY_SEND(
423 send(s->fd, buff, res, 0),
424 goto sock_error
425 );
426 session_change_state(s, STATE_OPENSENT);
427
428
429 /* receive OPEN */
430 while (1) {
431 void *recv_wnd = buff;
432 /* receive and decode message header */
433 SOCK_TRY_RECV(s->fd, recv_wnd, msg_t, goto sock_error);
434
435 const msg_t *msg = NULL;
436 PROTO_TRY(
437 parse_msg(buff, res, &msg),
438 res, goto proto_error
439 );
440
441 DEBUG("received msg: %s[%d]", msg_type_strs[msg->msg_type],
442 msg->msg_len);
443
444 switch (msg->msg_type) {
445 case MSG_TYPE_OPEN: {
446 if (handle_open(m, s, msg, recv_wnd) < 0)
447 goto sock_error;
448
449 PROTO_TRY(
450 new_msg_keepalive(buff, MAX_MSG_SIZE),
451 res, goto proto_error
452 );
453
454 SOCK_TRY_SEND(
455 send(s->fd, buff, res, 0),
456 goto sock_error
457 );
458
459 s->last_write_time = time(NULL);
460
461 session_change_state(s, STATE_OPENCONFIRM);
462 } break;
463 case MSG_TYPE_NOTIFICATION: {
464 SOCK_TRY_RECV(s->fd, recv_wnd, msg_notif_t, goto sock_error);
465
466 const msg_notif_t *notif= NULL;
467 PROTO_TRY(
468 parse_msg_notif(msg->msg_val, res, &notif),
469 res, goto proto_error
470 );
471
472 DEBUG("error code: %s, error subcode: %s",
473 notif_code_strs[notif->notif_error_code],
474 notif_code_subcodes_strs[notif->notif_error_code]
475 ? notif_code_subcodes_strs[notif->notif_error_code]
476 [notif->notif_error_subcode]
477 : "-");
478 } break;
479 case MSG_TYPE_KEEPALIVE: {
480 if (s->state == STATE_OPENCONFIRM)
481 session_change_state(s, STATE_ESTABLISHED);
482 s->last_read_time = time(NULL);
483
484 /* Update peer's Adj-TRIB-Out and send UPDATEs */
485 trib_update_adj_out(m->trib, &s->adj_trib_out);
486 session_update(s, m->id, m->itad);
487
488 /* Hand newly established session off to session_loop
489 * if this function returns, the session has died */
490 session_loop(arg);
491
492 if (s->mark_stop_init)
493 goto sock_error;
494
495 /* If peer disconnects going back to idle, start connect loop */
496 s->initiated = 1;
497 if ((ssize_t)connect_loop(arg) < 0)
498 return NULL;
499 } break;
500 default:
501 ERROR("unexpected %s message");
502 goto sock_error;
503 }
504 }
505
506
507proto_error:
508 send_notification_res(s->fd, res);
509
510sock_error:
511 if (s->mark_stop_init) {
512 send_notification(s->fd, NOTIF_CODE_CEASE, 0);
513 close(s->fd);
514 pthread_mutex_lock(&m->sessions_mutex);
515 manager_session_remove(m, s);
516 pthread_mutex_unlock(&m->sessions_mutex);
517 free(arg);
518 return NULL;
519 }
520 close(s->fd);
521 session_change_state(s, STATE_IDLE);
522 return NULL;
523}
524
525/* =================== CONNECTION HANDLING ================================= */
526
528static void *
529listen_loop(void *arg)
530{
531 manager_t *m = arg;
532
533 struct sockaddr_in6 peer_addr = { 0 };
534 socklen_t peer_addr_size = sizeof(struct sockaddr_in6);
535
536 while (m->run) {
537 /* accept connection (block) */
538 int request_fd = accept(m->fd, (struct sockaddr*)&peer_addr,
539 &peer_addr_size);
540 if (request_fd < 0) {
541 ERROR("could not accept() peer: %s", strerror(errno));
542 return NULL;
543 }
544
545 /* check that connection comes from peer, and that this peer does not
546 * have an active session */
547 const peer_t *peer = locator_lookup(m->locator, &peer_addr);
548 if (!peer) {
549 INFO("rejecting unknown peer connection: %s",
550 sockaddr_str((struct sockaddr *)&peer_addr));
551 close(request_fd);
552 continue;
553 }
554
555 DEBUG("accepted connection from %s, initiating peer",
556 sockaddr_str((struct sockaddr*)&peer_addr));
557
558
559 /* hand off connection to handshake handler on a new thread */
560 session_t *s = malloc(sizeof(session_t));
561 memset(s, 0, sizeof(session_t));
562 s->state = STATE_IDLE;
563 s->peer = peer;
564 s->fd = request_fd;
565 s->initiated = 0;
566 trib_adj_pair_add(m->trib, &s->adj_trib_in, &s->adj_trib_out);
567 s->adj_trib_in.routemap = peer->routemap_in;
568 s->adj_trib_out.routemap = peer->routemap_out;
569
570 void **handshake_data = malloc(2 * sizeof(void*));
571 handshake_data[0] = m;
572 handshake_data[1] = s;
573
574 pthread_create(&s->thread, NULL, &peer_handshake, handshake_data);
575 }
576
577 return NULL;
578}
579
580
582static void *
583maintenance_loop(void *arg)
584{
585 manager_t *m = arg;
586 char buff[MAX_MSG_SIZE];
587
588 while (m->run) {
589 time_t now = time(NULL);
590
591 for (int i = 0; i < m->sessions_size; i++) {
592 session_t *s = m->sessions[i];
593 if (s->state != STATE_ESTABLISHED || s->hold == 0)
594 continue;
595
596 if (now - s->last_write_time > s->keepalive) {
597 int n = new_msg_keepalive(buff, sizeof(buff));
598
599 DEBUG("sending KEEPALIVE to %s", sockaddr6_str(&s->peer->addr));
600 SOCK_TRY_SEND(send(s->fd, buff, n, 0), session_shutdown(s));
601 s->last_write_time = now;
602 }
603
604 if (now - s->last_read_time > s->hold) {
605 int n = new_msg_notif(buff, sizeof(buff),
606 NOTIF_CODE_ERROR_EXPIRED, 0, 0, NULL);
607
608 ERROR("session %s hold timer expired %ld",
609 sockaddr6_str(&s->peer->addr), s->last_read_time);
610 SOCK_TRY_SEND(send(s->fd, buff, n, 0), session_shutdown(s));
612 }
613
614 }
615
616 usleep(100000);
617 }
618
619 return NULL;
620}
621
622static void *
623update_loop(void *arg)
624{
625 manager_t *m = arg;
626
627 while (m->run) {
628 pthread_mutex_lock(&m->update_mut);
629 pthread_cond_wait(&m->update_cond, &m->update_mut);
630
631 if (!m->run)
632 return NULL;
633
634 for (size_t i = 0; i < m->sessions_size; i++)
635 session_update(m->sessions[i], m->id, m->itad);
636
637 pthread_mutex_unlock(&m->update_mut);
638 }
639
640 return NULL;
641}
642
643
644manager_t *
645manager_new(const struct sockaddr_in6 *listen_addr)
646{
647 static manager_t manager = { 0 };
648
649 if (manager.itad)
650 return NULL;
651
652 manager_t *m = &manager;
653 memset(m, 0, sizeof(manager_t));
654
655 /* init values */
656 m->run = 0;
657 m->listen_thread = 0;
658 m->maintenance_thread = 0;
659 m->update_mut = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
660 m->update_cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
661 m->fd = 0;
662
663 m->itad = 0;
664 m->id = 0;
665
666 m->locator = locator_new();
667 m->trib = trib_new(m->itad);
668 m->pib = pib_new();
669
670 m->sessions_size = 0;
671 m->sessions_capacity = 16;
672 m->sessions = malloc(m->sessions_capacity * sizeof(session_t*));
673 memset(m->sessions, 0, m->sessions_capacity * sizeof(session_t*));
674 m->sessions_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
675
676 m->connect_retry = TIMER_CONNECT_RETRY;
677 m->hold = TIMER_HOLD_TIME;
678 m->keepalive = TIMER_KEEPALIVE;
679 m->max_purge_time = TIMER_MAX_PURGE_TIME;
680 m->disable_time = TIMER_DISABLE_TIME;
681 m->min_itad_orig_int = TIMER_MIN_ITAD_ORIG_INT;
682 m->min_route_advert_int = TIMER_MIN_ROUTE_ADVERT_INT;
683
684 m->def_local_pref = DEF_LOCAL_PREF;
685 m->def_metric = DEF_METRIC;
686
687 /* create listen socket */
688 m->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
689 if (m->fd < 0) {
690 ERROR("could not create listen socket: %s", strerror(errno));
691 goto error;
692 }
693
694 if (bind(m->fd, (const struct sockaddr*)listen_addr,
695 sizeof(struct sockaddr_in6)) < 0)
696 {
697 ERROR("could not bind() listen socket: %s", strerror(errno));
698 goto error;
699 }
700
701 if (listen(m->fd, SOMAXCONN) < 0) {
702 ERROR("could not listen() listen socket: %s", strerror(errno));
703 goto error;
704 }
705
706 DEBUG("started session manager, listening at [%s]:%d",
707 sockaddr_str((struct sockaddr *)listen_addr),
708 ntohs(listen_addr->sin6_port));
709
710 return m;
711
712error:
713 locator_destroy(m->locator);
714 trib_destroy(m->trib);
715 pib_destroy(m->pib);
716 free(m->sessions);
717 return NULL;
718}
719
720
721/* ===================== SESSION INITIATION ================================= */
722
727static void *
728connect_loop(void *arg)
729{
730 manager_t *m = ((void**)arg)[0];
731 session_t *s = ((void**)arg)[1];
732
733 /* create socket every time we try to connect */
734 s->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
735
736 time_t connect_retry = m->connect_retry;
737
738 while (1) {
739 if (s->mark_stop_init) {
740 close(s->fd);
741 pthread_mutex_lock(&m->sessions_mutex);
742 manager_session_remove(m, s);
743 pthread_mutex_unlock(&m->sessions_mutex);
744 free(arg);
745 return (void*)-1L;
746 }
747
748 session_change_state(s, STATE_CONNECT);
749
750 int res = connect(s->fd, (struct sockaddr*)&s->peer->addr,
751 sizeof(struct sockaddr_in6));
752
753 if (res < 0) {
754 ERROR("connect(): %s", strerror(errno));
755 session_change_state(s, STATE_IDLE);
756
757 uint64_t retry_left = connect_retry * 1e6;
758 while (retry_left && !s->mark_stop_init) {
759 usleep(100e3);
760 retry_left -= 100e3;
761 }
762
763 if (connect_retry < MAX_BACKOFF_CONNECT_RETRY)
764 connect_retry *= 2;
765 continue;
766 }
767
768 break;
769 }
770
771 /* TCP channel established, hand off to request handler */
772 peer_handshake(arg);
773 return NULL;
774}
775
776
777void
778manager_peer_add(manager_t *manager, const struct sockaddr_in6 *addr,
779 uint32_t itad)
780{
781 /* add peer to peer locator */
782 const peer_t *peer = locator_add(manager->locator, addr, itad,
783 manager->hold, CAPINFO_TRANS_SEND_RECV);
784
785 /* create session object and hand off to connect loop */
786 session_t *s = malloc(sizeof(session_t));
787 memset(s, 0, sizeof(session_t));
788 s->peer = peer;
789 s->state = STATE_IDLE;
790 s->initiated = 1;
791 trib_adj_pair_add(manager->trib, &s->adj_trib_in, &s->adj_trib_out);
792 s->adj_trib_in.routemap = peer->routemap_in;
793 s->adj_trib_out.routemap = peer->routemap_out;
794
795 /* add session to manager session vector */
796 pthread_mutex_lock(&manager->sessions_mutex);
797 manager_session_add(manager, s);
798 pthread_mutex_unlock(&manager->sessions_mutex);
799
800 void **connect_data = malloc(2 * sizeof(void*));
801 connect_data[0] = manager;
802 connect_data[1] = s;
803
804 pthread_create(&s->thread, NULL, &connect_loop, connect_data);
805}
806
807peer_t *
808manager_peer_find(manager_t *manager, const struct sockaddr_in6 *addr)
809{
810 return locator_lookup(manager->locator, addr);
811}
812
813void
815{
816 manager->run = 1;
817 pthread_create(&manager->listen_thread, NULL, &listen_loop, manager);
818 pthread_create(&manager->maintenance_thread, NULL, &maintenance_loop,
819 manager);
820 pthread_create(&manager->update_thread, NULL, &update_loop, manager);
821}
822
823void
825{
826 /* wake up updater thread */
827 pthread_mutex_lock(&manager->update_mut);
828 pthread_cond_signal(&manager->update_cond);
829 pthread_mutex_unlock(&manager->update_mut);
830}
831
832void
834{
835 manager->run = 0;
836 shutdown(manager->fd, SHUT_RDWR);
837 pthread_join(manager->listen_thread, NULL);
838 pthread_join(manager->maintenance_thread, NULL);
839
840 pthread_mutex_lock(&manager->update_mut);
841 pthread_cond_signal(&manager->update_cond);
842 pthread_mutex_unlock(&manager->update_mut);
843 pthread_join(manager->update_thread, NULL);
844}
845
846void
848{
849 DEBUG("beginning shutdown");
850
851 manager_stop(manager);
852
853 for (size_t i = 0; i < manager->sessions_size; i++) {
854 if (!manager->sessions[i])
855 continue;
856 /* this indirectly causes session thread to call
857 * manager_session_remove() and kill itself */
858 manager->sessions[i]->mark_stop_init = 1;
859 session_shutdown(manager->sessions[i]);
860 pthread_join(manager->sessions[i]->thread, NULL);
861 }
862
863
864 DEBUG("shutdown complete");
865}
866
867void
869{
870 locator_destroy(manager->locator);
871 trib_destroy(manager->trib);
872 pib_destroy(manager->pib);
873 free(manager->sessions);
874 manager->itad = 0;
875}
876
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
peer_t * locator_lookup(locator_t *locator, const struct sockaddr_in6 *addr)
Lookup peer by its address.
Definition locator.c:68
void locator_destroy(locator_t *locator)
Destroy locator object.
Definition locator.c:87
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:833
manager_t * manager_new(const struct sockaddr_in6 *listen_addr)
Create manager and bind socket.
Definition manager.c:645
void manager_destroy(manager_t *manager)
Destroy manager object.
Definition manager.c:868
session_t * manager_session_lookup_address(const manager_t *m, const struct sockaddr_in6 *addr)
Lookup session by locator peer.
Definition manager.c:92
void manager_shutdown(manager_t *manager)
Shut down manager and all sessions.
Definition manager.c:847
void manager_run(manager_t *manager)
Run accept loop in thread.
Definition manager.c:814
peer_t * manager_peer_find(manager_t *manager, const struct sockaddr_in6 *addr)
Find known peer by address.
Definition manager.c:808
void manager_peer_add(manager_t *manager, const struct sockaddr_in6 *addr, uint32_t itad)
Add known peer to underlaying locator.
Definition manager.c:778
void manager_schedule_update(manager_t *manager)
Schedule UPDATEs.
Definition manager.c:824
Session manager.
pib_t * pib_new()
Initialize PIB.
Definition pib.c:50
void pib_destroy(pib_t *pib)
Deinitialize PIB.
Definition pib.c:68
Policy Information Base.
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:649
const size_t supported_routetypes_size
Supported routetypes constant size.
Definition protocol.c:181
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:731
runtime_error_t parse_msg_open(const void *buff, size_t len, const msg_open_t **open_out)
Deserialize message OPEN.
Definition protocol.c:708
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:795
runtime_error_t parse_capinfo(const void *buff, size_t len, const capinfo_t **capinfo_out)
Deserialize option capability information.
Definition protocol.c:748
const char * af_strs[]
Address family strings.
Definition protocol.c:65
const capinfo_routetype_t supported_routetypes[]
Supported routetypes constant.
Definition protocol.c:167
runtime_error_t parse_msg_notif(const void *buff, size_t len, const msg_notif_t **notif_out)
Deserialize NOTIFICATION message.
Definition protocol.c:1019
const char * app_proto_str(int app_proto)
Application protocol to string.
Definition protocol.c:125
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:630
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:237
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:768
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:688
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:434
@ ERROR_OPT
Definition protocol.h:441
@ ERROR_CAPINFO_CODE
Definition protocol.h:442
@ ERROR_MSGTYPE
Definition protocol.h:439
@ ERROR_HOLD
Definition protocol.h:433
@ ERROR_VERSION
Definition protocol.h:440
#define PROTO_TRY(o, res, a)
Try-Catch macro for serialization/deserialization functions.
Definition protocol.h:488
void session_shutdown(session_t *session)
Shutdown socket, terminate connection and thread.
Definition session.c:413
int send_notification(int fd, int code, int subcode)
Send notification helper.
Definition session.c:89
const char * id_str(uint32_t id)
LSID string.
Definition session.c:71
void session_update(const session_t *s, uint32_t local_id, uint32_t local_itad)
Update session.
Definition session.c:381
void session_change_state(session_t *s, session_state_t new_state)
Change session state.
Definition session.c:79
void * session_loop(void *arg)
Session loop.
Definition session.c:137
void session_destroy(session_t *session)
Destroy session object.
Definition session.c:423
Session logic.
Manager object.
Definition manager.h:41
int run
Definition manager.h:42
Known peer info object.
Definition locator.h:37
Session object.
Definition session.h:54
pthread_t thread
Definition session.h:55
int mark_stop_init
Definition session.h:58
const peer_t * peer
Definition session.h:68
time_t last_read_time
Definition session.h:73
time_t last_write_time
Definition session.h:74
uint16_t hold
Definition session.h:64
capinfo_routetype_t * routetypes
Definition session.h:81
int fd
Definition session.h:61
session_state_t state
Definition session.h:56
int initiated
Definition session.h:57
uint16_t keepalive
Definition session.h:65
table_t adj_trib_in
Definition session.h:85
uint32_t id
Definition session.h:69
size_t routetypes_count
Definition session.h:82
table_t adj_trib_out
Definition session.h:86
capinfo_transmode_t transmode
Definition session.h:80
routemap_t * routemap
Definition trib.h:103
void trib_destroy(trib_t *trib)
Deinit TRIB structure.
Definition trib.c:174
void trib_adj_pair_add(trib_t *trib, table_t *in, table_t *out)
Add and init pair of tables owned by caller.
Definition trib.c:138
void trib_update_adj_out(trib_t *trib, table_t *adj_trib_out)
Update an Adj-TRIB-Out.
Definition trib.c:339
trib_t * trib_new(uint32_t local_itad)
Initialize TRIB structure.
Definition trib.c:115
Telephony Routing Information Base.