Update the routing table when TRP updates are received.
authorJennifer Richards <jennifer@painless-security.com>
Fri, 1 Jul 2016 19:24:32 +0000 (15:24 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Fri, 1 Jul 2016 19:24:32 +0000 (15:24 -0400)
include/trp_internal.h
include/trust_router/trp.h
tr/tr_main.c
tr/tr_trp.c
trp/test/rtbl_test.c
trp/trp_conn.c
trp/trp_rtable.c
trp/trp_upd.c
trp/trpc.c
trp/trps.c

index faa8582..5289980 100644 (file)
@@ -8,6 +8,7 @@
 #include <trust_router/tr_dh.h>
 #include <tr_mq.h>
 #include <tr_msg.h>
+#include <trp_rtable.h>
 #include <trust_router/trp.h>
 
 /* info records */
@@ -59,8 +60,8 @@ struct trp_connection {
   TRP_CONNECTION *next;
   pthread_t *thread; /* thread servicing this connection */
   int fd;
-  TR_NAME *peer; /* who is this a connection to? */
   TR_NAME *gssname;
+  TR_NAME *peer;
   gss_ctx_id_t *gssctx;
   TRP_CONNECTION_STATUS status;
 };
@@ -74,7 +75,7 @@ typedef client_cb_fn TRP_AUTH_FUNC;
 typedef struct trpc_instance TRPC_INSTANCE;
 struct trpc_instance {
   TRPC_INSTANCE *next;
-  const char *server;
+  char *server;
   unsigned int port;
   TRP_CONNECTION *conn;
   TR_MQ *mq; /* msgs from master to trpc */
@@ -102,6 +103,7 @@ int trp_connection_lock(TRP_CONNECTION *conn);
 int trp_connection_unlock(TRP_CONNECTION *conn);
 int trp_connection_get_fd(TRP_CONNECTION *conn);
 void trp_connection_set_fd(TRP_CONNECTION *conn, int fd);
+TR_NAME *trp_connection_get_peer(TRP_CONNECTION *conn);
 TR_NAME *trp_connection_get_gssname(TRP_CONNECTION *conn);
 void trp_connection_set_gssname(TRP_CONNECTION *conn, TR_NAME *gssname);
 gss_ctx_id_t *trp_connection_get_gssctx(TRP_CONNECTION *conn);
@@ -114,7 +116,7 @@ TRP_CONNECTION *trp_connection_remove(TRP_CONNECTION *conn, TRP_CONNECTION *remo
 void trp_connection_append(TRP_CONNECTION *conn, TRP_CONNECTION *new);
 int trp_connection_auth(TRP_CONNECTION *conn, TRP_AUTH_FUNC auth_callback, void *callback_data);
 TRP_CONNECTION *trp_connection_accept(TALLOC_CTX *mem_ctx, int listen, TR_NAME *gssname);
-TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, const char *server, unsigned int port);
+TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, char *server, unsigned int port);
 
 TRPC_INSTANCE *trpc_new (TALLOC_CTX *mem_ctx);
 void trpc_free (TRPC_INSTANCE *trpc);
@@ -124,8 +126,8 @@ TRPC_INSTANCE *trpc_get_next(TRPC_INSTANCE *trpc);
 void trpc_set_next(TRPC_INSTANCE *trpc, TRPC_INSTANCE *next);
 TRPC_INSTANCE *trpc_remove(TRPC_INSTANCE *trpc, TRPC_INSTANCE *remove);
 void trpc_append(TRPC_INSTANCE *trpc, TRPC_INSTANCE *new);
-const char *trpc_get_server(TRPC_INSTANCE *trpc);
-void trpc_set_server(TRPC_INSTANCE *trpc, const char *server);
+char *trpc_get_server(TRPC_INSTANCE *trpc);
+void trpc_set_server(TRPC_INSTANCE *trpc, char *server);
 unsigned int trpc_get_port(TRPC_INSTANCE *trpc);
 void trpc_set_port(TRPC_INSTANCE *trpc, unsigned int port);
 DH *trpc_get_dh(TRPC_INSTANCE *trpc);
@@ -153,9 +155,12 @@ int trps_get_listener(TRPS_INSTANCE *trps,
                       const char *hostname,
                       unsigned int port,
                       void *cookie);
-int trps_auth_cb(gss_name_t clientName, gss_buffer_t displayName, void *data);
 TR_MQ_MSG *trps_mq_pop(TRPS_INSTANCE *trps);
 void trps_mq_append(TRPS_INSTANCE *trps, TR_MQ_MSG *msg);
 void trps_handle_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn);
 TRP_RC trps_handle_tr_msg(TRPS_INSTANCE *trps, TR_MSG *tr_msg);
