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