43#include <netinet/in.h>
55#define _COMPONENT_ "manager"
57#ifndef MAX_BACKOFF_CONNECT_RETRY
58 #define MAX_BACKOFF_CONNECT_RETRY 3600
62static void *connect_loop(
void *arg);
67manager_session_lookup_itad_id(
const manager_t *m, uint32_t itad,
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)
74 return m->sessions[i];
83 for (
size_t i = 0; i < m->sessions_size; i++)
86 return m->sessions[i];
94 const struct sockaddr_in6 *addr)
96 for (
size_t i = 0; i < m->sessions_size; i++)
98 memcmp(&m->sessions[i]->
peer->addr.sin6_addr, &addr->sin6_addr,
99 sizeof(
struct in6_addr)) == 0)
101 return m->sessions[i];
111send_notification_res(
int fd,
int res)
113 uint8_t code = NOTIF_CODE_ERROR_OPEN, subcode = 0;
116 code = NOTIF_CODE_ERROR_MSG;
117 subcode = NOTIF_SUBCODE_MSG_BAD_TYPE;
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;
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;
143 m->sessions[m->sessions_size++] = s;
151 for (
int i = 0; i < m->sessions_size; i++)
152 if (m->sessions[i] == s)
157 memcpy(&m->sessions[s_idx], &m->sessions[s_idx + 1],
158 sizeof(
session_t*) * (m->sessions_size - s_idx - 1));
167compare_itad_id(uint32_t itad1, uint32_t id1, uint32_t itad2, uint32_t id2)
169 return (id1 < id2) || (id1 == id2 && (itad1 < itad2));
184 ERROR(
"colliding connections initiated by same ID");
189 return compare_itad_id(m->itad, m->id, s2->
peer->itad, s2->
id);
193 return compare_itad_id(s1->
peer->itad, s1->
id, m->itad, m->id);
204 int res = 0, toread = 0;
205 SOCK_TRY_RECV(s->
fd, recv_wnd, msg_open_t,
goto sock_error);
207 msg_open_t *open = NULL;
210 res,
goto proto_error
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);
218 if (open->open_itad != s->
peer->itad) {
219 ERROR(
"peer ITAD mismatch");
221 NOTIF_SUBCODE_OPEN_BAD_ITAD);
226 if ((open->open_itad == m->itad) && (open->open_id == m->id)) {
227 ERROR(
"duplicate ID in ITAD detected, colliding peer rejected");
229 NOTIF_SUBCODE_OPEN_BAD_ID);
234 session_t *coll_s = manager_session_lookup_itad_id(m, open->open_itad,
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)) {
247 manager_session_remove(m, coll_s);
249 }
else if (coll_s->
state == STATE_ESTABLISHED) {
250 WARNING(
"collision resolved: kept established connection");
258 if (init_s && (init_s->
initiated == 1) && (init_s != s)) {
259 DEBUG(
"closing old initiating session");
261 pthread_join(init_s->
thread, NULL);
265 s->
id = open->open_id;
266 s->
hold = MIN(s->
peer->hold, open->open_hold);
271 pthread_mutex_lock(&m->sessions_mutex);
272 manager_session_add(m, s);
273 pthread_mutex_unlock(&m->sessions_mutex);
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,
282 msg_open_opt_t *opt = NULL;
285 res,
goto proto_error
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,
301 capinfo_t *capinfo = NULL;
304 res,
goto proto_error
308 capinfos_toread -= res;
310 DEBUG(
" capability info: %s[%d]",
312 capinfo->capinfo_len);
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;
321 sizeof(capinfo_routetype_t);
325 while (routetypes_toread) {
326 SOCK_TRY_RECV(s->
fd, recv_wnd,
327 capinfo_routetype_t,
goto sock_error);
329 capinfo_routetype_t *routetype = NULL;
333 res,
goto proto_error
336 routetype_cur += res;
338 capinfos_toread -= res;
339 routetypes_toread -= res;
341 DEBUG(
" route type: %s:%s",
342 af_strs[routetype->routetype_af],
345 memcpy(crt_cur, routetype, res);
349 case CAPINFO_CODE_TRANSMODE: {
350 SOCK_TRY_RECV(s->
fd, recv_wnd,
357 res,
goto proto_error
361 capinfos_toread -= res;
363 DEBUG(
" transmission mode: %s",
366 if (*transmode != CAPINFO_TRANS_SEND_RECV &&
367 (*transmode == s->
peer->transmode))
369 WARNING(
" transmission mode mismatch");
371 NOTIF_SUBCODE_OPEN_CAP_MISMATCH);
379 capinfo_cur +=
sizeof(capinfo_t) + capinfo->capinfo_len;
384 opt_cur +=
sizeof(msg_open_opt_t) + opt->opt_len;
390 send_notification_res(s->
fd, res);
406peer_handshake(
void *arg)
411 int res = 0, toread = 0;
412 char buff[MAX_MSG_SIZE];
417 s->
peer->hold, m->itad, m->id,
420 res,
goto proto_error
424 send(s->
fd, buff, res, 0),
432 void *recv_wnd = buff;
434 SOCK_TRY_RECV(s->
fd, recv_wnd, msg_t,
goto sock_error);
439 res,
goto proto_error
445 switch (msg->msg_type) {
446 case MSG_TYPE_OPEN: {
447 if (handle_open(m, s, msg, recv_wnd) < 0)
452 res,
goto proto_error
456 send(s->
fd, buff, res, 0),
464 case MSG_TYPE_NOTIFICATION: {
465 SOCK_TRY_RECV(s->
fd, recv_wnd, msg_notif_t,
goto sock_error);
467 msg_notif_t *notif= NULL;
470 res,
goto proto_error
473 DEBUG(
"error code: %s, error subcode: %s",
477 [notif->notif_error_subcode]
480 case MSG_TYPE_KEEPALIVE: {
481 if (s->
state == STATE_OPENCONFIRM)
502 if ((ssize_t)connect_loop(arg) < 0)
506 ERROR(
"unexpected %s message");
513 send_notification_res(s->
fd, res);
519 pthread_mutex_lock(&m->sessions_mutex);
520 manager_session_remove(m, s);
521 pthread_mutex_unlock(&m->sessions_mutex);
534listen_loop(
void *arg)
538 struct sockaddr_in6 peer_addr = { 0 };
539 socklen_t peer_addr_size =
sizeof(
struct sockaddr_in6);
543 int request_fd = accept(m->fd, (struct sockaddr*)&peer_addr,
545 if (request_fd < 0) {
547 ERROR(
"could not accept() peer: %s", strerror(errno));
555 INFO(
"rejecting unknown peer connection: %s",
556 sockaddr_str((
struct sockaddr *)&peer_addr));
561 DEBUG(
"accepted connection from %s, initiating peer",
562 sockaddr_str((
struct sockaddr*)&peer_addr));
568 s->
state = STATE_IDLE;
578 void **handshake_data = malloc(2 *
sizeof(
void*));
579 handshake_data[0] = m;
580 handshake_data[1] = s;
582 pthread_create(&s->
thread, NULL, &peer_handshake, handshake_data);
591maintenance_loop(
void *arg)
594 char buff[MAX_MSG_SIZE];
597 time_t now = time(NULL);
599 for (
int i = 0; i < m->sessions_size; i++) {
601 if (s->
state != STATE_ESTABLISHED || s->
hold == 0)
607 DEBUG(
"sending KEEPALIVE to %s", sockaddr6_str(&s->
peer->addr));
614 NOTIF_CODE_ERROR_EXPIRED, 0, 0, NULL);
616 ERROR(
"session %s hold timer expired %ld",
632update_loop(
void *arg)
637 pthread_mutex_lock(&m->update_mut);
639 while (atomic_load(&m->update_pending) == 0 && m->
run)
640 pthread_cond_wait(&m->update_cond, &m->update_mut);
643 pthread_mutex_unlock(&m->update_mut);
647 int pending = atomic_exchange(&m->update_pending, 0);
649 pthread_mutex_unlock(&m->update_mut);
654 struct timespec start, end;
655 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
657 for (
size_t i = 0; i < m->sessions_size; i++)
660 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
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)));
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;
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;
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;
716 m->def_local_pref = DEF_LOCAL_PREF;
717 m->def_metric = DEF_METRIC;
720 m->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
722 ERROR(
"could not create listen socket: %s", strerror(errno));
726 if (bind(m->fd, (
const struct sockaddr*)listen_addr,
727 sizeof(
struct sockaddr_in6)) < 0)
729 ERROR(
"could not bind() listen socket: %s", strerror(errno));
733 if (listen(m->fd, SOMAXCONN) < 0) {
734 ERROR(
"could not listen() listen socket: %s", strerror(errno));
738 DEBUG(
"started session manager, listening at [%s]:%d",
739 sockaddr_str((
struct sockaddr *)listen_addr),
740 ntohs(listen_addr->sin6_port));
760connect_loop(
void *arg)
766 s->
fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
768 time_t connect_retry = m->connect_retry;
776 int res = connect(s->
fd, (
struct sockaddr*)&s->
peer->addr,
777 sizeof(
struct sockaddr_in6));
782 ERROR(
"connect(): %s", strerror(errno));
785 uint64_t retry_left = connect_retry * 1e6;
791 if (connect_retry < MAX_BACKOFF_CONNECT_RETRY)
801 pthread_mutex_lock(&m->sessions_mutex);
802 manager_session_remove(m, s);
803 pthread_mutex_unlock(&m->sessions_mutex);
819 manager->hold, CAPINFO_TRANS_SEND_RECV);
825 s->
state = STATE_IDLE;
834 pthread_mutex_lock(&manager->sessions_mutex);
835 manager_session_add(manager, s);
836 pthread_mutex_unlock(&manager->sessions_mutex);
838 void **connect_data = malloc(2 *
sizeof(
void*));
839 connect_data[0] = manager;
842 pthread_create(&s->
thread, NULL, &connect_loop, connect_data);
855 pthread_create(&manager->listen_thread, NULL, &listen_loop, manager);
856 pthread_create(&manager->maintenance_thread, NULL, &maintenance_loop,
858 pthread_create(&manager->update_thread, NULL, &update_loop, manager);
862 server_run(manager->server);
864 if (manager->enum_emu)
865 enum_run(manager->enum_emu);
872 atomic_fetch_add(&manager->update_pending, 1);
874 pthread_mutex_lock(&manager->update_mut);
875 pthread_cond_signal(&manager->update_cond);
876 pthread_mutex_unlock(&manager->update_mut);
884 server_stop(manager->server);
886 if (manager->enum_emu)
887 enum_stop(manager->enum_emu);
891 shutdown(manager->fd, SHUT_RDWR);
892 pthread_join(manager->listen_thread, NULL);
893 pthread_join(manager->maintenance_thread, NULL);
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);
905 DEBUG(
"beginning shutdown");
909 for (
size_t i = 0; i < manager->sessions_size; i++) {
910 if (!manager->sessions[i])
916 pthread_join(manager->sessions[i]->
thread, NULL);
920 DEBUG(
"shutdown complete");
927 server_destroy(manager->server);
928 if (manager->enum_emu)
929 enum_destroy(manager->enum_emu);
933 free(manager->sessions);
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
#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
pib_t * pib_new()
Initialize PIB.
Definition pib.c:50
void pib_destroy(pib_t *pib)
Deinitialize PIB.
Definition pib.c:68
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
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.