In-progress check-in.
[trust_router.git] / tr / tr_tid.c
index 27c7a45..fb76dd7 100644 (file)
@@ -69,33 +69,15 @@ static void tr_tidc_resp_handler(TIDC_INSTANCE *tidc,
 {
   TR_RESP_COOKIE *cookie=talloc_get_type_abort(resp_cookie, TR_RESP_COOKIE);
 
-  tr_debug("tr_tidc_resp_handler: Response received! Realm = %s, Community = %s.",
+  tr_debug("tr_tidc_resp_handler: Response received! Realm = %s, Community = %s, result = %s.",
            resp->realm->buf,
-           resp->comm->buf);
-  
-  cookie->resp=tid_resp_dup(cookie, resp);
-}
+           resp->comm->buf,
+           (TID_SUCCESS==resp->result)?"success":"error");
 
-#if 0
-/* Old one, obsolete. */
-
-static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc, 
-                                  TID_REQ *req,
-                                  TID_RESP *resp, 
-                                  void *resp_cookie)
-{
-  tr_debug("tr_tidc_resp_handler: Response received (conn = %d)! Realm = %s, Community = %s.", ((TR_RESP_COOKIE *)resp_cookie)->orig_req->conn, resp->realm->buf, resp->comm->buf);
-  req->resp_rcvd = 1;
-
-  /* TBD -- handle concatentation of multiple responses to single req */
-  tids_send_response(((TR_RESP_COOKIE *)resp_cookie)->tids, 
-                    ((TR_RESP_COOKIE *)resp_cookie)->orig_req, 
-                    resp);
-  
-  return;
+  if (resp->error_path!=NULL)
+    tr_debug("tr_tids_resp_handler: error_path is set.");
+  cookie->resp=tid_resp_dup(cookie, resp);
 }
-#endif /* 0 */
-
 
 /* data for AAA req forwarding threads */
 struct tr_tids_fwd_cookie {
@@ -148,7 +130,7 @@ static void *tr_tids_req_fwd_thread(void *arg)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   struct tr_tids_fwd_cookie *args=talloc_get_type_abort(arg, struct tr_tids_fwd_cookie);
-  TIDC_INSTANCE *tidc=tidc_create(tmp_ctx);
+  TIDC_INSTANCE *tidc=tidc_create();
   TR_MQ_MSG *msg=NULL;
   TR_RESP_COOKIE *cookie=NULL;
   int rc=0;
@@ -156,6 +138,19 @@ static void *tr_tids_req_fwd_thread(void *arg)
 
   talloc_steal(tmp_ctx, args); /* take responsibility for the cookie */
 
+  if (tidc!=NULL)
+    talloc_steal(tmp_ctx, tidc);
+
+  /* create the cookie we will use for our response */
+  cookie=talloc(tmp_ctx, TR_RESP_COOKIE);
+  if (cookie==NULL) {
+    tr_notice("tr_tids_req_fwd_thread: unable to allocate response cookie.");
+    success=0;
+    goto cleanup;
+  }
+  cookie->thread_id=args->thread_id;
+  tr_debug("tr_tids_req_fwd_thread: thread %d started.", cookie->thread_id);
+
   /* Create a TID client instance */
   if (tidc==NULL) {
     tr_crit("tr_tids_req_fwd_thread: Unable to allocate TIDC instance.");
@@ -176,15 +171,11 @@ static void *tr_tids_req_fwd_thread(void *arg)
     success=0;
     goto cleanup;
   };
+  tr_debug("tr_tids_req_fwd_thread: thread %d opened TID connection to %s.",
+           cookie->thread_id,
+           args->aaa_hostname->buf);
 
   /* Send a TID request. */
-  cookie=talloc(tmp_ctx, TR_RESP_COOKIE);
-  if (cookie==NULL) {
-    tr_notice("tr_tids_req_fwd_thread: unable to allocate response cookie.");
-    success=0;
-    goto cleanup;
-  }
-  cookie->thread_id=args->thread_id;
   if (0 > (rc = tidc_fwd_request(tidc, args->fwd_req, tr_tidc_resp_handler, (void *)cookie))) {
     tr_notice("Error from tidc_fwd_request, rc = %d.", rc);
     success=0;
@@ -192,26 +183,29 @@ static void *tr_tids_req_fwd_thread(void *arg)
   }
   /* cookie->resp should now contain our copy of the response */
   success=1;
+  tr_debug("tr_tids_req_fwd_thread: thread %d received response.");
 
 cleanup:
   /* Notify parent thread of the response, if it's still listening. */
   if (0!=tr_tids_fwd_get_mutex(args)) {
-    tr_notice("tr_tids_req_fwd_thread: Error acquiring mutex.");
+    tr_notice("tr_tids_req_fwd_thread: thread %d unable to acquire mutex.", cookie->thread_id);
   } else if (NULL!=args->mq) {
     /* mq is still valid, so we can queue our response */
+    tr_debug("tr_tids_req_fwd_thread: thread %d using valid msg queue.", cookie->thread_id);
     if (success)
       msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_SUCCESS, TR_MQ_PRIO_NORMAL);
     else
       msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_FAILURE, TR_MQ_PRIO_NORMAL);
 
     if (msg==NULL)