+TRP_RENTRY *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer);
+TRP_RENTRY *trps_get_selected_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
+TR_NAME *trps_get_next_hop(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
+
 #endif /* TRP_INTERNAL_H */
index 5cda8ad..7867414 100644 (file)
@@ -35,7 +35,7 @@ void trp_upd_free(TRP_UPD *update);
 TR_EXPORT TRP_INFOREC *trp_upd_get_inforec(TRP_UPD *upd);
 void trp_upd_set_inforec(TRP_UPD *upd, TRP_INFOREC *rec);
 TR_EXPORT TR_NAME *trp_upd_get_peer(TRP_UPD *upd);
-TRP_RC trp_upd_set_peer(TRP_UPD *upd, TR_NAME *peer);
+void trp_upd_set_peer(TRP_UPD *upd, TR_NAME *peer);
 TR_EXPORT TRP_INFOREC *trp_inforec_new(TALLOC_CTX *mem_ctx, TRP_INFOREC_TYPE type);
 void trp_inforec_free(TRP_INFOREC *rec);
 TR_EXPORT TRP_INFOREC *trp_inforec_get_next(TRP_INFOREC *rec);
@@ -65,6 +65,6 @@ void trp_req_set_comm(TRP_REQ *req, TR_NAME *comm);
 TR_EXPORT TR_NAME *trp_req_get_realm(TRP_REQ *req);
 void trp_req_set_realm(TRP_REQ *req, TR_NAME *realm);
 TR_EXPORT TR_NAME *trp_req_get_peer(TRP_REQ *req);
-TRP_RC trp_req_set_peer(TRP_REQ *req, TR_NAME *peer);
+void trp_req_set_peer(TRP_REQ *req, TR_NAME *peer);
 
 #endif /* TRP_H */
index f6c67d0..91a494d 100644 (file)
@@ -124,6 +124,7 @@ static void tr_talloc_log(const char *msg)
 #endif /* TALLOC_DEBUG_ENABLE */
 
 
+#if DEBUG_PING_SELF
 struct thingy {
   TRPS_INSTANCE *trps;
   struct event *ev;
@@ -163,6 +164,7 @@ static void debug_ping(evutil_socket_t fd, short what, void *arg)
   if (count-- > 0)
     evtimer_add(thingy->ev, &interval);
 }
+#endif /* DEBUG_PING_SELF */
 
 int main(int argc, char *argv[])
 {
@@ -174,9 +176,11 @@ int main(int argc, char *argv[])
   struct tr_socket_event tids_ev;
   TR_TRPS_EVENTS *trps_ev;
   struct event *cfgwatch_ev;
+#if DEBUG_PING_SELF
   struct event *debug_ping_ev;
   struct timeval notime={0, 0};
   struct thingy thingy={NULL};
+#endif /* DEBUG_PING_SELF */
 
   /* we're going to be multithreaded, so disable null context tracking */
   talloc_set_abort_fn(tr_abort);
@@ -269,11 +273,13 @@ int main(int argc, char *argv[])
     return 1;
   }
 
+#if DEBUG_PING_SELF
   /* for debugging, send a message to peers on a timer */
   debug_ping_ev=evtimer_new(ev_base, debug_ping, (void *)&thingy);
   thingy.trps=tr->trps;
   thingy.ev=debug_ping_ev;
   evtimer_add(debug_ping_ev, &notime);
+#endif /* DEBUG_PING_SELF */
 
   tr_event_loop_run(ev_base); /* does not return until we are done */
 
index f085f7d..ac9f905 100644 (file)
@@ -155,12 +155,22 @@ static void tr_trps_cleanup_thread(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
   tr_debug("Deleted connection");
 }
 
+static void tr_trps_print_route_table(TRPS_INSTANCE *trps, FILE *f)
+{
+  char *table=trp_rtable_to_str(NULL, trps->rtable, " | ", NULL);
+  if (table==NULL)
+    fprintf(f, "Unable to print route table.\n");
+  else {
+    fprintf(f, "%s\n", table);
+    talloc_free(table);
+  }
+}
+
 static void tr_trps_process_mq(int socket, short event, void *arg)
 {
   TRPS_INSTANCE *trps=talloc_get_type_abort(arg, TRPS_INSTANCE);
   TR_MQ_MSG *msg=NULL;
   const char *s=NULL;
-  char *tmp=NULL;
 
   msg=trps_mq_pop(trps);
   while (msg!=NULL) {
@@ -171,7 +181,11 @@ static void tr_trps_process_mq(int socket, short event, void *arg)
                                                    TRP_CONNECTION));
     }
     else if (0==strcmp(s, "tr_msg")) {
-      trps_handle_tr_msg(trps, msg);
+      if (trps_handle_tr_msg(trps, tr_mq_msg_get_payload(msg))!=TRP_SUCCESS)
+        tr_notice("tr_trps_process_mq: error handling message.");
+      else {
+        tr_trps_print_route_table(trps, stderr);
+      }
     }
     else
       tr_notice("tr_trps_process_mq: unknown message '%s' received.", tr_mq_msg_get_message(msg));
