Connect to hard-coded peer and exchange route info. Buggy and incomplete.
[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, "trps_thread_exit");
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, "trpc_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, "trps_thread_exit")) {
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, "trpc_thread_exit")) {
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, "trpc_abort")) {
482           tr_mq_msg_free(msg);
483           break; /* exit loop */
484         }
485         else if (0==strcmp(msg_type, "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, "trpc_thread_exit");
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 /* starts a trpc thread to connect to server:port */
518 TRPC_INSTANCE *tr_trpc_initiate(TRPS_INSTANCE *trps, TRP_PEER *peer)
519 {
520   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
521   TRPC_INSTANCE *trpc=NULL;
522   TRP_CONNECTION *conn=NULL;
523   struct trpc_thread_data *thread_data=NULL;
524
525   tr_debug("tr_trpc_initiate entered");
526   trpc=trpc_new(tmp_ctx);
527   if (trpc==NULL) {
528     tr_crit("tr_trpc_initiate: could not allocate TRPC_INSTANCE.");
529     goto cleanup;
530   }
531   tr_debug("tr_trpc_initiate: allocated trpc");
532
533   conn=trp_connection_new(trpc);
534   if (conn==NULL) {
535     tr_crit("tr_trpc_initiate: could not allocate TRP_CONNECTION.");
536     goto cleanup;
537   }
538   trpc_set_conn(trpc, conn);
539   trpc_set_server(trpc, talloc_strdup(trpc, trp_peer_get_server(peer)));
540   trpc_set_port(trpc, trp_peer_get_port(peer));
541   trpc_set_gssname(trpc, trp_peer_get_gssname(peer));
542   tr_debug("tr_trpc_initiate: allocated connection");
543   
544   /* start thread */
545   thread_data=talloc(trpc, struct trpc_thread_data);
546   if (thread_data==NULL) {
547     tr_crit("tr_trpc_initiate: could not allocate struct trpc_thread_data.");
548     goto cleanup;
549   }
550   thread_data->trpc=trpc;
551   thread_data->trps=trps;
552
553   pthread_create(trp_connection_get_thread(conn), NULL, tr_trpc_thread, thread_data);
554   pthread_detach(*(trp_connection_get_thread(conn))); /* we will not rejoin the thread */
555
556   tr_debug("tr_trpc_initiate: started trpc thread");
557   trps_add_trpc(trps, trpc);
558
559  cleanup:
560   talloc_free(tmp_ctx);
561   return trpc;
562 }
563
564 /* decide how often to attempt to connect to a peer */
565 static int tr_conn_attempt_due(TRPS_INSTANCE *trps, TRP_PEER *peer, struct timespec *when)
566 {
567   return 1; /* currently make an attempt every cycle */
568 }
569
570 /* open missing connections to peers */
571 TRP_RC tr_connect_to_peers(TRPS_INSTANCE *trps)
572 {
573   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
574   TRP_PTABLE_ITER *iter=trp_ptable_iter_new(tmp_ctx);
575   TRP_PEER *peer=NULL;
576   TRPC_INSTANCE *trpc=NULL;
577   struct timespec curtime={0,0};
578   TRP_RC rc=TRP_ERROR;
579
580   if (clock_gettime(CLOCK_REALTIME, &curtime)) {
581     tr_err("tr_connect_to_peers: failed to read time.");
582     rc=TRP_CLOCKERR;
583     goto cleanup;
584   }
585
586   for (peer=trp_ptable_iter_first(iter, trps->ptable);
587        peer!=NULL;
588        peer=trp_ptable_iter_next(iter))
589   {
590     if (trps_find_trpc(trps, peer)==NULL) {
591       tr_debug("tr_connect_to_peers: %.*s missing connection.",
592                trp_peer_get_gssname(peer)->len, trp_peer_get_gssname(peer)->buf);
593       /* has it been long enough since we last tried? */
594       if (tr_conn_attempt_due(trps, peer, &curtime)) {
595         trp_peer_set_last_conn_attempt(peer, &curtime); /* we are trying again now */
596         trpc=tr_trpc_initiate(trps, peer);
597         if (trpc==NULL) {
598           tr_err("tr_connect_to_peers: unable to initiate TRP connection to %s:%u.",
599                  trp_peer_get_server(peer),
600                  trp_peer_get_port(peer));
601         }
602       }
603     }
604   }
605   rc=TRP_SUCCESS;
606     
607 cleanup:
608   trp_ptable_iter_free(iter);
609   talloc_free(tmp_ctx);
610   return rc;
611 }
612
613
614 /* Called by the config manager after a change to the active configuration.
615  * Updates configuration of objects that do not know about the config manager. */
616 void tr_config_changed(TR_CFG *new_cfg, void *cookie)
617 {
618   TRPS_INSTANCE *trps=talloc_get_type_abort(cookie, TRPS_INSTANCE);
619   trps_set_connect_interval(trps, new_cfg->internal->trp_connect_interval);
620   trps_set_update_interval(trps, new_cfg->internal->trp_update_interval);
621   trps_set_sweep_interval(trps, new_cfg->internal->trp_sweep_interval);
622 }
623