-      tr_notice("tr_tids_req_fwd_thread: unable to allocate response msg.");
+      tr_notice("tr_tids_req_fwd_thread: thread %d unable to allocate response msg.", cookie->thread_id);
 
     tr_mq_msg_set_payload(msg, (void *)cookie, NULL);
     if (NULL!=cookie)
       talloc_steal(msg, cookie); /* attach this to the msg so we can forget about it */
     tr_mq_add(args->mq, msg);
     talloc_steal(NULL, args); /* take out of our tmp_ctx; master thread now responsible for freeing */
+    tr_debug("tr_tids_req_fwd_thread: thread %d queued response message.", cookie->thread_id);
     if (0!=tr_tids_fwd_release_mutex(args))
       tr_notice("tr_tids_req_fwd_thread: Error releasing mutex.");
   }
@@ -248,11 +242,12 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   TR_AAA_SERVER_ITER *aaa_iter=NULL;
   pthread_t aaa_thread[TR_TID_MAX_AAA_SERVERS];
   struct tr_tids_fwd_cookie *aaa_cookie[TR_TID_MAX_AAA_SERVERS]={NULL};
+  TID_RESP *aaa_resp[TR_TID_MAX_AAA_SERVERS]={NULL};
   TR_NAME *apc = NULL;
   TID_REQ *fwd_req = NULL;
   TR_COMM *cfg_comm = NULL;
   TR_COMM *cfg_apc = NULL;
-  int oaction = TR_FILTER_ACTION_REJECT;
+  TR_FILTER_ACTION oaction = TR_FILTER_ACTION_REJECT;
   time_t expiration_interval=0;
   struct tr_tids_event_cookie *cookie=talloc_get_type_abort(cookie_in, struct tr_tids_event_cookie);
   TR_CFG_MGR *cfg_mgr=cookie->cfg_mgr;
@@ -280,11 +275,12 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   tids->req_count++;
 
   /* Duplicate the request, so we can modify and forward it */
-  if (NULL == (fwd_req=tid_dup_req(tmp_ctx, orig_req))) {
+  if (NULL == (fwd_req=tid_dup_req(orig_req))) {
     tr_debug("tr_tids_req_handler: Unable to duplicate request.");
     retval=-1;
     goto cleanup;
   }
+  talloc_steal(tmp_ctx, fwd_req);
 
   if (NULL == (cfg_comm=tr_comm_table_find_comm(cfg_mgr->active->ctable, orig_req->comm))) {
     tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", orig_req->comm->buf);
@@ -416,6 +412,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   }
 
   /* send a TID request to the AAA server(s), and get the answer(s) */
+  tr_debug("tr_tids_req_handler: sending TID request(s).");
   if (cfg_apc)
     expiration_interval = cfg_apc->expiration_interval;
   else expiration_interval = cfg_comm->expiration_interval;
@@ -430,6 +427,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     retval=-1;
     goto cleanup;
   }
+  tr_debug("tr_tids_req_handler: message queue allocated.");
 
   /* start threads */
   aaa_iter=tr_aaa_server_iter_new(tmp_ctx);