index d2e3826..7f5d575 100644 (file)
@@ -4,6 +4,7 @@
 #include <assert.h>
 
 #include <trust_router/tr_name.h>
+#include <trp_internal.h>
 #include <trp_rtable.h>
 
 char *apc[]={"apc1", "apc2", "apc3"};
index 9c3d813..53b0a0d 100644 (file)
@@ -1,4 +1,5 @@
 #include <gsscon.h>
+#include <gssapi.h>
 #include <fcntl.h>
 #include <talloc.h>
 #include <unistd.h>
@@ -30,14 +31,68 @@ void trp_connection_set_fd(TRP_CONNECTION *conn, int fd)
   conn->fd=fd;
 }
 
-TR_NAME *trp_connection_get_peer(TRP_CONNECTION *conn)
+/* we use the gss name of the peer to identify it */
+static TRP_RC trp_connection_set_peer(TRP_CONNECTION *conn)
 {
-  return conn->peer;
+  OM_uint32 major_status=0;
+  OM_uint32 minor_status=0;
+  gss_name_t source_name=GSS_C_NO_NAME;
+  gss_name_t target_name=GSS_C_NO_NAME;
+  gss_buffer_desc peer_display_name={0,NULL};
+  int local=0;
+
+  tr_debug("gssctx = %p", trp_connection_get_gssctx(conn));
+  tr_debug("*gssctx = %p", *trp_connection_get_gssctx(conn));
+  major_status=gss_inquire_context(&minor_status,
+                                   *trp_connection_get_gssctx(conn),
+                                  &source_name,
+                                  &target_name,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                  &local,
+                                   NULL);
+
+  if (major_status != GSS_S_COMPLETE) {
+    tr_err("trp_connection_set_peer: unable to identify GSS peer.");
+    if (source_name!=GSS_C_NO_NAME)
+      gss_release_name(&minor_status, &source_name);
+    if (target_name!=GSS_C_NO_NAME)
+      gss_release_name(&minor_status, &target_name);
+    return TRP_ERROR;
+  }
+
+  if (local) {
+    /* we are the source, peer is the target */
+    major_status=gss_display_name(&minor_status, target_name, &peer_display_name, NULL);
+  } else {
+    /* we are the target, peer is the source */
+    major_status=gss_display_name(&minor_status, source_name, &peer_display_name, NULL);
+  }
+  gss_release_name(&minor_status, &source_name);
+  gss_release_name(&minor_status, &target_name);
+
+  conn->peer=tr_new_name(peer_display_name.value);
+  if (conn->peer==NULL)
+    tr_err("trp_connection_set_peer: unable to allocate peer name.");
+  else {
+    if (conn->peer->len != peer_display_name.length) {
+      tr_err("trp_connection_set_peer: error converting GSS display name to TR_NAME.");
+      tr_free_name(conn->peer);
+      conn->peer=NULL;
+    }
+  }
+  gss_release_buffer(&minor_status, &peer_display_name);
+
+  if (conn->peer==NULL)
+    return TRP_ERROR;
+  
+  return TRP_SUCCESS;
 }
 
