Initialize route table with local routes. Fix bugs.
[trust_router.git] / tr / tr_trp.c
1 #include <pthread.h>
2 #include <fcntl.h>
3 #include <event2/event.h>
4 #include <talloc.h>
5 #include <errno.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <sys/time.h>
9 #include <time.h>
10
11 #include <gsscon.h>
12 #include <tr_rp.h>
13 #include <trp_internal.h>
14 #include <trp_ptable.h>
15 #include <trp_rtable.h>
16 #include <tr_config.h>
17 #include <tr_event.h>
18 #include <tr_msg.h>
19 #include <tr_trp.h>
20 #include <tr_debug.h>
21
22 /* data for event callbacks */
23 struct tr_trps_event_cookie {
24   TRPS_INSTANCE *trps;
25   TR_CFG_MGR *cfg_mgr;
26   struct event *ev;
27 };
28
29 /* callback to schedule event to process messages */
30 static void tr_trps_mq_cb(TR_MQ *mq, void *arg)
31 {
32   struct event *mq_ev=(struct event *)arg;
33   event_active(mq_ev, 0, 0);
34 }
35
36 static void msg_free_helper(void *p)
37 {
38   tr_msg_free_decoded((TR_MSG *)p);
39 }
40 /* takes a TR_MSG and puts it in a TR_MQ_MSG for processing by the main thread */
41 static TRP_RC tr_trps_msg_handler(TRPS_INSTANCE *trps,
42                                   TRP_CONNECTION *conn,
43                                   TR_MSG *tr_msg)
44 {
45   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
46   TR_MQ_MSG *mq_msg=NULL;
47
48   /* n.b., conn is available here, but do not hold onto the reference
49    * because it may be cleaned up if the originating connection goes
50    * down before the message is processed */
51   mq_msg=tr_mq_msg_new(tmp_ctx, "tr_msg");
52   if (mq_msg==NULL) {
53     return TRP_NOMEM;
54   }
55   tr_mq_msg_set_payload(mq_msg, (void *)tr_msg, msg_free_helper);
56   trps_mq_append(trps, mq_msg);
57   talloc_free(tmp_ctx); /* cleans up the message if it did not get appended correctly */
58   return TRP_SUCCESS;
59 }
60
61
62 static int tr_trps_gss_handler(gss_name_t client_name, gss_buffer_t gss_name,
63                                void *cookie_in)
64 {
65   TR_RP_CLIENT *rp;
66   struct tr_trps_event_cookie *cookie=(struct tr_trps_event_cookie *)cookie_in;
67   TRPS_INSTANCE *trps = cookie->trps;
68   TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
69   TR_NAME name={gss_name->value, gss_name->length};
70
71   tr_debug("tr_trps_gss_handler()");
72
73   if ((!client_name) || (!gss_name) || (!trps) || (!cfg_mgr)) {
74     tr_debug("tr_trps_gss_handler: Bad parameters.");
75     return -1;
76   }
77   
78   /* look up the RP client matching the GSS name */
79   if ((NULL == (rp = tr_rp_client_lookup(cfg_mgr->active->rp_clients, &name)))) {
80     tr_debug("tr_trps_gss_handler: Unknown GSS name %.*s", name.len, name.buf);
81     return -1;
82   }
83
84   /*trps->rp_gss = rp;*/
85   tr_debug("Client's GSS Name: %.*s", name.len, name.buf);
86
87   return 0;
88 }
89
90 /* data passed to thread */
91 struct trps_thread_data {
92   TRP_CONNECTION *conn;
93   TRPS_INSTANCE *trps;
94 };
95 /* thread to handle GSS connections to peers */
96 static void *tr_trps_thread(void *arg)
97 {
98   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
99   struct trps_thread_data *thread_data=talloc_get_type_abort(arg, struct trps_thread_data);
100   TRP_CONNECTION *conn=thread_data->conn;
101   TRPS_INSTANCE *trps=thread_data->trps;
102   TR_MQ_MSG *msg=NULL;
103
104   tr_debug("tr_trps_thread: started");
105   trps_handle_connection(trps, conn);
106
107   msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPS_DISCONNECTED);
108   tr_mq_msg_set_payload(msg, (void *)conn, NULL); /* do not pass a free routine */
109   if (msg==NULL)
110     tr_err("tr_trps_thread: error allocating TR_MQ_MSG");
111   else
112     trps_mq_append(trps, msg);
113
114   tr_debug("tr_trps_thread: exit");
115   talloc_free(tmp_ctx);
116   return NULL;
117 }
118
119 /* called when a connection to the TRPS port is received */
120 static void tr_trps_event_cb(int listener, short event, void *arg)
121 {
122   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
123   TRPS_INSTANCE *trps = talloc_get_type_abort(arg, TRPS_INSTANCE); /* aborts on wrong type */
124   TRP_CONNECTION *conn=NULL;
125   TR_NAME *gssname=NULL;
126   char *name=NULL;
127   struct trps_thread_data *thread_data=NULL;
128
129   if (0==(event & EV_READ)) {
130     tr_debug("tr_trps_event_cb: unexpected event on TRPS socket (event=0x%X)", event);
131   } else {
132     /* create a thread to handle this connection */
133     asprintf(&name, "trustrouter@%s", trps->hostname);
134     gssname=tr_new_name(name);
135     free(name); name=NULL;
136     conn=trp_connection_accept(tmp_ctx, listener, gssname);
137     if (conn!=NULL) {
138       /* need to monitor this fd and trigger events when read becomes possible */
139       thread_data=talloc(conn, struct trps_thread_data);
140       if (thread_data==NULL) {
141         tr_err("tr_trps_event_cb: unable to allocate trps_thread_data");
142         talloc_free(tmp_ctx);
143         return;
144       }
145       thread_data->conn=conn;
146       thread_data->trps=trps;
147       pthread_create(trp_connection_get_thread(conn), NULL, tr_trps_thread, thread_data);
148       pthread_detach(*(trp_connection_get_thread(conn))); /* we will not rejoin the thread */
149       trps_add_connection(trps, conn); /* remember the connection */
150     }
151   }
152   talloc_free(tmp_ctx);
153 }
154
155 static void tr_trps_cleanup_conn(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
156 {
157   /* everything belonging to the thread is in the TRP_CONNECTION
158    * associated with it */
159   trps_remove_connection(trps, conn);
160   trp_connection_free(conn);
161   tr_debug("Deleted connection");
162 }
163
164 #if 0
165 static void tr_trpc_abort(TRPC_INSTANCE *trpc)
166 {
167   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
168   TR_MQ_MSG *msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_ABORT);
169   tr_mq_msg_set_payload(msg, (void *)conn, NULL); /* do not pass a free routine */
170   trpc_mq_append(msg); /* gives msg over to the queue to manage */
171   
172 }
173 #endif
174
175 static void tr_trps_cleanup_trpc(TRPS_INSTANCE *trps, TRPC_INSTANCE *trpc)
176 {
177   /* everything belonging to the thread is in the TRP_CONNECTION
178    * associated with it */
179 /*  tr_trpc_abort(trpc); */ /* tell trpc to abort */
180   trps_remove_trpc(trps, trpc);
181   trpc_free(trpc);
182   tr_debug("Deleted connection");
183 }
184
185 static void tr_trps_print_route_table(TRPS_INSTANCE *trps, FILE *f)
186 {
187   char *table=trp_rtable_to_str(NULL, trps->rtable, " | ", NULL);
188   if (table==NULL)
189     fprintf(f, "Unable to print route table.\n");
190   else {
191     fprintf(f, "%s\n", table);
192     talloc_free(table);
193   }
194 }
195
196 static void tr_trps_process_mq(int socket, short event, void *arg)
197 {
198   TRPS_INSTANCE *trps=talloc_get_type_abort(arg, TRPS_INSTANCE);
199   TR_MQ_MSG *msg=NULL;
200   const char *s=NULL;
201
202   msg=trps_mq_pop(trps);
203   while (msg!=NULL) {
204     s=tr_mq_msg_get_message(msg);
205     if (0==strcmp(s, TR_MQMSG_TRPS_DISCONNECTED)) {
206       tr_trps_cleanup_conn(trps,
207                            talloc_get_type_abort(tr_mq_msg_get_payload(msg),
208                                                  TRP_CONNECTION));
209     }
210     else if (0==strcmp(s, TR_MQMSG_TRPC_DISCONNECTED)) {
211       /* trpc connection died */
212       tr_trps_cleanup_trpc(trps,
213                            talloc_get_type_abort(tr_mq_msg_get_payload(msg),
214                                                  TRPC_INSTANCE));
215     }
216
217     else if (0==strcmp(s, "tr_msg")) {
218       if (trps_handle_tr_msg(trps, tr_mq_msg_get_payload(msg))!=TRP_SUCCESS)
219         tr_notice("tr_trps_process_mq: error handling message.");
220       else {
221         tr_trps_print_route_table(trps, stderr);
222       }
223     }
224     else
225       tr_notice("tr_trps_process_mq: unknown message '%s' received.", tr_mq_msg_get_message(msg));
226
227     tr_mq_msg_free(msg);
228     msg=trps_mq_pop(trps);
229   }
230 }
231
232 static void tr_trps_update(int listener, short event, void *arg)
233 {
234   struct tr_trps_event_cookie *cookie=talloc_get_type_abort(arg, struct tr_trps_event_cookie);
235   TRPS_INSTANCE *trps=cookie->trps;
236   struct event *ev=cookie->ev;
237
238   tr_debug("tr_trps_update: sending scheduled route updates.");
239   trps_scheduled_update(trps);
240   event_add(ev, &(trps->update_interval));
241 }
242
243 static void tr_trps_sweep(int listener, short event, void *arg)
244 {
245   struct tr_trps_event_cookie *cookie=talloc_get_type_abort(arg, struct tr_trps_event_cookie);
246   TRPS_INSTANCE *trps=cookie->trps;
247   struct event *ev=cookie->ev;
248
249   tr_debug("tr_trps_sweep: sweeping routes.");
250   trps_sweep_routes(trps);
251   /* schedule the event to run again */
252   event_add(ev, &(trps->sweep_interval));
253 }
254
255 static void tr_connection_update(int listener, short event, void *arg)
256 {
257   struct tr_trps_event_cookie *cookie=talloc_get_type_abort(arg, struct tr_trps_event_cookie);
258   TRPS_INSTANCE *trps=cookie->trps;
259   struct event *ev=cookie->ev;
260
261   tr_debug("tr_connection_update: checking peer connections.");
262   tr_connect_to_peers(trps);
263   /* schedule the event to run again */
264   event_add(ev, &(trps->connect_interval));
265 }
266
267 static int tr_trps_events_destructor(void *obj)
268 {
269   TR_TRPS_EVENTS *ev=talloc_get_type_abort(obj, TR_TRPS_EVENTS);
270   if (ev->mq_ev!=NULL)
271     event_free(ev->mq_ev);
272   if (ev->connect_ev!=NULL)
273     event_free(ev->connect_ev);
274   if (ev->update_ev!=NULL)
275     event_free(ev->update_ev);
276   if (ev->sweep_ev!=NULL)
277     event_free(ev->sweep_ev);
278   return 0;
279 }
280 TR_TRPS_EVENTS *tr_trps_events_new(TALLOC_CTX *mem_ctx)
281 {
282   TR_TRPS_EVENTS *ev=talloc(mem_ctx, TR_TRPS_EVENTS);
283   if (ev!=NULL) {
284     ev->listen_ev=talloc(ev, struct tr_socket_event);
285     ev->mq_ev=NULL;
286     ev->connect_ev=NULL;
287     ev->update_ev=NULL;
288     ev->sweep_ev=NULL;
289     if (ev->listen_ev==NULL) {
290       talloc_free(ev);
291       ev=NULL;
292     }
293     talloc_set_destructor((void *)ev, tr_trps_events_destructor);
294   }
295   return ev;
296 }
297
298 /* Configure the trps instance and set up its event handler.
299  * Fills in trps_ev, which should be allocated by caller. */
300 TRP_RC tr_trps_event_init(struct event_base *base,
301                        TRPS_INSTANCE *trps,
302                        TR_CFG_MGR *cfg_mgr,
303                        TR_TRPS_EVENTS *trps_ev)
304 {
305   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
306   struct tr_socket_event *listen_ev=NULL;
307   struct tr_trps_event_cookie *trps_cookie=NULL;
308   struct tr_trps_event_cookie *connection_cookie=NULL;
309   struct tr_trps_event_cookie *update_cookie=NULL;
310   struct tr_trps_event_cookie *sweep_cookie=NULL;
311   TRP_RC retval=TRP_ERROR;
312
313   if (trps_ev == NULL) {
314     tr_debug("tr_trps_event_init: Null trps_ev.");
315     retval=TRP_BADARG;
316     goto cleanup;
317   }
318
319   /* get convenient handles */
320   listen_ev=trps_ev->listen_ev;
321
322   /* Create the cookie for callbacks. It is part of the trps context, so it will
323    * be cleaned up when trps is freed by talloc_free. */
324   trps_cookie=talloc(tmp_ctx, struct tr_trps_event_cookie);
325   if (trps_cookie == NULL) {
326     tr_debug("tr_trps_event_init: Unable to allocate trps_cookie.");
327     retval=TRP_NOMEM;
328     goto cleanup;
329   }
330   trps_cookie->trps=trps;
331   trps_cookie->cfg_mgr=cfg_mgr;
332   talloc_steal(trps, trps_cookie);
333
334   /* get a trps listener */
335   listen_ev->sock_fd=trps_get_listener(trps,
336                                        tr_trps_msg_handler,
337                                        tr_trps_gss_handler,
338                                        cfg_mgr->active->internal->hostname,
339                                        cfg_mgr->active->internal->trps_port,
340                                        (void *)trps_cookie);
341   if (listen_ev->sock_fd < 0) {
342     tr_crit("Error opening TRP server socket.");
343     retval=TRP_ERROR;
344     goto cleanup;
345   }
346   trps_cookie->ev=listen_ev->ev; /* in case it needs to frob the event */
347   
348   /* and its event */
349   listen_ev->ev=event_new(base,
350                           listen_ev->sock_fd,
351                           EV_READ|EV_PERSIST,
352                           tr_trps_event_cb,
353                           (void *)trps);
354   event_add(listen_ev->ev, NULL);
355   
356   /* now set up message queue processing event, only triggered by
357    * tr_trps_mq_cb() */
358   trps_ev->mq_ev=event_new(base,
359                            0,
360                            EV_PERSIST,
361                            tr_trps_process_mq,
362                            (void *)trps);
363   tr_mq_set_notify_cb(trps->mq, tr_trps_mq_cb, trps_ev->mq_ev);
364
365   /* now set up the peer connection timer event */
366   connection_cookie=talloc(tmp_ctx, struct tr_trps_event_cookie);
367   if (connection_cookie == NULL) {
368     tr_debug("tr_trps_event_init: Unable to allocate connection_cookie.");
369     retval=TRP_NOMEM;
370     goto cleanup;
371   }
372   connection_cookie->trps=trps;
373   connection_cookie->cfg_mgr=cfg_mgr;
374   talloc_steal(trps, connection_cookie);
375   trps_ev->connect_ev=event_new(base, -1, EV_TIMEOUT, tr_connection_update, (void *)connection_cookie);
376   connection_cookie->ev=trps_ev->connect_ev; /* in case it needs to frob the event */
377   event_add(trps_ev->connect_ev, &(trps->connect_interval));
378
379   /* now set up the route update timer event */
380   update_cookie=talloc(tmp_ctx, struct tr_trps_event_cookie);
381   if (update_cookie == NULL) {
382     tr_debug("tr_trps_event_init: Unable to allocate update_cookie.");
383     retval=TRP_NOMEM;
384     goto cleanup;
385   }
386   update_cookie->trps=trps;
387   update_cookie->cfg_mgr=cfg_mgr;
388   talloc_steal(trps, update_cookie);
389   trps_ev->update_ev=event_new(base, -1, EV_TIMEOUT, tr_trps_update, (void *)update_cookie);
390   update_cookie->ev=trps_ev->update_ev; /* in case it needs to frob the event */
391   event_add(trps_ev->update_ev, &(trps->update_interval));
392
393   /* now set up the route table sweep timer event */
394   sweep_cookie=talloc(tmp_ctx, struct tr_trps_event_cookie);
395   if (sweep_cookie == NULL) {
396     tr_debug("tr_trps_event_init: Unable to allocate sweep_cookie.");
397     retval=TRP_NOMEM;
398     goto cleanup;
399   }
400   sweep_cookie->trps=trps;
401   sweep_cookie->cfg_mgr=cfg_mgr;
402   talloc_steal(trps, sweep_cookie);
403   trps_ev->sweep_ev=event_new(base, -1, EV_TIMEOUT, tr_trps_sweep, (void *)sweep_cookie);
404   sweep_cookie->ev=trps_ev->sweep_ev; /* in case it needs to frob the event */
405   event_add(trps_ev->sweep_ev, &(trps->sweep_interval));
406
407   retval=TRP_SUCCESS;
408
409 cleanup:
410   talloc_free(tmp_ctx);
411   return retval;
412 }
413
414
415 struct trpc_notify_cb_data {
416   int msg_ready;
417   pthread_cond_t cond;
418   pthread_mutex_t mutex;
419 };
420
421 static void tr_trpc_mq_cb(TR_MQ *mq, void *arg)
422 {
423   struct trpc_notify_cb_data *cb_data=(struct trpc_notify_cb_data *) arg;
424   pthread_mutex_lock(&(cb_data->mutex));
425   if (!cb_data->msg_ready) {
426     cb_data->msg_ready=1;
427     pthread_cond_signal(&(cb_data->cond));
428   }
429   pthread_mutex_unlock(&(cb_data->mutex));
430 }
431
432 /* data passed to thread */
433 struct trpc_thread_data {
434   TRPC_INSTANCE *trpc;
435   TRPS_INSTANCE *trps;
436 };
437 static void *tr_trpc_thread(void *arg)
438 {
439   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
440   struct trpc_thread_data *thread_data=talloc_get_type_abort(arg, struct trpc_thread_data);
441   TRPC_INSTANCE *trpc=thread_data->trpc;
442   TRPS_INSTANCE *trps=thread_data->trps;
443   TRP_RC rc=TRP_ERROR;
444   TR_MQ_MSG *msg=NULL;
445   const char *msg_type=NULL;
446   char *encoded_msg=NULL;
447
448   struct trpc_notify_cb_data cb_data={0,
449                                       PTHREAD_COND_INITIALIZER,
450                                       PTHREAD_MUTEX_INITIALIZER};
451
452   tr_debug("tr_trpc_thread: started");
453
454   /* set up the mq for receiving */
455   pthread_mutex_lock(&(cb_data.mutex)); /* hold this lock until we enter the main loop */
456
457   tr_mq_lock(trpc->mq);
458   tr_mq_set_notify_cb(trpc->mq, tr_trpc_mq_cb, (void *) &cb_data);
459   tr_mq_unlock(trpc->mq);
460
461   rc=trpc_connect(trpc);
462   if (rc!=TRP_SUCCESS) {
463     tr_notice("tr_trpc_thread: failed to initiate connection to %s:%d.",
464               trpc_get_server(trpc),
465               trpc_get_port(trpc));
466   } else {
467     while (1) {
468       cb_data.msg_ready=0;
469       pthread_cond_wait(&(cb_data.cond), &(cb_data.mutex));
470       /* verify the condition */
471       if (cb_data.msg_ready) {
472         msg=trpc_mq_pop(trpc);
473         if (msg==NULL) {
474           /* no message in the queue */
475           tr_err("tr_trpc_thread: notified of msg, but queue empty");
476           break;
477         }
478
479         msg_type=tr_mq_msg_get_message(msg);
480
481         if (0==strcmp(msg_type, TR_MQMSG_ABORT)) {
482           tr_mq_msg_free(msg);
483           break; /* exit loop */
484         }
485         else if (0==strcmp(msg_type, TR_MQMSG_TRPC_SEND)) {
486           encoded_msg=tr_mq_msg_get_payload(msg);
487           if (encoded_msg==NULL)
488             tr_notice("tr_trpc_thread: null outgoing TRP message.");
489           else {
490             rc = trpc_send_msg(trpc, encoded_msg);
491             if (rc!=TRP_SUCCESS) {
492               tr_notice("tr_trpc_thread: trpc_send_msg failed.");
493               tr_mq_msg_free(msg);
494               break;
495             }
496           }
497         }
498         else
499           tr_notice("tr_trpc_thread: unknown message '%s' received.", msg_type);
500
501         tr_mq_msg_free(msg);
502       }
503     }
504   }
505
506   msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPC_DISCONNECTED);
507   tr_mq_msg_set_payload(msg, (void *)trpc, NULL); /* do not pass a free routine */
508   if (msg==NULL)
509     tr_err("tr_trpc_thread: error allocating TR_MQ_MSG");
510   else
511     trps_mq_append(trps, msg);
512
513   talloc_free(tmp_ctx);
514   return NULL;
515 }
516
517 /* convert an IDP realm into routing table entries. Outputs number in *n_routes */
518 static TRP_RENTRY **tr_make_local_routes(TALLOC_CTX *mem_ctx,
519                                          TR_IDP_REALM *realm,
520                                          char *trust_router,
521                                          size_t *n_routes)
522 {
523   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
524   TR_APC *apc=NULL;
525   TRP_RENTRY *new_entry=NULL;
526   TRP_RENTRY **entries=NULL;
527   size_t n_apcs=0, ii=0;
528
529   *n_routes=0;
530
531   if (realm==NULL)
532     goto cleanup;
533
534   /* count apcs */
535   for (apc=realm->apcs, n_apcs=0; apc!=NULL; apc=apc->next,n_apcs++) {}
536
537   entries=talloc_array(tmp_ctx, TRP_RENTRY *, n_apcs);
538   for (apc=realm->apcs,ii=0; apc!=NULL; apc=apc->next, ii++) {
539     new_entry=trp_rentry_new(entries);
540     if (new_entry==NULL) {
541       tr_crit("tr_make_local_routes: unable to allocate entry.");
542       talloc_free(entries);
543       goto cleanup;
544     }
545     trp_rentry_set_apc(new_entry, tr_dup_name(apc->id));
546     trp_rentry_set_realm(new_entry, tr_dup_name(realm->realm_id));
547     trp_rentry_set_peer(new_entry, tr_new_name("")); /* no peer, it's us */
548     trp_rentry_set_metric(new_entry, 0);
549     trp_rentry_set_trust_router(new_entry, tr_new_name(trust_router));
550     trp_rentry_set_next_hop(new_entry, tr_new_name(""));
551     /* we do not set selected (tbd later) or expiry/interval (not needed for
552      * local routes) */
553     entries[ii]=new_entry;
554   }
555
556   talloc_steal(mem_ctx, entries);
557   *n_routes=n_apcs;
558  cleanup:
559   talloc_free(tmp_ctx);
560   return entries;
561 }
562
563 struct tr_trpc_status_change_cookie {
564   TRPS_INSTANCE *trps;
565   TRPC_INSTANCE *trpc;
566   TRP_PEER *peer;
567 };
568 static void tr_trpc_status_change(TRP_CONNECTION *conn, void *cookie)
569 {
570   struct tr_trpc_status_change_cookie *cook=talloc_get_type_abort(cookie, struct tr_trpc_status_change_cookie);
571   /*TRPS_INSTANCE *trps=cook->trps;*/
572   /* TRPC_INSTANCE *trpc=cook->trpc;*/
573   TRP_PEER *peer=cook->peer;
574   TR_NAME *gssname=trp_peer_get_gssname(peer);
575
576   if (trp_connection_get_status(conn)==TRP_CONNECTION_UP)
577     tr_debug("tr_trpc_status_change: connection now up.");
578   else
579     tr_debug("tr_trpc_status_change: connection now down.");
580   tr_free_name(gssname);
581 }
582
583 /* starts a trpc thread to connect to server:port */
584 TRPC_INSTANCE *tr_trpc_initiate(TRPS_INSTANCE *trps, TRP_PEER *peer)
585 {
586   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
587   TRPC_INSTANCE *trpc=NULL;
588   TRP_CONNECTION *conn=NULL;
589   struct trpc_thread_data *thread_data=NULL;
590   struct tr_trpc_status_change_cookie *status_change_cookie=NULL;
591
592   tr_debug("tr_trpc_initiate entered");
593   trpc=trpc_new(tmp_ctx);
594   if (trpc==NULL) {
595     tr_crit("tr_trpc_initiate: could not allocate TRPC_INSTANCE.");
596     goto cleanup;
597   }
598   tr_debug("tr_trpc_initiate: allocated trpc");
599
600   conn=trp_connection_new(trpc);
601   if (conn==NULL) {
602     tr_crit("tr_trpc_initiate: could not allocate TRP_CONNECTION.");
603     goto cleanup;
604   }
605
606   status_change_cookie=talloc(conn, struct tr_trpc_status_change_cookie);
607   if (status_change_cookie==NULL) {
608     tr_crit("tr_trpc_initiate: could not allocate connection status cookie.");
609     goto cleanup;
610   }
611   status_change_cookie->trps=trps;
612   status_change_cookie->trpc=trpc;
613   status_change_cookie->peer=peer;
614   conn->status_change_cookie=status_change_cookie;
615   status_change_cookie=NULL;
616   conn->status_change_cb=tr_trpc_status_change;
617
618   trpc_set_conn(trpc, conn);
619   trpc_set_server(trpc, talloc_strdup(trpc, trp_peer_get_server(peer)));
620   trpc_set_port(trpc, trp_peer_get_port(peer));
621   trpc_set_gssname(trpc, trp_peer_get_gssname(peer));
622   tr_debug("tr_trpc_initiate: allocated connection");
623   
624   /* start thread */
625   thread_data=talloc(trpc, struct trpc_thread_data);
626   if (thread_data==NULL) {
627     tr_crit("tr_trpc_initiate: could not allocate struct trpc_thread_data.");
628     goto cleanup;
629   }
630   thread_data->trpc=trpc;
631   thread_data->trps=trps;
632
633   pthread_create(trp_connection_get_thread(conn), NULL, tr_trpc_thread, thread_data);
634   pthread_detach(*(trp_connection_get_thread(conn))); /* we will not rejoin the thread */
635
636   tr_debug("tr_trpc_initiate: started trpc thread");
637   trps_add_trpc(trps, trpc);
638
639  cleanup:
640   talloc_free(tmp_ctx);
641   return trpc;
642 }
643
644 /* Add local routes to the route table. */
645 TRP_RC tr_add_local_routes(TRPS_INSTANCE *trps, TR_CFG *cfg)
646 {
647   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
648   TR_IDP_REALM *cur=NULL;
649   TRP_RENTRY **local_routes=NULL;
650   size_t n_routes=0;
651   size_t ii=0;
652   char *trust_router_name=talloc_asprintf(tmp_ctx, "%s:%d", cfg->internal->hostname, cfg->internal->trps_port);
653
654   /* determine our trust router name */
655   if (trust_router_name==NULL)
656     return TRP_NOMEM;
657
658   for (cur=cfg->idp_realms; cur!=NULL; cur=cur->next) {
659     local_routes=tr_make_local_routes(tmp_ctx, cur, trust_router_name, &n_routes);
660     for (ii=0; ii<n_routes; ii++)
661       trps_add_route(trps, local_routes[ii]);
662
663     talloc_free(local_routes);
664     local_routes=NULL;
665     n_routes=0;
666   }
667
668   talloc_free(tmp_ctx);
669   return TRP_SUCCESS;
670 }
671
672 /* decide how often to attempt to connect to a peer */
673 static int tr_conn_attempt_due(TRPS_INSTANCE *trps, TRP_PEER *peer, struct timespec *when)
674 {
675   return 1; /* currently make an attempt every cycle */
676 }
677
678 /* open missing connections to peers */
679 TRP_RC tr_connect_to_peers(TRPS_INSTANCE *trps)
680 {
681   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
682   TRP_PTABLE_ITER *iter=trp_ptable_iter_new(tmp_ctx);
683   TRP_PEER *peer=NULL;
684   TRPC_INSTANCE *trpc=NULL;
685   struct timespec curtime={0,0};
686   TRP_RC rc=TRP_ERROR;
687
688   if (clock_gettime(CLOCK_REALTIME, &curtime)) {
689     tr_err("tr_connect_to_peers: failed to read time.");
690     rc=TRP_CLOCKERR;
691     goto cleanup;
692   }
693
694   for (peer=trp_ptable_iter_first(iter, trps->ptable);
695        peer!=NULL;
696        peer=trp_ptable_iter_next(iter))
697   {
698     if (trps_find_trpc(trps, peer)==NULL) {
699       tr_debug("tr_connect_to_peers: %.*s missing connection.",
700                trp_peer_get_gssname(peer)->len, trp_peer_get_gssname(peer)->buf);
701       /* has it been long enough since we last tried? */
702       if (tr_conn_attempt_due(trps, peer, &curtime)) {
703         trp_peer_set_last_conn_attempt(peer, &curtime); /* we are trying again now */
704         trpc=tr_trpc_initiate(trps, peer);
705         if (trpc==NULL) {
706           tr_err("tr_connect_to_peers: unable to initiate TRP connection to %s:%u.",
707                  trp_peer_get_server(peer),
708                  trp_peer_get_port(peer));
709         }
710       }
711     }
712   }
713   rc=TRP_SUCCESS;
714     
715 cleanup:
716   trp_ptable_iter_free(iter);
717   talloc_free(tmp_ctx);
718   return rc;
719 }
720
721
722 /* Called by the config manager after a change to the active configuration.
723  * Updates configuration of objects that do not know about the config manager. */
724 void tr_config_changed(TR_CFG *new_cfg, void *cookie)
725 {
726   TRPS_INSTANCE *trps=talloc_get_type_abort(cookie, TRPS_INSTANCE);
727   trps_set_connect_interval(trps, new_cfg->internal->trp_connect_interval);
728   trps_set_update_interval(trps, new_cfg->internal->trp_update_interval);
729   trps_set_sweep_interval(trps, new_cfg->internal->trp_sweep_interval);
730   trps_clear_rtable(trps); /* should we do this every time??? */
731   tr_add_local_routes(trps, new_cfg); /* should we do this every time??? */
732   trps_update_active_routes(trps);
733   tr_trps_print_route_table(trps, stderr);
734 }
735