@@ -441,6 +439,8 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   for (n_aaa=0, this_aaa=tr_aaa_server_iter_first(aaa_iter, aaa_servers);
        this_aaa!=NULL;
        n_aaa++, this_aaa=tr_aaa_server_iter_next(aaa_iter)) {
+    tr_debug("tr_tids_req_handler: Preparing to start thread %d.", n_aaa);
+
     aaa_cookie[n_aaa]=talloc(tmp_ctx, struct tr_tids_fwd_cookie);
     if (aaa_cookie[n_aaa]==NULL) {
       tr_notice("tr_tids_req_handler: unable to allocate cookie for AAA thread %d.", n_aaa);
@@ -459,10 +459,14 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     aaa_cookie[n_aaa]->mq=mq;
     aaa_cookie[n_aaa]->aaa_hostname=tr_dup_name(this_aaa->hostname);
     aaa_cookie[n_aaa]->dh_params=tr_dh_dup(orig_req->tidc_dh);
-    aaa_cookie[n_aaa]->fwd_req=tid_dup_req(aaa_cookie, fwd_req);
+    aaa_cookie[n_aaa]->fwd_req=tid_dup_req(fwd_req);
+    talloc_steal(aaa_cookie[n_aaa], aaa_cookie[n_aaa]->fwd_req);
+    tr_debug("tr_tids_req_handler: cookie %d initialized.", n_aaa);
 
     /* Take the cookie out of tmp_ctx before starting thread. If thread starts, it becomes
-     * responsible for freeing it until it queues a response. */
+     * responsible for freeing it until it queues a response. If we did not do this, the possibility
+     * exists that this function exits, freeing the cookie, before the thread takes the cookie
+     * out of our tmp_ctx. This would cause a segfault or talloc error in the thread. */
     talloc_steal(NULL, aaa_cookie[n_aaa]);
     if (0!=pthread_create(&(aaa_thread[n_aaa]), NULL, tr_tids_req_fwd_thread, aaa_cookie[n_aaa])) {
       talloc_steal(tmp_ctx, aaa_cookie[n_aaa]); /* thread start failed; steal this back */
@@ -470,8 +474,9 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
       retval=-1;
       goto cleanup;
     }
+    tr_debug("tr_tids_req_handler: thread %d started.", n_aaa);
   }
+
   /* determine expiration time */
   if (0!=tr_mq_pop_timeout(cfg_mgr->active->internal->tid_req_timeout, &ts_abort)) {
     tr_notice("tr_tids_req_handler: unable to read clock for timeout.");
@@ -480,6 +485,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   }
 
   /* wait for responses */
+  tr_debug("tr_tids_req_handler: waiting for response(s).");
   n_responses=0;
   n_failed=0;
   while (((n_responses+n_failed)<n_aaa) &&
@@ -487,6 +493,9 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     /* process message */
     if (0==strcmp(tr_mq_msg_get_message(msg), TR_TID_MQMSG_SUCCESS)) {
       payload=talloc_get_type_abort(tr_mq_msg_get_payload(msg), TR_RESP_COOKIE);
+      talloc_steal(tmp_ctx, payload); /* put this back in our context */
+      aaa_resp[payload->thread_id]=payload->resp; /* save pointers to these */
+
       if (payload->resp->result==TID_SUCCESS) {
         tr_tids_merge_resps(resp, payload->resp);
         n_responses++;
@@ -499,8 +508,16 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
       }
     } else if (0==strcmp(tr_mq_msg_get_message(msg), TR_TID_MQMSG_FAILURE)) {
       /* failure */
-      payload=talloc_get_type_abort(tr_mq_msg_get_payload(msg), TR_RESP_COOKIE);
       n_failed++;
+      payload=talloc_get_type(tr_mq_msg_get_payload(msg), TR_RESP_COOKIE);
+      if (payload!=NULL) 
+        talloc_steal(tmp_ctx, payload); /* put this back in our context */
+      else {
+        /* this means the thread was unable to allocate a response cookie, and we thus cannot determine which thread it was. This is bad and should never happen in a working system.. Give up. */
+        tr_notice("tr_tids_req_handler: TID request thread sent invalid reply. Aborting!");
+        retval=-1;
+        goto cleanup;
+      }
       tr_notice("tr_tids_req_handler: TID request for AAA server %d failed.",
                 payload->thread_id);
     } else {
@@ -510,8 +527,9 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
       goto cleanup;
     }
     
-    /* Now free the cookie for this thread. Null it so we know we've dealt with it. */
-    talloc_free(aaa_cookie[payload->thread_id]);
+    /* Set the cookie pointer to NULL so we know we've dealt with this one. The
+     * cookie itself is in our tmp_ctx, which we'll free before exiting. Let it hang
+     * around in case we are still using pointers to elements of the cookie. */
     aaa_cookie[payload->thread_id]=NULL;
 
     tr_mq_msg_free(msg);
@@ -522,6 +540,8 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
       break;
   }
 
+  tr_debug("tr_tids_req_handler: done waiting for responses. %d responses, %d failures.",
+           n_responses, n_failed);
   /* Inform any remaining threads that we will no longer handle their responses. */
   for (ii=0; ii<n_aaa; ii++) {
     if (aaa_cookie[ii]!=NULL) {
@@ -539,19 +559,25 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
    * reply (by setting their mq pointer to null). However, some may have responded by placing
    * a message on the mq after we last checked but before we set their mq pointer to null. These
    * will not know that we gave up on them, so we must free their cookies for them. We can just
-   * go through any remaining messages on the mq to identify these threads. */
+   * go through any remaining messages on the mq to identify these threads. By putting them in
+   * our context instead of freeing them directly, we ensure we don't accidentally invalidate
+   * any of our own pointers into the structure before this function exits. */
   while (NULL!=(msg=tr_mq_pop(mq, NULL))) {
     payload=(TR_RESP_COOKIE *)tr_mq_msg_get_payload(msg);
     if (aaa_cookie[payload->thread_id]!=NULL)
-      talloc_free(aaa_cookie[payload->thread_id]);
+      talloc_steal(tmp_ctx, aaa_cookie[payload->thread_id]);
 
     tr_mq_msg_free(msg);
   }
 
   if (n_responses==0) {
-    tid_resp_set_result(resp, TID_ERROR);
-    tid_resp_set_err_msg(resp, tr_new_name("No successful response from AAA server(s)."));
-    tid_resp_set_error_path(resp, orig_req->path);
+    /* No requests succeeded. Forward an error if we got any error responses. */
+    for (ii=0; ii<n_aaa; ii++) {
+      if (aaa_resp[ii]!=NULL)
+        tids_send_response(tids, orig_req, aaa_resp[ii]);
+      else
+        tids_send_err_response(tids, orig_req, "Unable to contact AAA server(s).");
+    }
   }
 
   /* success! */