-void trp_connection_set_peer(TRP_CONNECTION *conn, TR_NAME *peer)
+TR_NAME *trp_connection_get_peer(TRP_CONNECTION *conn)
 {
-  conn->peer=peer;
+  return conn->peer;
 }
 
 TR_NAME *trp_connection_get_gssname(TRP_CONNECTION *conn)
@@ -166,7 +221,6 @@ TRP_CONNECTION *trp_connection_new(TALLOC_CTX *mem_ctx)
   if (new_conn != NULL) {
     trp_connection_set_next(new_conn, NULL);
     trp_connection_set_fd(new_conn, -1);
-    trp_connection_set_peer(new_conn, NULL);
     trp_connection_set_gssname(new_conn, NULL);
     trp_connection_mutex_init(new_conn);
     trp_connection_set_status(new_conn, TRP_CONNECTION_DOWN);
@@ -226,6 +280,9 @@ int trp_connection_auth(TRP_CONNECTION *conn, TRP_AUTH_FUNC auth_callback, void
     return -1;
   }
 
+  trp_connection_set_peer(conn);
+  trp_connection_set_status(conn, TRP_CONNECTION_UP);
+
   if (auth)
     tr_debug("trp_connection_auth: Connection authenticated, fd = %d.", trp_connection_get_fd(conn));
   else
@@ -249,12 +306,11 @@ TRP_CONNECTION *trp_connection_accept(TALLOC_CTX *mem_ctx, int listen, TR_NAME *
   conn=trp_connection_new(mem_ctx);
   trp_connection_set_fd(conn, conn_fd);
   trp_connection_set_gssname(conn, gssname);
-  trp_connection_set_status(conn, TRP_CONNECTION_UP);
   return conn;
 }
 
 /* Initiate connection */
-TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, const char *server, unsigned int port)
+TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, char *server, unsigned int port)
 {
   int err = 0;
   int fd=-1;
@@ -285,7 +341,7 @@ TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, const char *server, unsigne
     return TRP_ERROR;
   } else {
     trp_connection_set_fd(conn, fd);
-    trp_connection_set_peer(conn, tr_new_name(server));
+    trp_connection_set_peer(conn);
     trp_connection_set_status(conn, TRP_CONNECTION_UP);
     return TRP_SUCCESS;
   }
index 97bf923..6cc8e18 100644 (file)
@@ -529,15 +529,17 @@ static char *timespec_to_str(struct timespec *ts)
 
 TRP_RENTRY *trp_rtable_get_selected_entry(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAME *realm)
 {
-  size_t n_entries=0;
-  TRP_RENTRY *entry=trp_rtable_get_realm_entries(rtbl, apc, realm, &n_entries);
-  if (n_entries==0)
-    return NULL;
+  size_t n=0;
+  TRP_RENTRY **entry=trp_rtable_get_realm_entries(rtbl, apc, realm, &n);
+  TRP_RENTRY *selected=NULL;
 
-  while((entry!=NULL) && (!trp_rentry_get_selected(entry)))
-    entry=trp_rentry_get_next(entry);
+  if (n==0)
+    return NULL;
 
-  return entry;
+  while(n-- && !trp_rentry_get_selected(entry[n])) { }
+  selected=entry[n];
+  talloc_free(entry);
+  return selected;
 }
 
 /* Pretty print a route table entry to a newly allocated string. If sep is NULL,
index 68ccacf..6865a44 100644 (file)
@@ -78,7 +78,7 @@ static int trp_inforec_route_destructor(void *object)
   }
   if (body->next_hop != NULL) {
     tr_free_name(body->next_hop);
-    body->hop=NULL;
+    body->next_hop=NULL;
     tr_debug("trp_inforec_route_destructor: freed next_hop");
   }
 
@@ -353,7 +353,7 @@ TRP_UPD *trp_upd_new(TALLOC_CTX *mem_ctx)
   if (new_body!=NULL) {
     new_body->records=NULL;
     new_body->peer=NULL;
-    talloc_set_destructor(new_body, trp_upd_destructor);
+    talloc_set_destructor((void *)new_body, trp_upd_destructor);
   }
   return new_body;
 }
@@ -390,8 +390,10 @@ void trp_upd_set_peer(TRP_UPD *upd, TR_NAME *peer)
 
   upd->peer=peer;
   for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
-    if (trp_inforec_set_next_hop(rec, cpy=tr_dup_name(peer)) != TRP_SUCCESS)
+    if (trp_inforec_set_next_hop(rec, cpy=tr_dup_name(peer)) != TRP_SUCCESS) {
+      tr_err("trp_upd_set_peer: error setting peer.");
       tr_free_name(cpy);
+    }
   }
 }
 
index 57b7378..4913455 100644 (file)
@@ -85,12 +85,12 @@ void trpc_append(TRPC_INSTANCE *trpc, TRPC_INSTANCE *new)
   trpc_set_next(trpc_get_tail(trpc), new);
 }
 
-const char *trpc_get_server(TRPC_INSTANCE *trpc)
+char *trpc_get_server(TRPC_INSTANCE *trpc)
 {
   return trpc->server;
 }
 
-void trpc_set_server(TRPC_INSTANCE *trpc, const char *server)
+void trpc_set_server(TRPC_INSTANCE *trpc, char *server)
 {
   trpc->server=server;
 }
index c96495d..824d8f9 100644 (file)
@@ -5,11 +5,20 @@
 
 #include <gsscon.h>
 #include <tr_rp.h>
-#include <tr_debug.h>
-#include <trp_rtable.h>
+#include <trust_router/tr_name.h>
 #include <trp_internal.h>
+#include <trp_rtable.h>
+#include <tr_debug.h>
 
 
+static int trps_destructor(void *object)
+{
+  TRPS_INSTANCE *trps=talloc_get_type_abort(object, TRPS_INSTANCE);
+  if (trps->rtable!=NULL)
+    trp_rtable_free(trps->rtable);
+  return 0;
+}
+
 TRPS_INSTANCE *trps_new (TALLOC_CTX *mem_ctx)
 {
   TRPS_INSTANCE *trps=talloc(mem_ctx, TRPS_INSTANCE);
@@ -24,6 +33,14 @@ TRPS_INSTANCE *trps_new (TALLOC_CTX *mem_ctx)
       /* failed to allocate mq */
       talloc_free(trps);
       trps=NULL;
+    } else {
+      trps->rtable=trp_rtable_new();
+      if (trps->rtable==NULL) {
+        /* failed to allocate rtable */
+        talloc_free(trps);
+        trps=NULL;
+      } else
+        talloc_set_destructor((void *)trps, trps_destructor);
     }
   }
   return trps;
@@ -114,58 +131,76 @@ TRP_RC trps_send_msg (TRPS_INSTANCE *trps, void *peer, const char *msg)
 
 static int trps_listen (TRPS_INSTANCE *trps, int port) 
 {
-    int rc = 0;
-    int conn = -1;
-    int optval = 1;
+  int rc = 0;
+  int conn = -1;
+  int optval = 1;
 
-    union {
-      struct sockaddr_storage storage;
-      struct sockaddr_in in4;
-    } addr;
+  union {
+    struct sockaddr_storage storage;
+    struct sockaddr_in in4;
+  } addr;
 
-    struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
+  struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
 
-    saddr->sin_port = htons (port);
-    saddr->sin_family = AF_INET;
-    saddr->sin_addr.s_addr = INADDR_ANY;
+  saddr->sin_port = htons (port);
+  saddr->sin_family = AF_INET;
+  saddr->sin_addr.s_addr = INADDR_ANY;
 
-    if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
-      return conn;
+  if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
+    return conn;
 
-    setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+  setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
 
-    if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
-      return rc;
+  if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
+    return rc;
 
-    if (0 > (rc = listen(conn, 512)))
-      return rc;
+  if (0 > (rc = listen(conn, 512)))
+    return rc;
 
-    tr_debug("trps_listen: TRP Server listening on port %d", port);
-    return conn;
+  tr_debug("trps_listen: TRP Server listening on port %d", port);
+  return conn;
 }
 
+#if 0 /* remove this if I forget to do so */
 /* returns EACCES if authorization is denied */
 int trps_auth_cb(gss_name_t clientName, gss_buffer_t displayName, void *data)
 {
-  TRPS_INSTANCE *inst = (TRPS_INSTANCE *)data;
+  TRPS_INSTANCE *trps = (TRPS_INSTANCE *)data;
   int result=0;
 
-  if (0!=inst->auth_handler(clientName, displayName, inst->cookie)) {
+  if (0!=trps->auth_handler(clientName, displayName, trps->cookie)) {
     tr_debug("trps_auth_cb: client '%.*s' denied authorization.", displayName->length, displayName->value);
     result=EACCES; /* denied */
   }
 
   return result;
 }
+#endif 
 
 /* get the currently selected route if available */
-TRP_RENTRY *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm)
+TRP_RENTRY *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer)
+{
+  return trp_rtable_get_entry(trps->rtable, comm, realm, peer);
+}
+
+TRP_RENTRY *trps_get_selected_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm)
 {
   return trp_rtable_get_selected_entry(trps->rtable, comm, realm);
 }
 
+/* copy the result if you want to keep it */
+TR_NAME *trps_get_next_hop(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm)
+{
+  TRP_RENTRY *route=trps_get_selected_route(trps, comm, realm);
+  if (route==NULL)
+    return NULL;
+
+  return trp_rentry_get_next_hop(route);
+}
+
+
 /* mark a route as retracted */
-static TRP_RC trps_retract_route(TRPS_INSTANCE *trps, TRP_RENTRY *entry)
+static void trps_retract_route(TRPS_INSTANCE *trps, TRP_RENTRY *entry)
 {
   trp_rentry_set_metric(entry, TRP_METRIC_INFINITY);
 }
@@ -181,13 +216,13 @@ static TRP_RC trps_read_message(TRPS_INSTANCE *trps, TRP_CONNECTION *conn, TR_MS
   int err=0;
   char *buf=NULL;
   size_t buflen = 0;
-  TR_NAME *peer=NULL
+  TR_NAME *peer=NULL;
 
   tr_debug("trps_read_message: started");
   if (err = gsscon_read_encrypted_token(trp_connection_get_fd(conn),
                                        *(trp_connection_get_gssctx(conn)), 
-                                        &buf,
-                                        &buflen)) {
+                                       &buf,
+                                       &buflen)) {
     tr_debug("trps_read_message: error");
     if (buf)
       free(buf);
@@ -206,11 +241,11 @@ static TRP_RC trps_read_message(TRPS_INSTANCE *trps, TRP_CONNECTION *conn, TR_MS
   /* verify we received a message we support, otherwise drop it now */
   switch (tr_msg_get_msg_type(*msg)) {
   case TRP_UPDATE:
-    trp_upd_set_peer(tr_msg_get_trp_upd(msg), tr_name_dup(peer));
+    trp_upd_set_peer(tr_msg_get_trp_upd(*msg), tr_dup_name(peer));
     break;
 
   case TRP_REQUEST:
-    trp_req_set_peer(tr_msg_get_trp_req(msg), tr_name_dup(peer));
+    trp_req_set_peer(tr_msg_get_trp_req(*msg), tr_dup_name(peer));
     break;
 
   default:
@@ -299,6 +334,21 @@ void trps_handle_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
   talloc_free(tmp_ctx);
 }
 
+static TRP_RC trps_validate_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
+{
+  if (trp_upd_get_inforec(upd)==NULL) {
+    tr_notice("trps_validate_update: received TRP update with no info records.");
+    return TRP_ERROR;
+  }
+
+  if (trp_upd_get_peer(upd)==NULL) {
+    tr_notice("trps_validate_update: received TRP update without origin peer information.");
+    return TRP_ERROR;
+  }
+  
+  return TRP_SUCCESS;
+}
+
 /* ensure that the update could be accepted if feasible */
 static TRP_RC trps_validate_inforec(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
 {
@@ -307,9 +357,10 @@ static TRP_RC trps_validate_inforec(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
     if ((trp_inforec_get_comm(rec)==NULL)
        || (trp_inforec_get_realm(rec)==NULL)
        || (trp_inforec_get_trust_router(rec)==NULL)
-       || (trp_inforec_get_next_hop(rec)==NULL))
+       || (trp_inforec_get_next_hop(rec)==NULL)) {
       tr_debug("trps_validate_inforec: missing record info.");
       return TRP_ERROR;
+    }
 
     /* check for valid metric */
     if ((trp_inforec_get_metric(rec)==TRP_METRIC_INVALID)
@@ -326,6 +377,7 @@ static TRP_RC trps_validate_inforec(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
     break;
 
   default:
+    tr_notice("trps_validate_inforec: unsupported record type.");
     return TRP_UNSUPPORTED;
   }
 
@@ -346,27 +398,28 @@ static unsigned int trps_advertised_metric(TRPS_INSTANCE *trps, TR_NAME *comm, T
   return trp_rentry_get_metric(entry) + trps_cost(trps, peer);
 }
 
-/* returns TRP_SUCCESS if route is feasible, TRP_ERROR otherwise */
-static TRP_RC trps_check_feasibility(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
+static int trps_check_feasibility(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
 {
   unsigned int rec_metric=trp_inforec_get_metric(rec);
   unsigned int new_metric=0;
   unsigned int current_metric=0;
+  TR_NAME *next_hop=NULL;
 
   /* we check these in the validation stage, but just in case... */
   if ((rec_metric==TRP_METRIC_INVALID) || (rec_metric>TRP_METRIC_INFINITY))
-    return TRP_ERROR;
+    return 0;
 
   /* retractions (aka infinite metrics) are always feasible */
   if (rec_metric==TRP_METRIC_INFINITY)
-    return TRP_SUCCESS;
+    return 1;
 
   /* updates from our current next hop are always feasible*/
-  if (0==tr_name_cmp(trp_inforec_get_next_hop(rec),
-                     trps_next_hop(trps,
-                                   trp_inforec_get_comm(rec),
-                                   trp_inforec_get_realm(rec)))) {
-    return TRP_SUCCESS;
+  next_hop=trps_get_next_hop(trps,
+                             trp_inforec_get_comm(rec),
+                             trp_inforec_get_realm(rec));;
+  if ((next_hop!=NULL)
+     && (0==tr_name_cmp(next_hop,trp_inforec_get_next_hop(rec)))) {
+    return 1;
   }
     
 
@@ -378,20 +431,19 @@ static TRP_RC trps_check_feasibility(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
                                         trp_inforec_get_next_hop(rec));
   new_metric=rec_metric + trps_cost(trps, trp_inforec_get_next_hop(rec));
   if (new_metric <= current_metric)
-    return TRP_SUCCESS;
+    return 1;
   else
-    return TRP_ERROR;
+    return 0;
 }
 
-/* uses memory pointed to by *ts, also returns that value */
-static void trps_compute_expiry(unsigned int interval, struct timespec *ts)
+/* uses memory pointed to by *ts, also returns that value. On error, its contents are {0,0} */
+static struct timespec *trps_compute_expiry(TRPS_INSTANCE *trps, unsigned int interval, struct timespec *ts)
 {
   const unsigned int small_factor=3; /* how many intervals we wait before expiring */
   if (0!=clock_gettime(CLOCK_REALTIME, ts)) {
-    tr_error("trps_compute_expiry: could not read realtime clock.");
+    tr_err("trps_compute_expiry: could not read realtime clock.");
     ts->tv_sec=0;
     ts->tv_nsec=0;
-    return NULL;
   }
   ts->tv_sec += small_factor*interval;
   return ts;
@@ -408,7 +460,7 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
   if (entry==NULL) {
     entry=trp_rentry_new(NULL);
     if (entry==NULL) {
-      tr_error("trps_accept_update: unable to allocate new entry.");
+      tr_err("trps_accept_update: unable to allocate new entry.");
       return TRP_NOMEM;
     }
 
@@ -421,9 +473,9 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
        ||(trp_rentry_get_realm(entry)==NULL)
        ||(trp_rentry_get_peer(entry)==NULL)
        ||(trp_rentry_get_trust_router(entry)==NULL)
-       ||(trp_rentry_next_hop(entry)==NULL)) {
+       ||(trp_rentry_get_next_hop(entry)==NULL)) {
       /* at least one field could not be allocated */
-      tr_error("trps_accept_update: unable to allocate all fields for entry.");
+      tr_err("trps_accept_update: unable to allocate all fields for entry.");
       trp_rentry_free(entry);
       return TRP_NOMEM;
     }
@@ -434,9 +486,14 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
    * the metric is infinity. An infinite metric can only occur here if we just retracted an existing
    * route (we never accept retractions as new routes), so there is no risk of leaving the expiry
    * time unset on a new route entry. */
+  tr_debug("trps_accept_update: accepting route update.");
   trp_rentry_set_metric(entry, trp_inforec_get_metric(rec));
-  if (!trps_route_retracted(trps, entry))
-    trp_rentry_set_expiry(entry, trps_compute_expiry(trps, trp_inforec_get_interval(rec)));
+  if (!trps_route_retracted(trps, entry)) {
+    tr_debug("trps_accept_update: route not retracted, setting expiry timer.");
+    trp_rentry_set_expiry(entry, trps_compute_expiry(trps,
+                                                     trp_inforec_get_interval(rec),
+                                                     trp_rentry_get_expiry(entry)));
+  }
   return TRP_SUCCESS;
 }
 
@@ -444,28 +501,31 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
 static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
 {
   unsigned int feas=0;
-  TRP_INFOREC *rec=trp_upd_get_inforec(upd);
+  TRP_INFOREC *rec=NULL;
   TRP_RENTRY *route=NULL;
 
-  if (rec==NULL) {
-    tr_notice("trps_handle_update: received TRP update with no info records.");
+  if (trps_validate_update(trps, upd) != TRP_SUCCESS) {
+    tr_notice("trps_handle_update: received invalid TRP update.");
     return TRP_ERROR;
   }
 
+  rec=trp_upd_get_inforec(upd);
   for (;rec!=NULL; rec=trp_inforec_get_next(rec)) {
-    /* validate/sanity check the update */
-    if (trps_validate_inforec(trps, upd) != TRP_SUCCESS) {
+    /* validate/sanity check the record update */
+    if (trps_validate_inforec(trps, rec) != TRP_SUCCESS) {
       tr_notice("trps_handle_update: invalid record in TRP update.");
       continue;
     }
 
     /* determine feasibility */
     feas=trps_check_feasibility(trps, rec);
+    tr_debug("trps_handle_update: record feasibility=%d", feas);
 
     /* do we have an existing route? */
-    route=trps_get_route(trps, trp_inforec_get_comm(rec), trp_inforec_get_realm(rec));
+    route=trps_get_route(trps, trp_inforec_get_comm(rec), trp_inforec_get_realm(rec), trp_inforec_get_next_hop(rec));
     if (route!=NULL) {
       /* there was a route table entry already */
+      tr_debug("trps_handle_updates: route entry already exists.");
       if (feas) {
         /* Update is feasible. Accept it. */
         trps_accept_update(trps, rec);
@@ -479,7 +539,8 @@ static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
       }
     } else {
       /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */
-      if (feas && (trp_inforec_get_metric != TRP_METRIC_INFINITY))
+      tr_debug("trps_handle_update: no route entry exists yet.");
+      if (feas && (trp_inforec_get_metric(rec) != TRP_METRIC_INFINITY))
         trps_accept_update(trps, rec);
     }
   }
@@ -490,7 +551,7 @@ TRP_RC trps_handle_tr_msg(TRPS_INSTANCE *trps, TR_MSG *tr_msg)
 {
   switch (tr_msg_get_msg_type(tr_msg)) {
   case TRP_UPDATE:
-    return trps_handle_update(TRPS_INSTANCE *trps, tr_msg_get_trp_upd(tr_msg));
+    return trps_handle_update(trps, tr_msg_get_trp_upd(tr_msg));
 
   case TRP_REQUEST:
     return TRP_UNSUPPORTED;