]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
sync to current darcs tree:
authorMichael Jerris <mike@jerris.com>
Thu, 6 Dec 2007 18:44:14 +0000 (18:44 +0000)
committerMichael Jerris <mike@jerris.com>
Thu, 6 Dec 2007 18:44:14 +0000 (18:44 +0000)
Tue Nov 20 11:46:34 EST 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * nua_register.c: silenced warning with URL_INIT_AS() on Sun CC

Tue Nov 20 11:47:06 EST 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * test_register.c: fixed authentication caching issue

Tue Nov 20 12:09:19 EST 2007  Pekka.Pessi@nokia.com
  * tport: tport_name_is_resolved() now uses host_is_ip_address()

Tue Nov 20 12:53:54 EST 2007  Pekka.Pessi@nokia.com
  * tport.c: fixed EXPENSIVE unresolved bug.

Wed Nov 21 07:10:40 EST 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * test_tport.c: skipping tests on TLS if send fails.

Wed Nov 21 11:46:42 EST 2007  Pekka.Pessi@nokia.com
  * test_nta.c: removed dead code

Thu Nov 22 08:42:14 EST 2007  Pekka.Pessi@nokia.com
  * test_nta.c: refactored client side tests

Thu Nov 22 09:39:45 EST 2007  Pekka.Pessi@nokia.com
  * nta: added nta_sip_is_internal().

Tue Nov 27 13:43:41 EST 2007  Pekka.Pessi@nokia.com
  * test_htable2.c: removed conversion warning

  Conversion of size_t to isize_t when compiled wihout --disable-size-compat.

Wed Nov 21 11:16:04 EST 2007  Daniele Rondina <geaaru at gmail dot com>
  * nta.c: nta_outgoing_*create() now uses NTATAG_TPORT() even if NTATAG_DEFAULT_PROXY() is set

Thu Nov 22 09:36:21 EST 2007  Pekka.Pessi@nokia.com
  * nta.c: always use tport from NTATAG_TPORT() (even if it is bad)

  Add tests, too.

Thu Nov 22 10:01:33 EST 2007  Pekka.Pessi@nokia.com
  * nta: added nta_msg_is_internal().

Mon Nov 26 17:08:16 EST 2007  Pekka.Pessi@nokia.com
  * test_proxy.c: removed memory leaks

Mon Nov 26 17:08:35 EST 2007  Pekka.Pessi@nokia.com
  * test_basic_call.c: fixed --no-proxy tests

Mon Nov 26 17:12:27 EST 2007  Pekka.Pessi@nokia.com
  * sofia-sip/su_wait.h: added su_msg_new(), su_msg_send_to(), su_msg_deinitializer()

  Reduce overhead from message passing.

Mon Nov 26 19:15:41 EST 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * configure.ac: defining HAVE_SOFIA_HTTP

Mon Nov 26 19:23:05 EST 2007  Pekka.Pessi@nokia.com
  * nua: moved message passing into nua_stack.c. Recfactored reference counting.

  This seems to fix the memory leak within 1.12.7.

Wed Nov 28 10:15:07 EST 2007  Pekka.Pessi@nokia.com
  * test_su.c: removed calls of deprecated (and unimplemented) functions su_clone_pause()/su_clone_resume()

Thu Nov 22 09:59:13 EST 2007  Pekka.Pessi@nokia.com
  * nua_stack.c: more logging on bad authentication

Mon Nov 26 19:49:34 EST 2007  Pekka.Pessi@nokia.com
  * tport.h, tport.c: updated tport_create() docs

Thu Nov 29 12:17:40 EST 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * tport: collecting statistics

Thu Nov 29 12:21:10 EST 2007  Pekka.Pessi@nokia.com
  * rules/sofia.am: defining INTERNAL_INCLUDES so it can be used from any subdir

  utils/Makefile.am, libsofia-sip-ua/nua/Makefile.am: using INCLUDES from sofia.am

Thu Nov 29 13:03:44 EST 2007  Pekka.Pessi@nokia.com
  * nua: moved test_nua contents in ltlibraries

Thu Nov 29 13:05:25 EST 2007  Pekka.Pessi@nokia.com
  * Makefile.am, configure.ac: added subdir tests for Check-based module tests

Fri Nov 30 09:03:14 EST 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * nua_session.c: avoid NULL nua_session_state_t pointer in nua_update_client_report

  Thanks to Fabio Margarido for reporting this problem.

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6539 d0543943-73ff-0310-b7d9-9358b9ac24b2

43 files changed:
libs/sofia-sip/Makefile.am
libs/sofia-sip/configure.ac
libs/sofia-sip/libsofia-sip-ua/nta/nta.c
libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h
libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c
libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am
libs/sofia-sip/libsofia-sip-ua/nua/nua.c
libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c
libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c
libs/sofia-sip/libsofia-sip-ua/nua/test_init.c
libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h
libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
libs/sofia-sip/libsofia-sip-ua/nua/test_register.c
libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h
libs/sofia-sip/libsofia-sip-ua/su/su_base_port.c
libs/sofia-sip/libsofia-sip-ua/su/su_port.h
libs/sofia-sip/libsofia-sip-ua/su/su_root.c
libs/sofia-sip/libsofia-sip-ua/su/test_htable2.c
libs/sofia-sip/libsofia-sip-ua/su/test_su.c
libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c
libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h
libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c
libs/sofia-sip/libsofia-sip-ua/tport/tport.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h
libs/sofia-sip/libsofia-sip-ua/url/url.c
libs/sofia-sip/rules/sofia.am
libs/sofia-sip/tests/Makefile.am [new file with mode: 0644]
libs/sofia-sip/tests/check_sofia.c [new file with mode: 0644]
libs/sofia-sip/tests/check_sofia.h [new file with mode: 0644]
libs/sofia-sip/tests/suite_for_nua.c [new file with mode: 0644]
libs/sofia-sip/utils/Makefile.am

index a60e0c88986412a729cf5e795f6afde35f975111..5539a0b267ec248908e0e09ca1b8850a2b966a4f 100644 (file)
@@ -7,7 +7,7 @@
 
 AUTOMAKE_OPTIONS = foreign 1.7
 
-SUBDIRS = libsofia-sip-ua $(GLIB_SUBDIRS) utils packages
+SUBDIRS = libsofia-sip-ua $(GLIB_SUBDIRS) utils packages tests
 DIST_SUBDIRS = libsofia-sip-ua libsofia-sip-ua-glib utils packages \
        win32 open_c
 
index 00fe8a32be96aa85f9b15c13640893539a2235d5..58cadbea90c92c1dcc740d5e5914bb2d6ab5d913 100644 (file)
@@ -100,6 +100,10 @@ SAC_SOFIA_SU
 SAC_OPENSSL
 SAC_TPORT
 
+dnl Check is used for testing
+PKG_CHECK_MODULES(CHECK, check >= 0.9.4, have_check="yes", have_check="no")
+AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")
+
 ### internal modules
 ### ----------------
 AC_DEFINE([HAVE_SOFIA_SIP], 1, [Define to 1 always])
@@ -122,11 +126,12 @@ fi
 AM_CONDITIONAL([HAVE_STUN], [test "x$enable_stun" = xyes])
 
 AC_ARG_ENABLE(nth,
-[  --disable-nth           disable nth and http modules (enabled)],
+[  --disable-nth           disable HTTP-related modules nth and http (enabled)],
  , enable_nth=yes)
 AM_CONDITIONAL([HAVE_NTH], [test "x$enable_nth" = xyes])
 if test x$enable_nth = xyes ; then
   AC_DEFINE([HAVE_SOFIA_NTH], 1, [Define to 1 if we use NTH library])
+  AC_DEFINE([HAVE_SOFIA_HTTP], 1, [Define to 1 if we use HTTP parser library])
 fi
 
 dnl Disable NTLM support by default
@@ -325,6 +330,7 @@ libsofia-sip-ua-glib/su-glib/Makefile
 libsofia-sip-ua-glib/su-glib/Doxyfile
 utils/Makefile
 utils/Doxyfile
+tests/Makefile
 win32/Makefile
 win32/config.h
 open_c/Makefile
index 3bd34df64873f0f75104c7986653fbc629359976..d010f9ca14ef4a7e5c24176b76abb0900b4120d2 100644 (file)
@@ -2780,12 +2780,26 @@ void nta_msg_discard(nta_agent_t *agent, msg_t *msg)
   msg_destroy(msg);
 }
 
+/** Check if the headers are from response generated locally by NTA. */
+int  nta_sip_is_internal(sip_t const *sip)
+{
+  return 
+    sip == NULL                /* No message generated */
+    || (sip->sip_flags & NTA_INTERNAL_MSG) == NTA_INTERNAL_MSG;
+}
+
 /** Check if the message is internally generated by NTA. */
-int  nta_is_internal_msg(msg_t const *msg)
+int nta_msg_is_internal(msg_t const *msg)
 {
   return msg_get_flags(msg, NTA_INTERNAL_MSG) == NTA_INTERNAL_MSG;
 }
 
+/** Check if the message is internally generated by NTA. 
+ *
+ * @deprecated Use nta_msg_is_internal() instead
+ */
+int  nta_is_internal_msg(msg_t const *msg) { return nta_msg_is_internal(msg); }
+
 /* ====================================================================== */
 /* 5) Stateless operation */
 
@@ -6343,6 +6357,7 @@ static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
                              msg_t *msg, sip_t *sip,
                              tagi_t *tags);
 static void outgoing_prepare_send(nta_outgoing_t *orq);
+static void outgoing_send_via(nta_outgoing_t *orq, tport_t *tp);
 static void outgoing_send(nta_outgoing_t *orq, int retransmit);
 static void outgoing_try_tcp_instead(nta_outgoing_t *orq);
 static void outgoing_try_udp_instead(nta_outgoing_t *orq);
@@ -6884,7 +6899,7 @@ nta_outgoing_t *outgoing_create(nta_agent_t *agent,
   int invite_100rel = agent->sa_invite_100rel;
 
   tagi_t const *t;
-  tport_t const *override_tport = NULL;
+  tport_t *override_tport = NULL;
 
   if (!agent->sa_tport_ip6)
     res_order = nta_res_ip4_only;
@@ -6988,11 +7003,16 @@ nta_outgoing_t *outgoing_create(nta_agent_t *agent,
       tpn = tport_name(override_tport);
       orq->orq_user_tport = 1;
     }
-    
   }
 
-  if (route_url) {
+  if (route_url && !orq->orq_user_tport) {
     invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url);
+
+    if (override_tport) {      /* Use transport protocol name from transport  */
+      if (strcmp(orq->orq_tpn->tpn_proto, "*") == 0) 
+       orq->orq_tpn->tpn_proto = tport_name(override_tport)->tpn_proto;
+    }
+
     resolved = tport_name_is_resolved(orq->orq_tpn);
     orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
     if (route_url != (url_string_t *)agent->sa_default_proxy)
@@ -7015,7 +7035,11 @@ nta_outgoing_t *outgoing_create(nta_agent_t *agent,
     sip_fragment_clear(sip->sip_request->rq_common);
   }
 
-  orq->orq_tpn->tpn_ident = tp_ident;
+  if (!override_tport)
+    orq->orq_tpn->tpn_ident = tp_ident;
+  else
+    orq->orq_tpn->tpn_ident = tport_name(override_tport)->tpn_ident;
+
   if (comp == NULL)
     orq->orq_tpn->tpn_comp = comp;
 
@@ -7100,7 +7124,9 @@ nta_outgoing_t *outgoing_create(nta_agent_t *agent,
   agent->sa_stats->as_client_tr++;
   orq->orq_hash = NTA_HASH(sip->sip_call_id, sip->sip_cseq->cs_seq);
 
-  if (resolved)
+  if (orq->orq_user_tport) 
+    outgoing_send_via(orq, override_tport);
+  else if (resolved)
     outgoing_prepare_send(orq);
 #if HAVE_SOFIA_SRESOLV
   else
@@ -7146,7 +7172,6 @@ outgoing_prepare_send(nta_outgoing_t *orq)
     tpn->tpn_port = "";
 
   tp = tport_by_name(sa->sa_tports, tpn);
-  orq->orq_tport = tport_ref(tp);
 
   if (tpn->tpn_port[0] == '\0') {
     if (sips || tport_has_tls(tp))
@@ -7155,17 +7180,28 @@ outgoing_prepare_send(nta_outgoing_t *orq)
       tpn->tpn_port = "5060";
   }
 
-  if (!orq->orq_tport) {
-    if (sips) {
-      SU_DEBUG_3(("nta outgoing create: no secure transport\n"));
-      outgoing_reply(orq, SIP_416_UNSUPPORTED_URI, 1);
-    }
-    else {
-      SU_DEBUG_3(("nta outgoing create: no transport protocol\n"));
-      outgoing_reply(orq, 503, "No transport", 1);
-    }
-    return;
+  if (tp) {
+    outgoing_send_via(orq, tp);
+  }
+  else if (sips) {
+    SU_DEBUG_3(("nta outgoing create: no secure transport\n"));
+    outgoing_reply(orq, SIP_416_UNSUPPORTED_URI, 1);
+  }
+  else {
+    SU_DEBUG_3(("nta outgoing create: no transport protocol\n"));
+    outgoing_reply(orq, 503, "No transport", 1);
   }
+}
+  
+/** Send request using given transport */
+static void
+outgoing_send_via(nta_outgoing_t *orq, tport_t *tp)
+{
+  tport_t *old_tp = orq->orq_tport;
+
+  orq->orq_tport = tport_ref(tp);
+
+  if (old_tp) tport_unref(old_tp);
 
   if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) {
     SU_DEBUG_3(("nta outgoing create: cannot insert Via line\n"));
@@ -7198,13 +7234,14 @@ outgoing_prepare_send(nta_outgoing_t *orq)
   if (orq->orq_delayed) {
     SU_DEBUG_5(("nta: delayed sending %s (%u)\n",
                orq->orq_method_name, orq->orq_cseq->cs_seq));
-    outgoing_queue(sa->sa_out.delayed, orq);
+    outgoing_queue(orq->orq_agent->sa_out.delayed, orq);
     return;
   }
 
   outgoing_send(orq, 0);
 }
 
+
 /** Send a request */
 static void
 outgoing_send(nta_outgoing_t *orq, int retransmit)
@@ -7226,6 +7263,11 @@ outgoing_send(nta_outgoing_t *orq, int retransmit)
     return;
   }
 
+  if (orq->orq_user_tport && !tport_is_clear_to_send(orq->orq_tport)) {
+    outgoing_tport_error(agent, orq, NULL, orq->orq_request, EPIPE);
+    return;
+  }
+
   if (!retransmit)
     orq->orq_sent = now;
 
index 50fd4d735def1ffddd833ca04e0d874637e0f27d..2d34688774c730d53252905d1138b56cc99c6b3f 100644 (file)
@@ -170,7 +170,8 @@ SOFIAPUBFUN int nta_msg_request_complete(msg_t *msg,
                                         char const *method_name,
                                         url_string_t const *req_url);
 
-SOFIAPUBFUN int nta_is_internal_msg(msg_t const *msg);
+SOFIAPUBFUN int nta_msg_is_internal(msg_t const *msg);
+SOFIAPUBFUN int nta_sip_is_internal(sip_t const *sip);
 
 /* ----------------------------------------------------------------------
  * 5) Leg-level prototypes
@@ -479,6 +480,8 @@ SOFIAPUBFUN void nta_reliable_destroy(nta_reliable_t *);
 
 SOFIAPUBFUN void nta_msg_discard(nta_agent_t *agent, msg_t *msg);
 
+SOFIAPUBFUN int nta_is_internal_msg(msg_t const *msg);
+
 SOFIA_END_DECLS
 
 #endif
index 4cc562fbc0246dab8acde3499def97c614c99151..8314f8279e51ce9198c390f759b03d2ad2b8a7a8 100644 (file)
@@ -35,6 +35,7 @@
 #include "config.h"
 
 typedef struct agent_t agent_t;
+typedef struct client_t client_t;
 
 #define SU_ROOT_MAGIC_T      agent_t
 
@@ -44,7 +45,8 @@ typedef struct agent_t agent_t;
 
 #define NTA_AGENT_MAGIC_T    agent_t
 #define NTA_LEG_MAGIC_T      agent_t
-#define NTA_OUTGOING_MAGIC_T agent_t
+#define NTA_OUTGOING_MAGIC_T client_t
+#define NTA_OUTGOING_MAGIC_T0 agent_t
 #define NTA_INCOMING_MAGIC_T agent_t
 #define NTA_RELIABLE_MAGIC_T agent_t
 
@@ -59,6 +61,7 @@ typedef struct agent_t agent_t;
 #include <sofia-sip/su_log.h>
 #include <sofia-sip/sofia_features.h>
 #include <sofia-sip/hostdomain.h>
+#include <sofia-sip/tport.h>
 
 #include <sofia-sip/string0.h>
 
@@ -99,6 +102,24 @@ struct sigcomp_compartment;
 
 char const name[] = "test_nta";
 
+typedef struct invite_client_t invite_client_t;
+
+typedef int client_check_f(client_t *, nta_outgoing_t *, sip_t const *);
+typedef int client_deinit_f(client_t *);
+
+struct client_t {
+  agent_t *c_ag;
+  char const *c_name;
+  client_check_f * c_check;
+  client_check_f * const * c_checks;
+  client_deinit_f * c_deinit;
+  void *c_extra;
+  nta_outgoing_t *c_orq;
+  int c_status;
+  int c_final;
+  int c_errors;
+};
+
 struct agent_t {
   su_home_t       ag_home[1];
   int             ag_flags;
@@ -114,8 +135,7 @@ struct agent_t {
   unsigned        ag_drop;
 
   nta_outgoing_t *ag_orq;
-  int             ag_status;
-  unsigned        ag_canceled:1, ag_acked:1, :0;
+  unsigned        ag_running :1, ag_canceled:1, ag_acked:1, :0;
 
   char const     *ag_comp;
   struct sigcomp_compartment *ag_client_compartment;
@@ -147,12 +167,8 @@ struct agent_t {
   nta_leg_t      *ag_tag_remote; /**< If this is set, outgoing_callback()
                                  *   tags it with the tag from remote.
                                  */
-  int             ag_tag_status; /**< Which response established dialog */
-  msg_param_t     ag_call_tag;  /**< Tag used to establish dialog */
-
   nta_reliable_t *ag_reliable;
 
-  sip_via_t      *ag_out_via;  /**< Outgoing via */
   sip_via_t      *ag_in_via;   /**< Incoming via */
 
   sip_content_type_t *ag_content_type;
@@ -160,6 +176,7 @@ struct agent_t {
 
   msg_t          *ag_probe_msg;
 
+
   /* Dummy servers */
   char const     *ag_sink_port;
   su_socket_t     ag_sink_socket, ag_down_socket;
@@ -241,8 +258,8 @@ void leg_zap(agent_t *ag, nta_leg_t *leg)
   else if (leg == ag->ag_bob_leg)
     ag->ag_bob_leg = NULL;
   else 
-     printf("%s:%u: %s: did not exist\n", 
-           __FILE__, __LINE__, __func__);
+    printf("%s:%u: %s: did not exist\n", 
+          __FILE__, __LINE__, __func__);
 
   nta_leg_destroy(leg);
 }
@@ -344,87 +361,122 @@ int new_leg_callback_200(agent_t *ag,
 }
 
 
-int outgoing_callback(agent_t *ag,
+static client_check_f * const default_checks[];
+
+int outgoing_callback(client_t *ctx,
                      nta_outgoing_t *orq,
                      sip_t const *sip)
 {
-  BEGIN();
-
-  int status = sip->sip_status->st_status;
+  agent_t *ag = ctx->c_ag;
+  int status = nta_outgoing_status(orq);
+  client_check_f * const *checks;
 
   if (tstflags & tst_verbatim) {
-    printf("%s: %s: %s %03d %s\n", name, __func__, 
-          sip->sip_status->st_version, 
-          sip->sip_status->st_status, 
-          sip->sip_status->st_phrase);
+    if (sip)
+      printf("%s: %s: response %s %03d %s\n", name, ctx->c_name, 
+            sip->sip_status->st_version, 
+            sip->sip_status->st_status, 
+            sip->sip_status->st_phrase);
+    else
+      printf("%s: %s: callback %03d\n", name, ctx->c_name,
+            status);
   }
 
-  TEST_P(orq, ag->ag_orq);
+  if (status >= 200 && ag->ag_comp) {          /* XXX */
+    nta_compartment_decref(&ag->ag_client_compartment);
+    ag->ag_client_compartment = nta_outgoing_compartment(ctx->c_orq);
+  }
 
-  ag->ag_status = status;
+  if (status > ctx->c_status)
+    ctx->c_status = status;
+  if (status >= 200)
+    ctx->c_final = 1;
 
-  if (status < 200)
-    return 0;
+  if (ctx->c_check && ctx->c_check(ctx, orq, sip))
+    ctx->c_errors++;
 
-  if (ag->ag_comp) {
-    nta_compartment_decref(&ag->ag_client_compartment);
-    ag->ag_client_compartment = nta_outgoing_compartment(orq);
-  }
+  checks = ctx->c_checks;
 
-  if (ag->ag_out_via == NULL)
-    ag->ag_out_via = sip_via_dup(ag->ag_home, sip->sip_via);
+  for (checks = checks ? checks : default_checks; *checks; checks++)
+    if ((*checks)(ctx, ctx->c_orq, sip))
+      ctx->c_errors++;
 
-  if (ag->ag_tag_remote) {
-    TEST_S(nta_leg_rtag(ag->ag_tag_remote, sip->sip_to->a_tag), 
-          sip->sip_to->a_tag);
-    ag->ag_tag_remote = NULL;
-  }
+  return 0;
+}
 
-  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+/** Deinit client. Return nonzero if client checks failed. */
+static 
+int client_deinit(client_t *c)
+{
+  int errors = c->c_errors;
 
-  nta_outgoing_destroy(orq);
-  ag->ag_orq = NULL;
+  if (c->c_deinit && c->c_deinit(c))
+    errors++;
 
-  END();
+  if (c->c_orq) nta_outgoing_destroy(c->c_orq), c->c_orq = NULL;
+
+  c->c_errors = 0; 
+  c->c_status = 0;
+
+  return errors;
 }
 
-static
-int test_magic_branch(agent_t *ag, sip_t const *sip) 
+
+static 
+void nta_test_run(agent_t *ag)
 {
-  BEGIN();
-  
-  if (sip) {
-    TEST_1(sip->sip_via);
-    TEST_S(sip->sip_via->v_branch, "MagicalBranch");
+  for (ag->ag_running = 1; ag->ag_running;) {
+    if (tstflags & tst_verbatim) {
+      fputs(".", stdout); fflush(stdout);
+    }
+    su_root_step(ag->ag_root, 500L);
   }
-
-  END();
 }
 
-static
-int magic_callback(agent_t *ag,
-                  nta_outgoing_t *orq,
-                  sip_t const *sip)
+
+/** Run client test. Return nonzero if client checks failed. */
+static 
+int client_run_with(client_t *c, int expected, void (*runner)(client_t *c))
 {
-  test_magic_branch(ag, sip);
-  return outgoing_callback(ag, orq, sip);
+  int resulting;
+
+  TEST_1(c->c_orq != NULL);
+
+  runner(c);
+
+  resulting = c->c_status;
+
+  if (client_deinit(c))
+    return 1;
+
+  if (expected)
+    TEST(resulting, expected);
+
+  return 0;
 }
 
-void 
-nta_test_run(agent_t *ag)
+static 
+void until_final_received(client_t *c)
 {
-  for (ag->ag_status = 0; ag->ag_status < 200;) {
+  for (c->c_final = 0; !c->c_final; ) {
     if (tstflags & tst_verbatim) {
       fputs(".", stdout); fflush(stdout);
     }
-    su_root_step(ag->ag_root, 500L);
+    su_root_step(c->c_ag->ag_root, 500L);
   }
 }
 
-void 
-nta_test_run_until_acked(agent_t *ag)
+static 
+int client_run(client_t *c, int expected)
+{
+  return client_run_with(c, expected, until_final_received);
+}
+
+static
+void until_server_acked(client_t *c)
 {
-  ag->ag_status = 0;
+  agent_t *ag = c->c_ag;
+
   for (ag->ag_acked = 0; !ag->ag_acked;) {
     if (tstflags & tst_verbatim) {
       fputs(".", stdout); fflush(stdout);
@@ -433,10 +485,17 @@ nta_test_run_until_acked(agent_t *ag)
   }
 }
 
+static 
+int client_run_until_acked(client_t *c, int expected)
+{
+  return client_run_with(c, expected, until_server_acked);
+}
+
 void 
-nta_test_run_until_canceled(agent_t *ag)
+until_server_canceled(client_t *c)
 {
-  ag->ag_status = 0;
+  agent_t *ag = c->c_ag;
+
   for (ag->ag_canceled = 0; !ag->ag_canceled;) {
     if (tstflags & tst_verbatim) {
       fputs(".", stdout); fflush(stdout);
@@ -445,6 +504,13 @@ nta_test_run_until_canceled(agent_t *ag)
   }
 }
 
+static 
+int client_run_until_canceled(client_t *c, int expected)
+{
+  return client_run_with(c, expected, until_server_canceled);
+}
+
+
 #include <sofia-sip/msg_mclass.h>
 
 int test_init(agent_t *ag, char const *resolv_conf)
@@ -507,16 +573,16 @@ int test_init(agent_t *ag, char const *resolv_conf)
   
   /* Create agent */
   ag->ag_agent = nta_agent_create(ag->ag_root,
-                        (url_string_t *)contact,
-                        NULL,
-                        NULL,
-                        NTATAG_MCLASS(ag->ag_mclass),
-                        NTATAG_USE_TIMESTAMP(1),
-                        SRESTAG_RESOLV_CONF(resolv_conf),
-                        NTATAG_USE_NAPTR(0),
-                        NTATAG_USE_SRV(0),
-                        NTATAG_PRELOAD(2048),
-                        TAG_END());
+                                 (url_string_t *)contact,
+                                 NULL,
+                                 NULL,
+                                 NTATAG_MCLASS(ag->ag_mclass),
+                                 NTATAG_USE_TIMESTAMP(1),
+                                 SRESTAG_RESOLV_CONF(resolv_conf),
+                                 NTATAG_USE_NAPTR(0),
+                                 NTATAG_USE_SRV(0),
+                                 NTATAG_PRELOAD(2048),
+                                 TAG_END());
   TEST_1(ag->ag_agent);
 
   {
@@ -582,30 +648,30 @@ int test_init(agent_t *ag, char const *resolv_conf)
     ag->ag_aliases = m;
 
     err = nta_agent_set_params(ag->ag_agent, 
-                     NTATAG_ALIASES(ag->ag_aliases),
-                     NTATAG_REL100(1),
-                     NTATAG_UA(1), 
-                     NTATAG_USE_NAPTR(1),
-                     NTATAG_USE_SRV(1),
-                     NTATAG_MAX_FORWARDS(20),
-                     TAG_END());
+                              NTATAG_ALIASES(ag->ag_aliases),
+                              NTATAG_REL100(1),
+                              NTATAG_UA(1), 
+                              NTATAG_USE_NAPTR(1),
+                              NTATAG_USE_SRV(1),
+                              NTATAG_MAX_FORWARDS(20),
+                              TAG_END());
     TEST(err, 6);
 
     err = nta_agent_set_params(ag->ag_agent, 
-                     NTATAG_ALIASES(ag->ag_aliases),
-                     NTATAG_DEFAULT_PROXY("sip:127.0.0.1"),
-                     TAG_END());
+                              NTATAG_ALIASES(ag->ag_aliases),
+                              NTATAG_DEFAULT_PROXY("sip:127.0.0.1"),
+                              TAG_END());
     TEST(err, 2);
 
     err = nta_agent_set_params(ag->ag_agent, 
-                     NTATAG_ALIASES(ag->ag_aliases),
-                     NTATAG_DEFAULT_PROXY(NULL),
-                     TAG_END());
+                              NTATAG_ALIASES(ag->ag_aliases),
+                              NTATAG_DEFAULT_PROXY(NULL),
+                              TAG_END());
     TEST(err, 2);
 
     err = nta_agent_set_params(ag->ag_agent, 
-                     NTATAG_DEFAULT_PROXY("tel:+35878008000"),
-                     TAG_END());
+                              NTATAG_DEFAULT_PROXY("tel:+35878008000"),
+                              TAG_END());
     TEST(err, -1);
 
   }
@@ -617,11 +683,11 @@ int test_init(agent_t *ag, char const *resolv_conf)
     *url = *ag->ag_aliases->m_url;
     url->url_user = "%";
     ag->ag_server_leg = nta_leg_tcreate(ag->ag_agent, 
-                      leg_callback_200,
-                      ag,
-                      NTATAG_NO_DIALOG(1),
-                      URLTAG_URL(url),
-                      TAG_END());
+                                       leg_callback_200,
+                                       ag,
+                                       NTATAG_NO_DIALOG(1),
+                                       URLTAG_URL(url),
+                                       TAG_END());
     TEST_1(ag->ag_server_leg);
   }
 
@@ -634,10 +700,10 @@ int test_reinit(agent_t *ag)
   /* Create a new default leg */
   nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL;
   TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent, 
-                                            leg_callback_200,
-                                            ag,
-                                            NTATAG_NO_DIALOG(1),
-                                            TAG_END()));
+                                             leg_callback_200,
+                                             ag,
+                                             NTATAG_NO_DIALOG(1),
+                                             TAG_END()));
   END();
 }
 
@@ -836,6 +902,92 @@ sip_payload_t *test_payload(su_home_t *home, size_t size)
   return pl;
 }
 
+static 
+int client_check_to_tag(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (sip) 
+    TEST_1(sip->sip_to && sip->sip_to->a_tag);
+  return 0;
+}
+
+static 
+int check_magic_branch(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (sip) {
+    TEST_1(sip->sip_via);
+    TEST_S(sip->sip_via->v_branch, "MagicalBranch");
+  }
+  return 0;
+}
+
+static
+int check_via_with_sigcomp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (sip && sip->sip_via) {
+    TEST_S(sip->sip_via->v_comp, "sigcomp");
+  }
+  return 0;
+}
+
+static
+int check_via_without_sigcomp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (sip && sip->sip_via) {
+    TEST_1(sip->sip_via->v_comp == NULL);
+  }
+  return 0;
+}
+
+static
+int check_via_with_tcp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (sip && sip->sip_via) {
+    TEST_S(sip->sip_via->v_protocol, "SIP/2.0/TCP");
+  }
+  return 0;
+}
+
+static
+int check_via_with_sctp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (sip && sip->sip_via) {
+    TEST_S(sip->sip_via->v_protocol, "SIP/2.0/SCTP");
+  }
+  return 0;
+}
+
+static
+int check_via_with_udp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (sip && sip->sip_via) {
+    TEST_S(sip->sip_via->v_protocol, "SIP/2.0/UDP");
+  }
+  return 0;
+}
+
+static
+int save_and_check_tcp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  if (ctx->c_status >= 200 && ctx->c_extra) {
+    tport_t *tport = nta_outgoing_transport(orq);
+    TEST_1(tport);
+    *(tport_t **)ctx->c_extra = tport;
+  }
+
+  return check_via_with_tcp(ctx, orq, sip);
+}
+
+
+static client_check_f * const default_checks[] = {
+  client_check_to_tag,
+  NULL
+};
+
+static client_check_f * const no_default_checks[] = {
+  NULL
+};
+
+
 /* Test transports */
 
 int test_tports(agent_t *ag)
@@ -844,6 +996,7 @@ int test_tports(agent_t *ag)
   sip_via_t const *v, *v_udp_only = NULL;
   char const *udp_comp = NULL;
   char const *tcp_comp = NULL;
+  tport_t *tcp_tport = NULL;
 
   url_t url[1];
 
@@ -893,36 +1046,32 @@ int test_tports(agent_t *ag)
      */
     char const p_acid[] = "P-Access-Network-Info: IEEE-802.11g\n";
     url_t url[1];
+    client_t ctx[1] = {{ ag, "Test 0.1", check_via_without_sigcomp }};
 
     *url = *ag->ag_contact->m_url;
     url->url_params = NULL;
     ag->ag_expect_leg = ag->ag_default_leg;
-    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
-
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, 
-                              outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.1"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              SIPTAG_HEADER_STR(p_acid),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, 
+                          outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_HEADER_STR(p_acid),
+                          TAG_END());
+
+    TEST_1(!client_run(ctx, 200));
+
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
-    TEST_1(ag->ag_request);
 
+    TEST_1(ag->ag_request);
     msg_destroy(ag->ag_request), ag->ag_request = NULL;
 
-    TEST_1(ag->ag_out_via->v_comp == NULL);
-
     nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
   }
 
@@ -933,30 +1082,27 @@ int test_tports(agent_t *ag)
      */
     url_t url[1];
     sip_t *sip;
+    client_t ctx[1] = {{ ag, "Test 0.1.2", check_via_without_sigcomp }};
     
     *url = *ag->ag_contact->m_url;
     /* Test that method parameter is stripped and headers in query are used */
     url->url_params = "method=MESSAGE;user=IP";
     url->url_headers = "organization=United%20Testers";
     ag->ag_expect_leg = ag->ag_default_leg;
-    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
-
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, 
-                              outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.1.2"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, 
+                          outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
     TEST_1(ag->ag_request);
     TEST_1(sip = sip_object(ag->ag_request));
@@ -965,8 +1111,6 @@ int test_tports(agent_t *ag)
     TEST_S(sip->sip_organization->g_string, "United Testers");
     TEST_S(sip->sip_request->rq_url->url_params, "user=IP");
     
-    TEST_1(ag->ag_out_via->v_comp == NULL);
-
     nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
   }
 
@@ -977,6 +1121,7 @@ int test_tports(agent_t *ag)
     url_t url[1];
     sip_payload_t *pl;
     size_t size = 1024;
+    client_t ctx[1] = {{ ag, "Test 0.1.3", check_via_with_sigcomp }};
 
     *url = *ag->ag_aliases->m_url;
     url->url_user = "alice";
@@ -988,30 +1133,26 @@ int test_tports(agent_t *ag)
     TEST_1(pl = test_payload(ag->ag_home, size));
 
     ag->ag_expect_leg = ag->ag_server_leg;
-    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
 
-    ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                               ag->ag_obp,
-                               SIP_METHOD_MESSAGE,
-                               (url_string_t *)url,
-                               NTATAG_COMP("sigcomp"),
-                               SIPTAG_SUBJECT_STR("Test 0.1.3"),
-                               SIPTAG_FROM(ag->ag_bob),
-                               SIPTAG_TO(ag->ag_alice),
-                               SIPTAG_CONTACT(ag->ag_m_bob),
-                               SIPTAG_PAYLOAD(pl),
-                               TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          NTATAG_COMP("sigcomp"),
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          TAG_END());
     su_free(ag->ag_home, pl);
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
+    TEST_1(!client_run(ctx, 200));
+
     TEST_1(ag->ag_client_compartment);
     nta_compartment_decref(&ag->ag_client_compartment);
-    TEST_P(ag->ag_orq, NULL);
     TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-    TEST_S(ag->ag_out_via->v_comp, "sigcomp");
   }
 
   /* Test 0.2
@@ -1020,10 +1161,13 @@ int test_tports(agent_t *ag)
    * of 512 kB
    */
   if (tcp) {
+    client_t ctx[1] = {{ ag, "Test 0.2", save_and_check_tcp, }};
     url_t url[1];
     sip_payload_t *pl;
     usize_t size = 512 * 1024;
 
+    ctx->c_extra = &tcp_tport;
+
     *url = *ag->ag_aliases->m_url;
     url->url_user = "alice";
     url->url_params = "transport=tcp";
@@ -1031,25 +1175,112 @@ int test_tports(agent_t *ag)
     TEST_1(pl = test_payload(ag->ag_home, size));
 
     ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_orq = 
-    nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                      NULL,
-                      SIP_METHOD_MESSAGE,
-                      (url_string_t *)url,
-                      SIPTAG_SUBJECT_STR("Test 0.2"),
-                      SIPTAG_FROM(ag->ag_bob),
-                      SIPTAG_TO(ag->ag_alice),
-                      SIPTAG_CONTACT(ag->ag_m_bob),
-                      SIPTAG_PAYLOAD(pl),
-                      NTATAG_DEFAULT_PROXY(ag->ag_obp),
-                      TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          NTATAG_DEFAULT_PROXY(ag->ag_obp),
+                          TAG_END());
     su_free(ag->ag_home, pl);
+    TEST_1(!client_run(ctx, 200));
+    TEST_1(tcp_tport);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  if (tcp_tport) {
+    /* Test 0.2.1 - always use transport connection from NTATAG_TPORT()
+     *
+     * Test bug reported by geaaru 
+     * - NTATAG_TPORT() is not used if NTATAG_DEFAULT_PROXY() is given
+     */
+    client_t ctx[1] = {{ ag, "Test 0.2.1", save_and_check_tcp }};
+    url_t url[1];
+    sip_payload_t *pl;
+    tport_t *used_tport = NULL;
+    
+    ctx->c_extra = &used_tport;
+    
+    TEST(tport_shutdown(tcp_tport, 1), 0); /* Not going to send anymore */
+
+    TEST_1(pl = test_payload(ag->ag_home, 512));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          NTATAG_DEFAULT_PROXY(ag->ag_obp),
+                          NTATAG_TPORT(tcp_tport),
+                          TAG_END());
+    su_free(ag->ag_home, pl);
+    TEST_1(!client_run(ctx, 503));
+
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+
+    TEST_1(used_tport == tcp_tport);
+
+    tport_unref(tcp_tport), tcp_tport = NULL;
+
+    if (v_udp_only)            /* Prepare for next test */
+      TEST_1(tcp_tport = tport_ref(tport_parent(used_tport)));
+    tport_unref(used_tport);
+  }
+
+  if (tcp_tport) {
+    /* test 0.2.2 - select transport protocol using NTATAG_TPORT()
+     *
+     * Use primary NTATAG_TPORT() to select transport
+     */
+    client_t ctx[1] = {{ ag, "Test 0.2.2", save_and_check_tcp }};
+    url_t url[1];
+    sip_payload_t *pl;
+    tport_t *used_tport = NULL;
+    
+    ctx->c_extra = &used_tport;
+    TEST_1(tport_is_primary(tcp_tport));
+
+    TEST_1(pl = test_payload(ag->ag_home, 512));
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+    url->url_host = v_udp_only->v_host;
+    url->url_port = v_udp_only->v_port;
+    url->url_params = NULL;    /* No sigcomp */
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          (url_string_t *)url,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          NTATAG_TPORT(tcp_tport),
+                          TAG_END());
+    su_free(ag->ag_home, pl);
+    TEST_1(!client_run(ctx, 503));
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
     TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+
+    TEST_1(used_tport);
+    TEST_1(tport_is_tcp(used_tport));
+    tport_unref(used_tport);
+    tport_unref(tcp_tport), tcp_tport = NULL;
   }
 
   /* Test 0.3
@@ -1057,6 +1288,7 @@ int test_tports(agent_t *ag)
    * This time include a large payload of 512 kB, let NTA choose transport.
    */
   if (tcp) {
+    client_t ctx[1] = {{ ag, "Test 0.3" }};
     url_t url[1];
     sip_payload_t *pl;
     usize_t size = 512 * 1024;
@@ -1067,23 +1299,19 @@ int test_tports(agent_t *ag)
     TEST_1(pl = test_payload(ag->ag_home, size));
 
     ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_orq = 
-      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                      ag->ag_obp,
-                      SIP_METHOD_MESSAGE,
-                      (url_string_t *)url,
-                      SIPTAG_SUBJECT_STR("Test 0.3"),
-                      SIPTAG_FROM(ag->ag_bob),
-                      SIPTAG_TO(ag->ag_alice),
-                      SIPTAG_CONTACT(ag->ag_m_bob),
-                      SIPTAG_PAYLOAD(pl),
-                      TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          TAG_END());
     su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
   }
 
@@ -1092,6 +1320,7 @@ int test_tports(agent_t *ag)
    * This time include a payload of 2 kB, let NTA choose transport.
    */
   {
+    client_t ctx[1] = {{ ag, "Test 0.4.1", check_via_with_tcp }};
     url_t url[1];
     sip_payload_t *pl;
     usize_t size = 2 * 1024;
@@ -1100,30 +1329,24 @@ int test_tports(agent_t *ag)
     url->url_user = "alice";
 
     TEST_1(pl = test_payload(ag->ag_home, size));
-    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
 
     ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_orq = 
-      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                      ag->ag_obp,
-                      SIP_METHOD_MESSAGE,
-                      (url_string_t *)url,
-                      SIPTAG_SUBJECT_STR("Test 0.4.1"),
-                      SIPTAG_FROM(ag->ag_bob),
-                      SIPTAG_TO(ag->ag_alice),
-                      SIPTAG_CONTACT(ag->ag_m_bob),
-                      SIPTAG_PAYLOAD(pl),
-                      TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          TAG_END());
     su_free(ag->ag_home, pl);
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    TEST_1(!client_run(ctx, 200));
+
     TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-    TEST_1(ag->ag_out_via);
-    TEST_1(strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/TCP") == 0 ||
-          strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/SCTP") == 0);
     su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
   }
 
@@ -1132,6 +1355,7 @@ int test_tports(agent_t *ag)
    * This time include a payload of 2 kB, let NTA choose transport.
    */
   if (v_udp_only) {
+    client_t ctx[1] = {{ ag, "Test 0.4.2", check_via_with_udp }};
     url_t url[1];
     sip_payload_t *pl;
     usize_t size = 2 * 1024;
@@ -1148,24 +1372,23 @@ int test_tports(agent_t *ag)
 
     su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
 
-    ag->ag_orq = 
-      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                      ag->ag_obp,
-                      SIP_METHOD_MESSAGE,
-                      (url_string_t *)url,
-                      SIPTAG_SUBJECT_STR("Test 0.4.2"),
-                      SIPTAG_FROM(ag->ag_bob),
-                      SIPTAG_TO(ag->ag_alice),
-                      SIPTAG_CONTACT(ag->ag_m_bob),
-                      SIPTAG_PAYLOAD(pl),
-                      TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          TAG_END());
     su_free(ag->ag_home, pl);
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    TEST_1(!client_run(ctx, 200));
+
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+
     TEST_1(ag->ag_in_via);
     TEST_1(strcasecmp(ag->ag_in_via->v_protocol, "SIP/2.0/UDP") == 0);
     su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
@@ -1176,6 +1399,7 @@ int test_tports(agent_t *ag)
    * This time include a payload of 2 kB, try to use UDP.
    */
   if (udp) {
+    client_t ctx[1] = {{ ag, "Test 0.5", check_via_with_udp }};
     url_t url[1];
     sip_payload_t *pl;
     usize_t size = 2 * 1024;
@@ -1185,36 +1409,33 @@ int test_tports(agent_t *ag)
 
     TEST_1(pl = test_payload(ag->ag_home, size));
 
-    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
-
     ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_orq = 
-      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                      ag->ag_obp,
-                      SIP_METHOD_MESSAGE,
-                      (url_string_t *)url,
-                      SIPTAG_SUBJECT_STR("Test 0.5"),
-                      SIPTAG_FROM(ag->ag_bob),
-                      SIPTAG_TO(ag->ag_alice),
-                      SIPTAG_CONTACT(ag->ag_m_bob),
-                      SIPTAG_PAYLOAD(pl),
-                      TPTAG_MTU(0xffffffff),
-                      TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          TPTAG_MTU(0xffffffff),
+                          TAG_END());
     su_free(ag->ag_home, pl);
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    TEST_1(!client_run(ctx, 200));
+
     TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-    TEST_1(ag->ag_out_via);
-    TEST_S(ag->ag_out_via->v_protocol, "SIP/2.0/UDP");
   }
 
   if (udp) {
-    /* Send a message from default leg to server leg 
+    /* Test 0.6
+     * Send a message from default leg to server leg 
      * using a prefilled Via header
      */
+    client_t ctx[1] = {{ ag, "Test 0.6", check_magic_branch }};
+
     sip_via_t via[1];
 
     sip_via_init(via);
@@ -1232,22 +1453,18 @@ int test_tports(agent_t *ag)
                         TAG_END());
 
     ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, 
-                              magic_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.6"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              SIPTAG_VIA(via),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_VIA(via),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
 
     nta_agent_set_params(ag->ag_agent, 
@@ -1262,6 +1479,7 @@ int test_tports(agent_t *ag)
     url_t url[1];
     sip_payload_t *pl;
     usize_t size = 16 * 1024;
+    client_t ctx[1] = {{ ag, "Test 0.7", check_via_with_sctp }};
 
     *url = *ag->ag_aliases->m_url;
     url->url_user = "alice";
@@ -1275,23 +1493,19 @@ int test_tports(agent_t *ag)
     TEST_1(pl = test_payload(ag->ag_home, size));
 
     ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.7"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                              TAG_END());
-   TEST_1(ag->ag_orq);
-   su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          TAG_END());
+    su_free(ag->ag_home, pl);
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
   }
 
@@ -1300,6 +1514,7 @@ int test_tports(agent_t *ag)
     url_t url[1];
     sip_payload_t *pl;
     usize_t size = 128 * 1024;
+    client_t ctx[1] = {{ ag, "Test 0.8" }};
 
     nta_agent_set_params(ag->ag_agent, 
                         NTATAG_MAXSIZE(65536),
@@ -1312,23 +1527,19 @@ int test_tports(agent_t *ag)
 
     ag->ag_expect_leg = ag->ag_server_leg;
     ag->ag_latest_leg = NULL;
-    ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.8"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                      TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_PAYLOAD(pl),
+                          TAG_END());
     su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 413);
-    TEST_P(ag->ag_orq, NULL);
+    TEST_1(!client_run(ctx, 413));
     TEST_P(ag->ag_latest_leg, NULL);
 
     nta_agent_set_params(ag->ag_agent, 
@@ -1339,6 +1550,7 @@ int test_tports(agent_t *ag)
   /* Test 0.9: Timeout */
   {
     url_t url[1];
+    client_t ctx[1] = {{ ag, "Test 0.9" }};
 
     printf("%s: starting MESSAGE timeout test, completing in 4 seconds\n",
           name);
@@ -1357,21 +1569,18 @@ int test_tports(agent_t *ag)
 
     ag->ag_expect_leg = ag->ag_server_leg;
     ag->ag_latest_leg = NULL;
-    ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.9"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              TAG_END());
-
-    TEST_1(ag->ag_orq);
-    nta_test_run(ag);
-    TEST(ag->ag_status, 408);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_bob),
+                          SIPTAG_TO(ag->ag_alice),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          TAG_END());
+
+    TEST_1(!client_run(ctx, 408));
     TEST_P(ag->ag_latest_leg, NULL);
 
     nta_agent_set_params(ag->ag_agent,
@@ -1419,7 +1628,8 @@ int leg_callback_save(agent_t *ag,
 
   ag->ag_latest_leg = leg;
   ag->ag_irq = irq;
-  ag->ag_status = 1000;
+
+  ag->ag_running = 0;
 
   return 0;
 }
@@ -1433,56 +1643,59 @@ int test_destroy_incoming(agent_t *ag)
 
   *url = *ag->ag_contact->m_url;
 
-  /* Test 3.1
-   * Check that when a incoming request is destroyed in callback, 
-   * a 500 response is sent
-   */
-  ag->ag_expect_leg = ag->ag_default_leg;
-  nta_leg_bind(ag->ag_default_leg, leg_callback_destroy, ag);
-
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_default_leg, 
-                             outgoing_callback, ag,
-                             ag->ag_obp,
-                             SIP_METHOD_MESSAGE,
-                             (url_string_t *)url,
-                             SIPTAG_SUBJECT_STR("Test 3.1"),
-                             SIPTAG_FROM(ag->ag_alice),
-                             SIPTAG_TO(ag->ag_bob),
-                             TAG_END());
-  TEST_1(ag->ag_orq);
-  
-  nta_test_run(ag);
-  TEST(ag->ag_status, 500);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  {
+    client_t ctx[1] = {{ ag, "Test 3.1" }};
 
-  /* Test 3.1
-   * Check that when a incoming request is destroyed, a 500 response is sent
-   */
-  nta_leg_bind(ag->ag_default_leg, leg_callback_save, ag);
-
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_default_leg, 
-                             outgoing_callback, ag,
-                             ag->ag_obp,
-                             SIP_METHOD_MESSAGE,
-                             (url_string_t *)url,
-                             SIPTAG_SUBJECT_STR("Test 3.1"),
-                             SIPTAG_FROM(ag->ag_alice),
-                             SIPTAG_TO(ag->ag_bob),
-                             TAG_END());
-  TEST_1(ag->ag_orq);
-
-  nta_test_run(ag);
-  TEST(ag->ag_status, 1000);
-  TEST_1(ag->ag_irq);
-  TEST_1(ag->ag_orq);
-  TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
-  nta_incoming_destroy(ag->ag_irq), ag->ag_irq = NULL;
-  nta_test_run(ag);
-  TEST(ag->ag_status, 500);
-  TEST_P(ag->ag_orq, NULL);
+    /* Test 3.1
+     * Check that when a incoming request is destroyed in callback, 
+     * a 500 response is sent
+     */
+    ag->ag_expect_leg = ag->ag_default_leg;
+    nta_leg_bind(ag->ag_default_leg, leg_callback_destroy, ag);
+    
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, 
+                          outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 500));
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 3.2
+     * Check that when an incoming request is destroyed, a 500 response is sent
+     */
+    client_t ctx[1] = {{ ag, "Test 3.2" }};
+
+    nta_leg_bind(ag->ag_default_leg, leg_callback_save, ag);
+    
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, 
+                          outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          TAG_END());
+    TEST_1(ctx->c_orq);
+    nta_test_run(ag);
+    TEST(ctx->c_status, 0);
+    TEST_1(ag->ag_irq);
+    TEST_1(ctx->c_orq);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+
+    nta_incoming_destroy(ag->ag_irq), ag->ag_irq = NULL;
+
+    TEST_1(!client_run(ctx, 500));
+  }
 
   END();
 }
@@ -1526,22 +1739,19 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
     /* Test 1.1
      * Send a message to sip:example.org
      */
+    client_t ctx[1] = {{ ag, "Test 1.1" }};
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.1"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-    
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -1549,22 +1759,20 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
     /* Test 1.2
      * Send a message to sip:srv.example.org
      */
+    client_t ctx[1] = {{ ag, "Test 1.2" }};
     url->url_host = "srv.example.org";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.2"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -1572,23 +1780,20 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
     /* Test 1.3
      * Send a message to sip:ipv.example.org
      */
+    client_t ctx[1] = {{ ag, "Test 1.3" }};
     url->url_host = "ipv.example.org";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.3"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -1596,23 +1801,20 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
     /* Test 1.4.1
      * Send a message to sip:down.example.org
      */
+    client_t ctx[1] = {{ ag, "Test 1.4.1" }};
     url->url_host = "down.example.org";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.4.1"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-   TEST_1(ag->ag_orq);
-
-   nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
 
   }
@@ -1621,23 +1823,20 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
     /* Test 1.4.2
      * Send a message to sip:na503.example.org
      */
+    client_t ctx[1] = {{ ag, "Test 1.4.2" }};
     url->url_host = "na503.example.org";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.4.2"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 503);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 503));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -1645,23 +1844,20 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
     /* Test 1.4.3
      * Send a message to sip:nona.example.org
      */
+    client_t ctx[1] = {{ ag, "Test 1.4.3" }};
     url->url_host = "nona.example.org";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.4.3"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -1671,23 +1867,20 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * After failing to find _sip._udp.nosrv.example.org,
      * second SRV with _sip._udp.srv.example.org succeeds
      */
+    client_t ctx[1] = {{ ag, "Test 1.4.4" }};
     url->url_host = "nosrv.example.org";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.4.4"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -1696,24 +1889,21 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * Send a message to sip:srv.example.org;transport=tcp
      * Test outgoing_make_srv_query()
      */
+    client_t ctx[1] = {{ ag, "Test 1.5.1: outgoing_make_srv_query()" }};
     url->url_host = "srv.example.org";
     url->url_params = "transport=tcp";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.5.1: outgoing_make_srv_query()"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
     url->url_params = NULL;
   }
@@ -1723,24 +1913,22 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * Send a message to sip:srv.example.org;transport=udp
      * Test outgoing_make_srv_query()
      */
+    client_t ctx[1] = {{ ag, "Test 1.5.2: outgoing_make_srv_query()" }};
+
     url->url_host = "srv.example.org";
     url->url_params = "transport=udp";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.5.2: outgoing_make_srv_query()"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
     url->url_params = NULL;
   }
@@ -1750,24 +1938,22 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * Send a message to sip:srv2.example.org;transport=udp
      * Test outgoing_query_srv_a()
      */
+    client_t ctx[1] = {{ ag, "Test 1.5: outgoing_query_srv_a()" }};
+
     url->url_host = "srv2.example.org";
     url->url_params = "transport=udp";
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.5: outgoing_query_srv_a()"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
     url->url_params = NULL;
   }
@@ -1777,24 +1963,22 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * Send a message to sip:srv.example.org:$port
      * Test outgoing_make_a_aaaa_query()
      */
+    client_t ctx[1] = {{ ag, "Test 1.6.1: outgoing_make_a_aaaa_query()" }};
+
     url->url_host = "srv.example.org";
     url->url_port = ag->ag_contact->m_url->url_port;
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.6.1: outgoing_make_a_aaaa_query()"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 503);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 503));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -1803,24 +1987,22 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * Send a message to sip:a.example.org:$port
      * Test outgoing_make_a_aaaa_query()
      */
+    client_t ctx[1] = {{ ag, "Test 1.6.2: outgoing_make_a_aaaa_query()" }};
+
     url->url_host = "a.example.org";
     url->url_port = ag->ag_contact->m_url->url_port;
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.6.2: outgoing_make_a_aaaa_query()"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
     url->url_port = NULL;
   }
@@ -1831,21 +2013,21 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * Send a message to sip:na.example.org
      * Test outgoing_query_all() with NAPTR "A" flag
      */
+    client_t ctx[1] = {{ ag, "Test 1.6c" }};
+
     url->url_host = "na.example.org";
     ag->ag_expect_leg = ag->ag_default_leg;
-    TEST_1(ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.6c"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END()));
-    nta_test_run(ag);
-    TEST(ag->ag_status, 503);
-    TEST(ag->ag_orq, NULL);
+    TEST_1(ctx->c_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                               ag->ag_obp,
+                               SIP_METHOD_MESSAGE,
+                               (url_string_t *)url,
+                               SIPTAG_SUBJECT_STR(ctx->c_name),
+                               SIPTAG_FROM(ag->ag_alice),
+                               SIPTAG_TO(ag->ag_bob),
+                               SIPTAG_CONTACT(ag->ag_m_alice),
+                               TAG_END()));
+    TEST_1(!client_run(ctx, 503));
     TEST(ag->ag_latest_leg, ag->ag_default_leg);
   }
 #endif
@@ -1855,382 +2037,26 @@ int test_resolv(agent_t *ag, char const *resolv_conf)
      * Send a message to sip:down2.example.org:$port
      * Test A record failover.
      */
+    client_t ctx[1] = {{ ag, "Test 1.7: outgoing_make_a_aaaa_query()" }};
+
     url->url_host = "down2.example.org";
     url->url_port = ag->ag_contact->m_url->url_port;
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.7: outgoing_make_a_aaaa_query()"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
     url->url_params = NULL;
   }
 
-#if 0
-  /* Test 0.1.1
-   * Send a message from Bob to Alice using SIGCOMP and TCP
-   */
-  if (tcp_comp) {
-    url_t url[1];
-    sip_payload_t *pl;
-    usize_t size = 1024;
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "alice";
-    if (url->url_params)
-      url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
-    else
-      url->url_params = "transport=tcp";
-
-    TEST_1(pl = test_payload(ag->ag_home, size));
-    ag->ag_expect_leg = ag->ag_server_leg;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                               ag->ag_obp,
-                               SIP_METHOD_MESSAGE,
-                               (url_string_t *)url,
-                               SIPTAG_SUBJECT_STR("Test 0.1.1"),
-                               SIPTAG_FROM(ag->ag_bob),
-                               SIPTAG_TO(ag->ag_alice),
-                               SIPTAG_CONTACT(ag->ag_m_bob),
-                               SIPTAG_PAYLOAD(pl),
-                               TAG_END()));
-    su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, ag->ag_server_leg);
-  }
-
-  /* Test 0.2
-   * Send a message from Bob to Alice
-   * This time specify a TCP URI, and include a large payload 
-   * of 512 kB
-   */
-  if (tcp) {
-    url_t url[1];
-    sip_payload_t *pl;
-    usize_t size = 512 * 1024;
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "alice";
-#if 0
-    if (url->url_params)
-      url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
-    else
-#endif
-      url->url_params = "transport=tcp";
-
-
-    TEST_1(pl = test_payload(ag->ag_home, size));
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.2"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                              TAG_END()));
-    su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, ag->ag_server_leg);
-  }
-
-  /* Test 0.3
-   * Send a message from Bob to Alice
-   * This time include a large payload of 512 kB, let NTA choose transport.
-   */
-  if (tcp) {
-    url_t url[1];
-    sip_payload_t *pl;
-    usize_t size = 512 * 1024;
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "alice";
-
-    TEST_1(pl = test_payload(ag->ag_home, size));
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.3"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                              TAG_END()));
-    su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, ag->ag_server_leg);
-  }
-
-  /* Test 0.4:
-   * Send a message from Bob to Alice
-   * This time include a payload of 2 kB, let NTA choose transport.
-   */
-  {
-    url_t url[1];
-    sip_payload_t *pl;
-    usize_t size = 2 * 1024;
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "alice";
-
-    TEST_1(pl = test_payload(ag->ag_home, size));
-
-    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.4"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                              TAG_END()));
-    su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, ag->ag_server_leg);
-    TEST_1(ag->ag_out_via);
-    TEST_1(strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/TCP") == 0 ||
-          strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/SCTP") == 0);
-  }
-
-  /* Test 0.5:
-   * Send a message from Bob to Alice
-   * This time include a payload of 2 kB, try to use UDP.
-   */
-  if (udp) {
-    url_t url[1];
-    sip_payload_t *pl;
-    usize_t size = 2 * 1024;
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "alice";
-
-    TEST_1(pl = test_payload(ag->ag_home, size));
-
-    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.5"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                              TPTAG_MTU(0xffffffff),
-                              TAG_END()));
-    su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, ag->ag_server_leg);
-    TEST_1(ag->ag_out_via);
-    TEST_S(ag->ag_out_via->v_protocol, "SIP/2.0/UDP");
-  }
-
-  if (udp) {
-    /* Send a message from default leg to server leg 
-     * using a prefilled Via header
-     */
-    sip_via_t via[1];
-
-    sip_via_init(via);
-
-    via->v_protocol = sip_transport_udp;
-    
-    via->v_host = ag->ag_contact->m_url->url_host;
-    via->v_port = ag->ag_contact->m_url->url_port;
-    
-    sip_via_add_param(ag->ag_home, via, "branch=MagicalBranch");
-
-    nta_agent_set_params(ag->ag_agent, 
-                        NTATAG_USER_VIA(1),
-                        TAG_END());
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    TEST_1(ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, 
-                              magic_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.6"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              SIPTAG_VIA(via),
-                              TAG_END()));
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, ag->ag_server_leg);
-
-    nta_agent_set_params(ag->ag_agent, 
-                        NTATAG_USER_VIA(0),
-                        TAG_END());
-  }
-
-  /* Test 0.7
-   * Send a message from Bob to Alice using SCTP 
-   */
-  if (sctp) {
-    url_t url[1];
-    sip_payload_t *pl;
-    usize_t size = 16 * 1024;
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "alice";
-#if 0
-    if (url->url_params)
-      url->url_params = su_sprintf(NULL, "%s;transport=sctp", url->url_params);
-    else
-#endif
-      url->url_params = "transport=sctp";
-
-    TEST_1(pl = test_payload(ag->ag_home, size));
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.7"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                              TAG_END()));
-    su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, ag->ag_server_leg);
-  }
-
-  /* Test 0.8: Send a too large message */
-  if (tcp) {
-    url_t url[1];
-    sip_payload_t *pl;
-    usize_t size = 128 * 1024;
-
-    nta_agent_set_params(ag->ag_agent, 
-                        NTATAG_MAXSIZE(65536),
-                        TAG_END());
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "alice";
-
-    TEST_1(pl = test_payload(ag->ag_home, size));
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_latest_leg = NULL;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.8"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              SIPTAG_PAYLOAD(pl),
-                              TAG_END()));
-    su_free(ag->ag_home, pl);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 413);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, NULL);
-
-    nta_agent_set_params(ag->ag_agent, 
-                        NTATAG_MAXSIZE(2 * 1024 * 1024),
-                        TAG_END());
-  }
-
-  /* Test 0.9: Timeout */
-  {
-    url_t url[1];
-
-    printf("%s: starting MESSAGE timeout test, test will complete in 4 seconds\n",
-          name);
-
-    nta_agent_set_params(ag->ag_agent, 
-                        NTATAG_TIMEOUT_408(1),
-                        NTATAG_SIP_T1(25), 
-                        NTATAG_SIP_T1X64(64 * 25), 
-                        TAG_END());
-
-    *url = *ag->ag_aliases->m_url;
-    url->url_user = "timeout";
-    url->url_port = ag->ag_sink_port;
-
-    ag->ag_expect_leg = ag->ag_server_leg;
-    ag->ag_latest_leg = NULL;
-    TEST_1(ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 0.9"),
-                              SIPTAG_FROM(ag->ag_bob),
-                              SIPTAG_TO(ag->ag_alice),
-                              SIPTAG_CONTACT(ag->ag_m_bob),
-                              TAG_END()));
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 408);
-    TEST(ag->ag_orq, NULL);
-    TEST(ag->ag_latest_leg, NULL);
-
-    nta_agent_set_params(ag->ag_agent,
-                        NTATAG_SIP_T1(500),
-                        NTATAG_SIP_T1X64(64 * 500),
-                        TAG_END());
-  }
-#endif  
-
   nta_agent_set_params(ag->ag_agent,
                       NTATAG_SIP_T1(500),
                       NTATAG_SIP_T1X64(64 * 500),
@@ -2266,26 +2092,23 @@ int test_routing(agent_t *ag)
      * our own port number.
      */
     url_t url2[1];
+    client_t ctx[1] = {{ ag, "Test 1.2" }};
 
     *url2 = *url;
     url2->url_port = "9";      /* discard service */
 
     ag->ag_expect_leg = ag->ag_default_leg;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              (url_string_t *)url,
-                              SIP_METHOD_MESSAGE,
-                              (url_string_t *)url2,
-                              SIPTAG_SUBJECT_STR("Test 1.2"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          (url_string_t *)url,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)url2,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
   }
 
@@ -2304,88 +2127,87 @@ int test_dialog(agent_t *ag)
    * Alice sends a message to Bob, then Bob back to the Alice, and again
    * Alice to Bob.
    */
+
   ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
-                                          leg_callback_200,
-                                          ag,
-                                          SIPTAG_FROM(ag->ag_alice),
-                                          SIPTAG_TO(ag->ag_bob),
-                                          TAG_END());
+                                    leg_callback_200,
+                                    ag,
+                                    SIPTAG_FROM(ag->ag_alice),
+                                    SIPTAG_TO(ag->ag_bob),
+                                    TAG_END());
   TEST_1(ag->ag_alice_leg);
   TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
-  nta_leg_bind(ag->ag_server_leg, new_leg_callback_200, ag);
 
-  /* Send message from Alice to Bob establishing the dialog */
-  ag->ag_expect_leg = ag->ag_server_leg;
-  ag->ag_tag_remote = ag->ag_alice_leg;
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ag,
-                            ag->ag_obp,
-                            SIP_METHOD_MESSAGE,
-                            (url_string_t *)ag->ag_m_bob->m_url,
-                            SIPTAG_SUBJECT_STR("Test 2.1"),
-                            SIPTAG_FROM(ag->ag_alice),
-                            SIPTAG_TO(ag->ag_bob),
-                            SIPTAG_CONTACT(ag->ag_m_alice),
-                            TAG_END());
-  TEST_1(ag->ag_orq);
+  {
+    client_t ctx[1] = {{ ag, "Test 2.1" }};
 
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-  TEST_1(ag->ag_bob_leg != NULL);
+    nta_leg_bind(ag->ag_server_leg, new_leg_callback_200, ag);
+
+    /* Send message from Alice to Bob establishing the dialog */
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ag->ag_tag_remote = ag->ag_alice_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)ag->ag_m_bob->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_bob_leg != NULL);
+  }
 
-  nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag);
-
-  /* Send message from Bob to Alice */
-  ag->ag_expect_leg = ag->ag_alice_leg;
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
-                      NULL,
-                      SIP_METHOD_MESSAGE,
-                      (url_string_t *)ag->ag_m_alice->m_url,
-                      SIPTAG_SUBJECT_STR("Test 2.2"),
-                      TAG_END());
-  TEST_1(ag->ag_orq);
-
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
-
-  /* Send again message from Alice to Bob */
-  ag->ag_expect_leg = ag->ag_bob_leg;
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ag,
-                      NULL,
-                      SIP_METHOD_MESSAGE,
-                      (url_string_t *)ag->ag_m_bob->m_url,
-                      SIPTAG_SUBJECT_STR("Test 2.3"),
-                      TAG_END());
-  TEST_1(ag->ag_orq);
-
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_bob_leg);
-
-  /* Send message from Bob to Alice
-   * This time, however, specify request URI 
-   */
   {
+    /* Send message from Bob to Alice */
+    client_t ctx[1] = {{ ag, "Test 2.2" }};
+
+    nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag);
+
+
     ag->ag_expect_leg = ag->ag_alice_leg;
-    ag->ag_orq = 
-          nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
-                        NULL,
-                        SIP_METHOD_MESSAGE,
-                        (url_string_t *)ag->ag_m_alice->m_url,
-                        SIPTAG_SUBJECT_STR("Test 2.4"),
-                        TAG_END());
-    TEST_1(ag->ag_orq);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)ag->ag_m_alice->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+    TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+  }
 
-    nta_test_run(ag);
-    TEST(ag->ag_status, 200);
-    TEST_P(ag->ag_orq, NULL);
+  {
+    /* Send again message from Alice to Bob */
+    client_t ctx[1] = {{ ag, "Test 2.3" }};
+    ag->ag_expect_leg = ag->ag_bob_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)ag->ag_m_bob->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+    TEST_P(ag->ag_latest_leg, ag->ag_bob_leg);
+  }
+  
+  {
+    /* Send message from Bob to Alice
+     * This time, however, specify request URI 
+     */
+    client_t ctx[1] = {{ ag, "Test 2.4" }};
+    ag->ag_expect_leg = ag->ag_alice_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_MESSAGE,
+                          (url_string_t *)ag->ag_m_alice->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
     TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
   }
 
@@ -2415,7 +2237,7 @@ int test_for_ack(agent_t *ag,
 
   TEST(method, sip_method_ack);
   
-  ag->ag_status = 200;
+  ag->ag_running = 0;
 
   END();
 }
@@ -2506,7 +2328,7 @@ int alice_leg_callback(agent_t *ag,
     leg_zap(ag, leg);
   }
   if (sip)
-  return 200;
+    return 200;
 
   END();
 }
@@ -2561,7 +2383,7 @@ int bob_leg_callback(agent_t *ag,
   if (sip->sip_request->rq_method != sip_method_invite) {
     return 200;
   } else {
-       nta_incoming_bind(irq, test_for_ack, ag); 
+    nta_incoming_bind(irq, test_for_ack, ag); 
 #if 1
     nta_incoming_treply(irq,
                        SIP_180_RINGING,
@@ -2584,129 +2406,191 @@ int bob_leg_callback(agent_t *ag,
   END();
 }
 
-int outgoing_invite_callback(agent_t *ag,
-                            nta_outgoing_t *orq,
-                            sip_t const *sip)
-{
-  BEGIN();
+struct invite_client_t {
+  client_t ic_client[1];
+  nta_outgoing_t *ic_orq;      /* Original INVITE transaction */
+  int ic_tag_status;           /* Status for current branch */
+  char *ic_tag;
+};
 
-  int status = sip->sip_status->st_status;
+static
+int invite_client_deinit(client_t *c)
+{
+  agent_t *ag = c->c_ag;
+  invite_client_t *ic = (invite_client_t *)c;
 
-  if (tstflags & tst_verbatim) {
-    printf("%s: %s: %s %03d %s\n", name, __func__, 
-          sip->sip_status->st_version, 
-          sip->sip_status->st_status, 
-          sip->sip_status->st_phrase);
-  }
+  if (ic->ic_orq) nta_outgoing_destroy(ic->ic_orq), ic->ic_orq = NULL;
+  if (ic->ic_tag) su_free(ag->ag_home, ic->ic_tag), ic->ic_tag = NULL;
 
-  {
-    msg_t *msg;
+  return 0;
+}
 
-    TEST_1(msg = nta_outgoing_getresponse(orq));
-    TEST_1(msg->m_refs == 2);
-    TEST_1(sip_object(msg) == sip);
-    if (ag->ag_probe_msg == NULL)
-      ag->ag_probe_msg = msg;
-    msg_destroy(msg);
-  }
+static 
+int check_prack_sending(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  agent_t *ag = ctx->c_ag;
+  int status = ctx->c_status;
 
-  if (status < 200) {
+  if (100 < status && status < 200) {
     if (sip->sip_require && sip_has_feature(sip->sip_require, "100rel")) {
+      nta_outgoing_t *prack = NULL;
+
       TEST_1(sip->sip_rseq);
-      orq = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL,
-                              NULL,
-                              sip, 
-                              TAG_END());
-      TEST_1(orq);
-      nta_outgoing_destroy(orq);
+      
+      prack = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL,
+                                NULL,
+                                sip, 
+                                TAG_END());
+      nta_outgoing_destroy(prack);
+      TEST_1(prack != NULL);
     }
-    return 0;
   }
+  return 0;
+}
 
-  if (status < 300) {
-    nta_outgoing_t *ack;
 
+static 
+int check_leg_tagging(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  agent_t *ag = ctx->c_ag;
+  int status = ctx->c_status;
+
+  if (200 <= status && status < 300) {
     TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
     
     TEST(nta_leg_client_route(ag->ag_call_leg, 
                              sip->sip_record_route,
                              sip->sip_contact), 0);
+  }
+
+  return 0;
+}
+
+
+static 
+int check_tu_ack(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  agent_t *ag = ctx->c_ag;
+  int status = ctx->c_status;
 
+  if (200 <= status && status < 300) {
+    nta_outgoing_t *ack;
     ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
                               NULL,
                               SIP_METHOD_ACK,
                               NULL,
                               SIPTAG_CSEQ(sip->sip_cseq),
                               TAG_END());
-    TEST_1(ack);
     nta_outgoing_destroy(ack);
+    TEST_1(ack);
   }
-  else {
-    ag->ag_status = status;
-  }
 
-  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+  return 0;
+}
+
 
-  nta_outgoing_destroy(orq);
-  ag->ag_orq = NULL;
-  ag->ag_call_leg = NULL;
-  END();
+static
+int check_final_error(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  agent_t *ag = ctx->c_ag;
+  int status = ctx->c_status;
+  
+  if (status >= 300)
+    ag->ag_call_leg = NULL;
+
+  return 0;
+}
+
+
+/** Cancel call after receiving 1XX response */
+static
+int cancel_invite(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
+{
+  int status = ctx->c_status;
+
+  if (100 < status && status < 200) {
+    nta_outgoing_cancel(orq);
+    ctx->c_status = 0;
+  }
+  else if (status >= 200) {
+    TEST_1(status == 487 || status == 504);
+  }
+
+  return 0;
 }
 
+static client_check_f * const checks_for_invite[] = {
+  client_check_to_tag,
+  check_leg_tagging,
+  check_tu_ack,
+  check_final_error,
+  NULL,
+};
+
+static client_check_f * const checks_for_reinvite[] = {
+  client_check_to_tag,
+  check_prack_sending,
+  check_leg_tagging,
+  check_tu_ack,
+  NULL,
+};
 
 int test_call(agent_t *ag)
 {
-  sip_content_type_t *c = ag->ag_content_type;
+  sip_content_type_t *ct = ag->ag_content_type;
   sip_payload_t      *sdp = ag->ag_payload;
   nta_leg_t *old_leg;
   sip_replaces_t *r1, *r2;
 
   BEGIN();
 
-  /*
-   * Test establishing a call
-   *
-   * Alice sends a INVITE to Bob, then Bob sends 200 Ok.
-   */
-  ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
-                                          alice_leg_callback,
-                                          ag,
-                                          SIPTAG_FROM(ag->ag_alice),
-                                          SIPTAG_TO(ag->ag_bob),
-                                          TAG_END());
-  TEST_1(ag->ag_alice_leg);
-  
-  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
-  nta_leg_bind(ag->ag_server_leg, bob_leg_callback, ag);
+  {
+    invite_client_t ic[1] = {{ 
+       {{ ag, "Call 1", NULL, checks_for_invite, invite_client_deinit }} }}; 
+    client_t *ctx = ic->ic_client;
+
+    /*
+     * Test establishing a call
+     *
+     * Alice sends a INVITE to Bob, then Bob sends 200 Ok.
+     */
+    ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+                                      alice_leg_callback,
+                                      ag,
+                                      SIPTAG_FROM(ag->ag_alice),
+                                      SIPTAG_TO(ag->ag_bob),
+                                      TAG_END());
+    TEST_1(ag->ag_alice_leg);
   
-  /* Send INVITE */
-  ag->ag_expect_leg = ag->ag_server_leg;
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
-                             outgoing_invite_callback, ag,
-                             ag->ag_obp,
-                             SIP_METHOD_INVITE,
-                             (url_string_t *)ag->ag_m_bob->m_url,
-                             SIPTAG_SUBJECT_STR("Call 1"),
-                             SIPTAG_CONTACT(ag->ag_m_alice),
-                             SIPTAG_CONTENT_TYPE(c),
-                             SIPTAG_ACCEPT_CONTACT_STR("*;audio"),
-                             SIPTAG_PAYLOAD(sdp),
-                             NTATAG_USE_TIMESTAMP(1),
-                             NTATAG_PASS_100(1),
-                             TAG_END());
-  TEST_1(ag->ag_orq);
+    TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+    nta_leg_bind(ag->ag_server_leg, bob_leg_callback, ag);
   
-  /* Try to CANCEL it immediately */
-  TEST_1(nta_outgoing_cancel(ag->ag_orq) == 0);
-  /* As Bob immediately answers INVITE with 200 Ok, 
-     cancel should be answered with 487. */
-
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-  TEST_1(ag->ag_bob_leg != NULL);
+    /* Send INVITE */
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+                          outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_INVITE,
+                          (url_string_t *)ag->ag_m_bob->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_ACCEPT_CONTACT_STR("*;audio"),
+                          SIPTAG_PAYLOAD(sdp),
+                          NTATAG_USE_TIMESTAMP(1),
+                          NTATAG_PASS_100(1),
+                          TAG_END());
+    TEST_1(ctx->c_orq);
+    /* Try to CANCEL it immediately */
+    TEST_1(nta_outgoing_cancel(ctx->c_orq) == 0);
+    /* As Bob immediately answers INVITE with 200 Ok, 
+       cancel should be answered with 481 and 200 Ok is teruned to INVITE. */
+    TEST_1(!client_run(ctx, 200));
+
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_bob_leg != NULL);
+  }
 
   TEST_1(r1 = nta_leg_make_replaces(ag->ag_alice_leg, ag->ag_home, 0));
   TEST_1(r2 = sip_replaces_format(ag->ag_home, "%s;from-tag=%s;to-tag=%s",
@@ -2715,55 +2599,59 @@ int test_call(agent_t *ag)
   TEST_P(ag->ag_alice_leg, nta_leg_by_replaces(ag->ag_agent, r2));
   TEST_P(ag->ag_bob_leg, nta_leg_by_replaces(ag->ag_agent, r1));
 
-  /* Re-INVITE from Bob to Alice.
-   *
-   * Alice first sends 183, waits for PRACK, then sends 184 and 185,
-   * waits for PRACKs, then sends 200, waits for ACK.
-   */
-  ag->ag_expect_leg = ag->ag_alice_leg;
-  ag->ag_orq = 
-       nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_bob_leg, 
-                            outgoing_invite_callback, ag,
-                            NULL,
-                            SIP_METHOD_INVITE,
-                            NULL,
-                            SIPTAG_SUBJECT_STR("Re-INVITE"),
-                            SIPTAG_CONTACT(ag->ag_m_bob),
-                            SIPTAG_SUPPORTED_STR("foo"),
-                            SIPTAG_CONTENT_TYPE(c),
-                            SIPTAG_PAYLOAD(sdp),
-                            TAG_END());
-  TEST_1(ag->ag_orq);
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+  {
+    invite_client_t ic[1] = {{ 
+       {{ ag, "Re-INVITE in Call 1", NULL, checks_for_reinvite, invite_client_deinit }} 
+      }}; 
+    client_t *ctx = ic->ic_client;
+
+    /* Re-INVITE from Bob to Alice.
+     *
+     * Alice first sends 183, waits for PRACK, then sends 184 and 185,
+     * waits for PRACKs, then sends 200, waits for ACK.
+     */
+    ag->ag_expect_leg = ag->ag_alice_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_bob_leg, 
+                          outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_INVITE,
+                          NULL,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_CONTACT(ag->ag_m_bob),
+                          SIPTAG_SUPPORTED_STR("foo"),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_PAYLOAD(sdp),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+    TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+  }
+
+  {
+    client_t ctx[1] = {{ ag, "Hangup" }};
 
-  nta_agent_set_params(ag->ag_agent, 
-                      NTATAG_DEBUG_DROP_PROB(0),
-                      TAG_END());
+    nta_agent_set_params(ag->ag_agent, 
+                        NTATAG_DEBUG_DROP_PROB(0),
+                        TAG_END());
 
-  /* Send BYE from Bob to Alice */
-  old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
-  ag->ag_orq = 
-       nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
-                            NULL,
-                            SIP_METHOD_BYE,
-                            NULL,
-                            SIPTAG_SUBJECT_STR("Hangup"),
-                            SIPTAG_FROM(ag->ag_alice),
-                            SIPTAG_TO(ag->ag_bob),
-                            SIPTAG_CONTACT(ag->ag_m_alice),
-                            SIPTAG_CONTENT_TYPE(c),
-                            SIPTAG_PAYLOAD(sdp),
-                            TAG_END());
-  TEST_1(ag->ag_orq);
-  
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, old_leg);
-  TEST_P(ag->ag_alice_leg, NULL);
+    /* Send BYE from Bob to Alice */
+    old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_BYE,
+                          NULL,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_PAYLOAD(sdp),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+    TEST_P(ag->ag_latest_leg, old_leg);
+    TEST_P(ag->ag_alice_leg, NULL);
+  }
 
   nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
   ag->ag_latest_leg = NULL;
@@ -2850,120 +2738,87 @@ int bob_leg_callback2(agent_t *ag,
 
   if (sip->sip_request->rq_method != sip_method_invite) {
     return 200;
-  } else {
-    nta_incoming_bind(irq, test_for_ack_or_timeout, ag); 
-    nta_incoming_treply(irq,
-                       SIP_183_SESSION_PROGRESS,
-                       SIPTAG_CONTENT_TYPE(ag->ag_content_type),
-                       SIPTAG_PAYLOAD(ag->ag_payload),
-                       SIPTAG_CONTACT(ag->ag_m_bob),
-                       TAG_END());
-    if (0)
+  } 
+
+  nta_incoming_bind(irq, test_for_ack_or_timeout, ag); 
+  nta_incoming_treply(irq,
+                     SIP_183_SESSION_PROGRESS,
+                     SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+                     SIPTAG_PAYLOAD(ag->ag_payload),
+                     SIPTAG_CONTACT(ag->ag_m_bob),
+                     TAG_END());
+  if (0)
     nta_incoming_treply(irq,
                        SIP_180_RINGING,
                        SIPTAG_CONTENT_TYPE(ag->ag_content_type),
                        SIPTAG_PAYLOAD(ag->ag_payload),
                        SIPTAG_CONTACT(ag->ag_m_bob),
                        TAG_END());
-    nta_incoming_treply(irq,
-                       SIP_200_OK,
-                       SIPTAG_CONTACT(ag->ag_m_bob),
-                       TAG_END());
-    ag->ag_irq = irq;
-  }
+  nta_incoming_treply(irq,
+                     SIP_200_OK,
+                     SIPTAG_CONTACT(ag->ag_m_bob),
+                     TAG_END());
+  ag->ag_irq = irq;
 
   END();
 }
 
+/** Fork the original INVITE. */
+static
+int check_orq_tagging(client_t *ctx,
+                     nta_outgoing_t *orq,
+                     sip_t const *sip)
+{   
+  agent_t *ag = ctx->c_ag;
+  int status = ctx->c_status;
+  invite_client_t *ic = (invite_client_t *)ctx;
 
-int invite_prack_callback(agent_t *ag,
-                         nta_outgoing_t *orq,
-                         sip_t const *sip)
-{
-  BEGIN();
-
-  int status = sip->sip_status->st_status;
-
-  if (tstflags & tst_verbatim) {
-    printf("%s: %s: %s %03d %s\n", name, __func__, 
-          sip->sip_status->st_version, 
-          sip->sip_status->st_status, 
-          sip->sip_status->st_phrase);
-  }
-
-  if (!ag->ag_call_tag && (status >= 200 || (status > 100 && sip->sip_rseq))) {
-    nta_outgoing_t *tagged;
+  if (100 < status &&  status < 200) {
+    TEST_1(sip->sip_rseq);
     TEST_1(sip->sip_to->a_tag);
-    ag->ag_tag_status = status;
-    ag->ag_call_tag = su_strdup(ag->ag_home, sip->sip_to->a_tag);
-    TEST_S(ag->ag_call_tag, sip->sip_to->a_tag);
-    TEST_S(nta_leg_rtag(ag->ag_call_leg, ag->ag_call_tag), ag->ag_call_tag);
-    TEST(nta_leg_client_route(ag->ag_call_leg, 
-                             sip->sip_record_route,
-                             sip->sip_contact), 0);
-    tagged = nta_outgoing_tagged(orq, 
-                                invite_prack_callback,
-                                ag,
-                                ag->ag_call_tag,
-                                sip->sip_rseq);
-    TEST_1(tagged);
-    nta_outgoing_destroy(orq);
-    if (ag->ag_orq == orq)
-      ag->ag_orq = tagged;
-    orq = tagged;
-  }
-
-  if (status > ag->ag_status)
-    ag->ag_status = status;
-
-  if (status > 100 && status < 200 && sip->sip_rseq) {
-    nta_outgoing_t *prack;
-    prack = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL,
-                              NULL,
-                              sip, 
-                              TAG_END());
-    TEST_1(prack);
-    nta_outgoing_destroy(prack);
-    return 0;
-  }
-
-  if (status < 200)
-    return 0;
-
-  if (status < 300) {
-    nta_outgoing_t *ack;
-    msg_t *msg;
-    sip_t *osip;
-
-    TEST_1(msg = nta_outgoing_getrequest(orq));
-    TEST_1(osip = sip_object(msg));
 
-    TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
+    TEST_1(orq == ctx->c_orq);
+  
+    TEST_1(ic); TEST_1(ic->ic_orq == NULL);
+    TEST_1(ic->ic_tag == NULL);
+  
+    ic->ic_orq = orq;
+    ic->ic_tag = su_strdup(ag->ag_home, sip->sip_to->a_tag); TEST_1(ic->ic_tag);
+    ic->ic_tag_status = status;
     
+    TEST_S(nta_leg_rtag(ag->ag_call_leg, ic->ic_tag), ic->ic_tag);
+  
     TEST(nta_leg_client_route(ag->ag_call_leg, 
                              sip->sip_record_route,
                              sip->sip_contact), 0);
+  
+    orq = nta_outgoing_tagged(orq, 
+                             outgoing_callback,
+                             ctx,
+                             ic->ic_tag,
+                             sip->sip_rseq);
+    TEST_1(orq);
+    nta_outgoing_destroy(ctx->c_orq);
+    ctx->c_orq = orq;
 
-    ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
-                              NULL,
-                              SIP_METHOD_ACK,
-                              NULL,
-                              SIPTAG_CSEQ(sip->sip_cseq),
-                              NTATAG_ACK_BRANCH(osip->sip_via->v_branch),
-                              TAG_END());
-    TEST_1(ack);
-    nta_outgoing_destroy(ack);
-    msg_destroy(msg);
+    TEST_1(ctx->c_checks && ctx->c_checks[0] == check_orq_tagging);
+
+    ctx->c_checks++;
   }
 
-  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+  return 0;
+}
+
+static client_check_f * const checks_for_100rel[] = {
+  check_orq_tagging,
+  client_check_to_tag,
+  check_prack_sending,
+  check_leg_tagging,
+  check_tu_ack,
+  NULL,
+};
 
-  nta_outgoing_destroy(orq);
-  ag->ag_orq = NULL;
-  ag->ag_call_leg = NULL;
 
-  END();
-}
 
 static int process_prack(nta_reliable_magic_t *arg,
                         nta_reliable_t *rel,
@@ -3049,67 +2904,6 @@ int bob_leg_callback3(agent_t *ag,
 }
 
 
-int invite_183_cancel_callback(agent_t *ag,
-                              nta_outgoing_t *orq,
-                              sip_t const *sip)
-{
-  BEGIN();
-
-  int status = sip->sip_status->st_status;
-
-  if (tstflags & tst_verbatim) {
-    printf("%s: %s: %s %03d %s\n", name, __func__, 
-          sip->sip_status->st_version, 
-          sip->sip_status->st_status, 
-          sip->sip_status->st_phrase);
-  }
-
-  if (status > 100 && status < 200) {
-    nta_outgoing_cancel(orq);
-    return 0;
-  }
-
-  if (status < 200)
-    return 0;
-
-  if (status < 300) {
-    nta_outgoing_t *ack;
-    msg_t *msg;
-    sip_t *osip;
-
-    TEST_1(msg = nta_outgoing_getrequest(orq));
-    TEST_1(osip = sip_object(msg));
-
-    TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
-    
-    TEST(nta_leg_client_route(ag->ag_call_leg, 
-                             sip->sip_record_route,
-                             sip->sip_contact), 0);
-
-    ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
-                              NULL,
-                              SIP_METHOD_ACK,
-                              NULL,
-                              SIPTAG_CSEQ(sip->sip_cseq),
-                              NTATAG_ACK_BRANCH(osip->sip_via->v_branch),
-                              TAG_END());
-    TEST_1(ack);
-    nta_outgoing_destroy(ack);
-    msg_destroy(msg);
-  }
-  else {
-    ag->ag_status = status;
-  }
-
-  TEST_1(sip->sip_to && sip->sip_to->a_tag);
-
-  nta_outgoing_destroy(orq);
-  ag->ag_orq = NULL;
-  ag->ag_call_leg = NULL;
-
-  END();
-}
-
 /*
  * Test establishing a call with an early dialog / 100 rel / timeout
  *
@@ -3120,133 +2914,134 @@ int invite_183_cancel_callback(agent_t *ag,
 
 int test_prack(agent_t *ag)
 {
-  sip_content_type_t *c = ag->ag_content_type;
+  BEGIN();
+
+  sip_content_type_t *ct = ag->ag_content_type;
   sip_payload_t      *sdp = ag->ag_payload;
   nta_leg_t *old_leg;
 
-  BEGIN();
-
   {
     /* Send a PRACK from default leg, NTA responds to it with error */
     url_t url[1];
+    client_t ctx[1] = {{ ag, "Test 1.1" }};
 
     *url = *ag->ag_aliases->m_url;
     url->url_user = "bob";
 
     ag->ag_expect_leg = ag->ag_server_leg;
     ag->ag_latest_leg = NULL;
-    ag->ag_orq = 
-         nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
-                              ag->ag_obp,
-                              SIP_METHOD_PRACK,
-                              (url_string_t *)url,
-                              SIPTAG_SUBJECT_STR("Test 1.1"),
-                              SIPTAG_FROM(ag->ag_alice),
-                              SIPTAG_TO(ag->ag_bob),
-                              SIPTAG_CONTACT(ag->ag_m_alice),
-                              SIPTAG_RACK_STR("1432432 42332432 INVITE"),
-                              TAG_END());
-    TEST_1(ag->ag_orq);
-    
-    nta_test_run(ag);
-    TEST(ag->ag_status, 481);
-    TEST_P(ag->ag_orq, NULL);
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_PRACK,
+                          (url_string_t *)url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_RACK_STR("1432432 42332432 INVITE"),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 481));
     TEST_P(ag->ag_latest_leg, NULL);
   }
 
   ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
-                                          alice_leg_callback,
-                                          ag,
-                                          SIPTAG_FROM(ag->ag_alice),
-                                          SIPTAG_TO(ag->ag_bob),
-                                          TAG_END());
+                                    alice_leg_callback,
+                                    ag,
+                                    SIPTAG_FROM(ag->ag_alice),
+                                    SIPTAG_TO(ag->ag_bob),
+                                    TAG_END());
   TEST_1(ag->ag_alice_leg);
   
   TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
 
   /* Send INVITE */
-  nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
-  ag->ag_expect_leg = ag->ag_server_leg;
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
-                             invite_prack_callback, ag,
-                             ag->ag_obp,
-                             SIP_METHOD_INVITE,
-                             (url_string_t *)ag->ag_m_bob->m_url,
-                             SIPTAG_SUBJECT_STR("Call 2"),
-                             SIPTAG_CONTACT(ag->ag_m_alice),
-                             SIPTAG_REQUIRE_STR("100rel"),
-                             SIPTAG_CONTENT_TYPE(c),
-                             SIPTAG_PAYLOAD(sdp),
-                             TAG_END());
-  TEST_1(ag->ag_orq);
-  
-  nta_test_run_until_acked(ag);
-  TEST(ag->ag_status, 200);
-  /*TEST(ag->ag_tag_status, 183);*/
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-  TEST_1(ag->ag_bob_leg != NULL);
+  {
+    invite_client_t ic[1] = {{ {{ ag, "Call 2",  NULL, checks_for_100rel, invite_client_deinit }} }};
+    client_t *ctx = ic->ic_client;
 
-  /* Send BYE from Bob to Alice */
-  old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
-  ag->ag_orq = 
-       nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
-                            NULL,
-                            SIP_METHOD_BYE,
-                            NULL,
-                            SIPTAG_SUBJECT_STR("Hangup"),
-                            SIPTAG_FROM(ag->ag_alice),
-                            SIPTAG_TO(ag->ag_bob),
-                            SIPTAG_CONTACT(ag->ag_m_alice),
-                            SIPTAG_CONTENT_TYPE(c),
-                            SIPTAG_PAYLOAD(sdp),
-                            TAG_END());
-  TEST_1(ag->ag_orq);
-  
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, old_leg);
-  TEST_P(ag->ag_alice_leg, NULL);
+    nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+                          outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_INVITE,
+                          (url_string_t *)ag->ag_m_bob->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_REQUIRE_STR("100rel"),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_PAYLOAD(sdp),
+                          TAG_END());
+
+    TEST_1(!client_run_until_acked(ctx, 200));
+
+    /*TEST(ic->ic_tag_status, 183); */
+
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_bob_leg != NULL);
+  }
+
+  {
+    client_t ctx[1] = {{ ag, "Hangup" }};
+
+    /* Send BYE from Bob to Alice */
+    old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_BYE,
+                          NULL,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_PAYLOAD(sdp),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+    TEST_P(ag->ag_latest_leg, old_leg);
+    TEST_P(ag->ag_alice_leg, NULL);
+  }
 
   nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
   ag->ag_latest_leg = NULL;
   ag->ag_call_leg = NULL;
-  if (ag->ag_call_tag)
-    su_free(ag->ag_home, (void *)ag->ag_call_tag), ag->ag_call_tag = NULL;
 
-  /* Test CANCELing a call after received PRACK */
+  /* Test CANCELing a call after receiving 100rel response */
   ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
-                                          alice_leg_callback,
-                                          ag,
-                                          SIPTAG_FROM(ag->ag_alice),
-                                          SIPTAG_TO(ag->ag_bob),
-                                          TAG_END());
+                                    alice_leg_callback,
+                                    ag,
+                                    SIPTAG_FROM(ag->ag_alice),
+                                    SIPTAG_TO(ag->ag_bob),
+                                    TAG_END());
   TEST_1(ag->ag_alice_leg);
   
   TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
 
-  /* Send INVITE */
-  nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag);
-  ag->ag_expect_leg = ag->ag_server_leg;
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
-                             invite_183_cancel_callback, ag,
-                             ag->ag_obp,
-                             SIP_METHOD_INVITE,
-                             (url_string_t *)ag->ag_m_bob->m_url,
-                             SIPTAG_SUBJECT_STR("Call 2b"),
-                             SIPTAG_CONTACT(ag->ag_m_alice),
-                             SIPTAG_REQUIRE_STR("100rel"),
-                             SIPTAG_CONTENT_TYPE(c),
-                             SIPTAG_PAYLOAD(sdp),
-                             TAG_END());
-  TEST_1(ag->ag_orq);
-  
-  nta_test_run(ag);
-  TEST_1(ag->ag_status == 487 || ag->ag_status == 504);
-  TEST_P(ag->ag_orq, NULL);
+  {
+    invite_client_t ic[1] = {{ {{ ag, "Call 2b",  cancel_invite, checks_for_invite, invite_client_deinit }} }};
+    client_t *ctx = ic->ic_client;
+
+    /* Send INVITE */
+    nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag);
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+                          outgoing_callback, ctx,
+                          ag->ag_obp,
+                          SIP_METHOD_INVITE,
+                          (url_string_t *)ag->ag_m_bob->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_REQUIRE_STR("100rel"),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_PAYLOAD(sdp),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 0));
+  }
+
   TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
   TEST_1(ag->ag_bob_leg != NULL);
 
@@ -3255,109 +3050,122 @@ int test_prack(agent_t *ag)
   ag->ag_call_leg = NULL;
 
   if (EXPENSIVE_CHECKS) {
-  printf("%s: starting 100rel timeout test, test will complete in 4 seconds\n",
-        name);
+    printf("%s: starting 100rel timeout test, test will complete in 4 seconds\n",
+          name);
   
-  TEST(nta_agent_set_params(ag->ag_agent,
-                           NTATAG_SIP_T1(25),
-                           NTATAG_SIP_T1X64(64 * 25),
-                           TAG_END()), 2);
-
-  ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
-                                          alice_leg_callback,
-                                          ag,
-                                          SIPTAG_FROM(ag->ag_alice),
-                                          SIPTAG_TO(ag->ag_bob),
-                                          TAG_END());
-  TEST_1(ag->ag_alice_leg);
+    TEST(nta_agent_set_params(ag->ag_agent,
+                             NTATAG_SIP_T1(25),
+                             NTATAG_SIP_T1X64(64 * 25),
+                             TAG_END()), 2);
+
+    ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+                                      alice_leg_callback,
+                                      ag,
+                                      SIPTAG_FROM(ag->ag_alice),
+                                      SIPTAG_TO(ag->ag_bob),
+                                      TAG_END());
+    TEST_1(ag->ag_alice_leg);
   
-  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
-
-  /* Send INVITE, 
-   * send precious provisional response
-   * do not send PRACK, 
-   * timeout (after 64 * t1 ~ 3.2 seconds),
-   */
-  nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
-  ag->ag_expect_leg = ag->ag_server_leg;
-  ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
-                             outgoing_callback, ag,
-                             ag->ag_obp,
-                             SIP_METHOD_INVITE,
-                             (url_string_t *)ag->ag_m_bob->m_url,
-                             SIPTAG_SUBJECT_STR("Call 3"),
-                             SIPTAG_CONTACT(ag->ag_m_alice),
-                             SIPTAG_REQUIRE_STR("100rel"),
-                             SIPTAG_CONTENT_TYPE(c),
-                             SIPTAG_PAYLOAD(sdp),
-                             TAG_END());
-  TEST_1(ag->ag_orq);
+    TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+    {
+      invite_client_t ic[1] = {{ {{ ag, "Call 3",  NULL,  checks_for_invite, invite_client_deinit }} }};
+      client_t *ctx = ic->ic_client;
+
+      /* Send INVITE, 
+       * send precious provisional response
+       * do not send PRACK, 
+       * timeout (after 64 * t1 ~ 3.2 seconds),
+       */
+      nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+      ag->ag_expect_leg = ag->ag_server_leg;
+      ctx->c_orq = 
+       nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+                            outgoing_callback, ctx,
+                            ag->ag_obp,
+                            SIP_METHOD_INVITE,
+                            (url_string_t *)ag->ag_m_bob->m_url,
+                            SIPTAG_SUBJECT_STR(ctx->c_name),
+                            SIPTAG_CONTACT(ag->ag_m_alice),
+                            SIPTAG_REQUIRE_STR("100rel"),
+                            SIPTAG_CONTENT_TYPE(ct),
+                            SIPTAG_PAYLOAD(sdp),
+                            TAG_END());
+      TEST_1(ctx->c_orq);
   
-  nta_test_run(ag);
-  TEST(ag->ag_status, 503);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-  TEST_1(ag->ag_bob_leg == NULL);
+      nta_test_run(ag);
+      TEST(ctx->c_status, 503);
+      TEST_P(ctx->c_orq, NULL);
+      TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+      TEST_1(ag->ag_bob_leg == NULL);
+    }
 
-  TEST(nta_agent_set_params(ag->ag_agent, 
-                           NTATAG_SIP_T1(500), 
-                           NTATAG_SIP_T1X64(64 * 500), 
-                           TAG_END()), 2);
+    TEST(nta_agent_set_params(ag->ag_agent, 
+                             NTATAG_SIP_T1(500), 
+                             NTATAG_SIP_T1X64(64 * 500), 
+                             TAG_END()), 2);
   }
 
   if (EXPENSIVE_CHECKS || 1) {
-  printf("%s: starting timer C, test will complete in 1 seconds\n",
-        name);
+    /*
+     * client sends INVITE, 
+     * server sends provisional response, 
+     * client PRACKs it,
+     * client timeouts after timer C
+     */
+
+    invite_client_t ic[1] = {{ 
+       {{ ag, "Call 4",  NULL, checks_for_100rel, invite_client_deinit }}
+      }};
+    client_t *ctx = ic->ic_client;
+
+    printf("%s: starting timer C, test will complete in 1 seconds\n",
+          name);
   
-  TEST(nta_agent_set_params(ag->ag_agent,
-                           NTATAG_TIMER_C(1000),
-                           TAG_END()), 1);
-
-  TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
-                                           alice_leg_callback,
-                                           ag,
-                                           SIPTAG_FROM(ag->ag_alice),
-                                           SIPTAG_TO(ag->ag_bob),
-                                           TAG_END()));
-  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+    TEST(nta_agent_set_params(ag->ag_agent,
+                             NTATAG_TIMER_C(1000),
+                             TAG_END()), 1);
 
-  /* Send INVITE, 
-   * send precious provisional response
-   * timeout after timer C
-   */
-  nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag);
-  ag->ag_expect_leg = ag->ag_server_leg;
-  TEST_1(ag->ag_orq = 
-        nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
-                             invite_prack_callback, ag,
-                             ag->ag_obp,
-                             SIP_METHOD_INVITE,
-                             (url_string_t *)ag->ag_m_bob->m_url,
-                             SIPTAG_SUBJECT_STR("Call 4"),
-                             SIPTAG_CONTACT(ag->ag_m_alice),
-                             SIPTAG_REQUIRE_STR("100rel"),
-                             SIPTAG_CONTENT_TYPE(c),
-                             SIPTAG_PAYLOAD(sdp),
-                             TAG_END()));
-  nta_test_run_until_canceled(ag);
-  TEST(ag->ag_status, 408);
-  TEST_1(ag->ag_canceled != 0); 
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-  TEST_1(ag->ag_bob_leg);
-  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+    TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+                                             alice_leg_callback,
+                                             ag,
+                                             SIPTAG_FROM(ag->ag_alice),
+                                             SIPTAG_TO(ag->ag_bob),
+                                             TAG_END()));
+    TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+    nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag);
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ctx->c_orq = 
+          nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+                               outgoing_callback, ic->ic_client,
+                               ag->ag_obp,
+                               SIP_METHOD_INVITE,
+                               (url_string_t *)ag->ag_m_bob->m_url,
+                               SIPTAG_SUBJECT_STR(ctx->c_name),
+                               SIPTAG_CONTACT(ag->ag_m_alice),
+                               SIPTAG_REQUIRE_STR("100rel"),
+                               SIPTAG_CONTENT_TYPE(ct),
+                               SIPTAG_PAYLOAD(sdp),
+                               TAG_END()));
 
-  TEST(nta_agent_set_params(ag->ag_agent, 
-                           NTATAG_TIMER_C(185 * 1000), 
-                           TAG_END()), 1);
+    /* Run until 1) server gets CANCEL and 2) client gets 408 */
+    TEST_1(!client_run_until_canceled(ctx, 408));
 
-  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
-  ag->ag_latest_leg = NULL;
-  ag->ag_call_leg = NULL;
-  if (ag->ag_call_tag)
-    su_free(ag->ag_home, (void *)ag->ag_call_tag), ag->ag_call_tag = NULL;
+    TEST_1(ag->ag_canceled != 0); 
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_bob_leg);
+    nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+
+    TEST(nta_agent_set_params(ag->ag_agent,
+                             NTATAG_TIMER_C(185 * 1000), 
+                             TAG_END()), 1);
+
+    nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+    ag->ag_latest_leg = NULL;
+    ag->ag_call_leg = NULL;
   }
+
   END();
 }
 
@@ -3430,7 +3238,7 @@ int alice_leg_callback2(agent_t *ag,
   }
 
   if(sip)
-       return 200;
+    return 200;
 
   END();
 }
@@ -3444,76 +3252,81 @@ int alice_leg_callback2(agent_t *ag,
  */
 int test_fix_467(agent_t *ag)
 {
-  sip_content_type_t *c = ag->ag_content_type;
+  sip_content_type_t *ct = ag->ag_content_type;
   sip_payload_t      *sdp = ag->ag_payload;
   nta_leg_t *old_leg;
 
   BEGIN();
 
   ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
-                                           alice_leg_callback2,
-                                           ag,
-                                           SIPTAG_FROM(ag->ag_alice),
-                                           SIPTAG_TO(ag->ag_bob),
-                                           TAG_END());
+                                    alice_leg_callback2,
+                                    ag,
+                                    SIPTAG_FROM(ag->ag_alice),
+                                    SIPTAG_TO(ag->ag_bob),
+                                    TAG_END());
   TEST_1(ag->ag_alice_leg);
   
   TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
   ag->ag_bob_leg = NULL;
-  ag->ag_call_tag = NULL;
 
-  /* Send INVITE */
-  nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
-  ag->ag_expect_leg = ag->ag_server_leg;
-  ag->ag_orq = 
-       nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
-                            invite_prack_callback, ag,
-                            ag->ag_obp,
-                            SIP_METHOD_INVITE,
-                            (url_string_t *)ag->ag_m_bob->m_url,
-                            SIPTAG_SUBJECT_STR("Call 5"),
-                            SIPTAG_CONTACT(ag->ag_m_alice),
-                            SIPTAG_REQUIRE_STR("100rel"),
-                            SIPTAG_CONTENT_TYPE(c),
-                            SIPTAG_PAYLOAD(sdp),
-                            TAG_END());
-  TEST_1(ag->ag_orq);
-  
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  /*TEST(ag->ag_tag_status, 183);*/
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
-  TEST_1(ag->ag_bob_leg != NULL);
+  {
+    invite_client_t ic[1] = {{
+       {{ ag, "Call 5",  NULL, checks_for_100rel, invite_client_deinit }}
+      }};
+    client_t *ctx = ic->ic_client;
+
+    /* Send INVITE */
+    nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+                          outgoing_callback, ic->ic_client,
+                          ag->ag_obp,
+                          SIP_METHOD_INVITE,
+                          (url_string_t *)ag->ag_m_bob->m_url,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_REQUIRE_STR("100rel"),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_PAYLOAD(sdp),
+                          TAG_END());
+
+    TEST_1(!client_run(ctx, 200));
+
+    /*TEST(ag->ag_tag_status, 183);*/
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_bob_leg != NULL);
+  }
 
-  /* Send BYE from Bob to Alice */
   old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
-  ag->ag_orq = 
-       nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
-                            NULL,
-                            SIP_METHOD_BYE,
-                            NULL,
-                            SIPTAG_SUBJECT_STR("Hangup"),
-                            SIPTAG_FROM(ag->ag_alice),
-                            SIPTAG_TO(ag->ag_bob),
-                            SIPTAG_CONTACT(ag->ag_m_alice),
-                            SIPTAG_CONTENT_TYPE(c),
-                            SIPTAG_PAYLOAD(sdp),
-                            TAG_END());
-  TEST_1(ag->ag_orq);
-  
-  nta_test_run(ag);
-  TEST(ag->ag_status, 200);
-  TEST_P(ag->ag_orq, NULL);
-  TEST_P(ag->ag_latest_leg, old_leg);
-  TEST_P(ag->ag_alice_leg, NULL);
+
+  {
+    client_t ctx[1] = {{ ag, "Hangup" }};
+
+    /* Send BYE from Bob to Alice */
+    ctx->c_orq = 
+      nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx,
+                          NULL,
+                          SIP_METHOD_BYE,
+                          NULL,
+                          SIPTAG_SUBJECT_STR(ctx->c_name),
+                          SIPTAG_FROM(ag->ag_alice),
+                          SIPTAG_TO(ag->ag_bob),
+                          SIPTAG_CONTACT(ag->ag_m_alice),
+                          SIPTAG_CONTENT_TYPE(ct),
+                          SIPTAG_PAYLOAD(sdp),
+                          TAG_END());
+    TEST_1(!client_run(ctx, 200));
+    TEST_P(ag->ag_latest_leg, old_leg);
+    TEST_P(ag->ag_alice_leg, NULL);
+  }
 
   END();
-/*
-  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
-  ag->ag_latest_leg = NULL;
-  ag->ag_call_leg = NULL;
-*/
+  /*
+    nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+    ag->ag_latest_leg = NULL;
+    ag->ag_call_leg = NULL;
+  */
 }
 
 #if HAVE_ALARM
@@ -3551,6 +3364,29 @@ void usage(int exitcode)
   exit(exitcode);
 }
 
+#if HAVE_OPEN_C
+int posix_main(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+  int retval;
+
+  tstflags |= tst_verbatim;
+
+  su_log_set_level(su_log_default, 9);
+  su_log_set_level(nta_log, 9);
+  su_log_set_level(tport_log, 9);
+
+  retval = posix_main(argc, argv);
+
+  sleep(7);
+
+  return retval;
+}
+
+#define main posix_main
+#endif
+
 int main(int argc, char *argv[])
 {
   int retval = 0, quit_on_single_failure = 0;
@@ -3633,16 +3469,6 @@ int main(int argc, char *argv[])
   }
 #endif
 
-#if HAVE_OPEN_C
-  tstflags |= tst_verbatim;
-  su_log_soft_set_level(su_log_default, 9);
-  su_log_soft_set_level(nta_log, 9);
-  su_log_soft_set_level(tport_log, 9);
-  setenv("SU_DEBUG", "9", 1);
-  setenv("NUA_DEBUG", "9", 1);
-  setenv("NTA_DEBUG", "9", 1);
-  setenv("TPORT_DEBUG", "9", 1);
-#endif
   su_init();
 
   if (!(TSTFLAGS & tst_verbatim)) {
@@ -3650,17 +3476,10 @@ int main(int argc, char *argv[])
     su_log_soft_set_level(tport_log, 0);
   }
 
-#if HAVE_OPEN_C
 #define SINGLE_FAILURE_CHECK()                                         \
-         do { fflush(stdout);                                                  \
-           if (retval && quit_on_single_failure) { su_deinit(); sleep(7); return retval; } \
-         } while(0)
-#else
-  #define SINGLE_FAILURE_CHECK()                                               \
-         do { fflush(stdout);                                                  \
-           if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
-         } while(0)
-#endif
+  do { fflush(stdout);                                                 \
+    if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
+  } while(0)
   
   retval |= test_init(ag, argv[i]); SINGLE_FAILURE_CHECK();
   if (retval == 0) {
@@ -3681,9 +3500,5 @@ int main(int argc, char *argv[])
 
   su_deinit();
 
-#if HAVE_OPEN_C
-  sleep(7);
-#endif  
-  
   return retval;
 }
index aa0352cf805b4e409f8d3c79b434279f4eb58878..aec84dc18b844ca569bba807517bf06a42bac9b0 100644 (file)
@@ -8,26 +8,10 @@
 # ----------------------------------------------------------------------
 # Header paths
 
-INCLUDES =             -I$(srcdir)/../bnf -I../bnf \
-                       -I$(srcdir)/../ipt -I../ipt \
-                       -I$(srcdir)/../iptsec -I../iptsec \
-                       -I$(srcdir)/../http -I../http \
-                       -I$(srcdir)/../msg -I../msg \
-                       -I$(srcdir)/../nea -I../nea \
-                       -I$(srcdir)/../nta -I../nta \
-                       -I$(srcdir)/../nth -I../nth \
-                       -I$(srcdir)/../sdp -I../sdp \
-                       -I$(srcdir)/../sip -I../sip \
-                       -I$(srcdir)/../soa -I../soa \
-                       -I$(srcdir)/../tport -I../tport \
-                       -I$(srcdir)/../stun -I../stun \
-                       -I$(srcdir)/../url -I../url \
-                       -I$(srcdir)/../su -I../su
-
 # ----------------------------------------------------------------------
 # Build targets
 
-noinst_LTLIBRARIES =   libnua.la
+noinst_LTLIBRARIES =   libnua.la libtestnua.la libtestproxy.la libtestnat.la
 
 check_PROGRAMS =       test_nua
 
@@ -57,7 +41,26 @@ libnua_la_SOURCES =  nua.c nua_stack.h nua_common.c nua_stack.c \
 
 COVERAGE_INPUT =       $(libnua_la_SOURCES) $(include_sofia_HEADERS)
 
-LDADD =                libnua.la \
+test_nua_LDFLAGS =     -static
+
+libtestnua_la_SOURCES = test_nua.h test_ops.c \
+                       test_init.c \
+                       test_nua_api.c test_nua_params.c \
+                       test_register.c test_basic_call.c \
+                       test_offer_answer.c \
+                       test_call_reject.c test_cancel_bye.c \
+                       test_call_hold.c test_session_timer.c \
+                       test_refer.c test_100rel.c \
+                       test_simple.c test_sip_events.c \
+                       test_extension.c
+
+libtestproxy_la_SOURCES = test_proxy.h test_proxy.c
+
+libtestnat_la_SOURCES = test_nat.h test_nat.c test_nat_tags.c
+
+test_nua_SOURCES =     test_nua.c 
+
+test_nua_LDADD =       libnua.la libtestnua.la libtestproxy.la libtestnat.la \
                        ../iptsec/libiptsec.la \
                        ../ipt/libipt.la \
                        ../nea/libnea.la \
@@ -74,21 +77,6 @@ LDADD =              libnua.la \
                        ../bnf/libbnf.la \
                        ../su/libsu.la
 
-test_nua_LDFLAGS =     -static
-
-test_nua_SOURCES =     test_nua.c test_nua.h test_ops.c \
-                       test_init.c \
-                       test_nua_api.c test_nua_params.c \
-                       test_register.c test_basic_call.c \
-                       test_offer_answer.c \
-                       test_call_reject.c test_cancel_bye.c \
-                       test_call_hold.c test_session_timer.c \
-                       test_refer.c test_100rel.c \
-                       test_simple.c test_sip_events.c \
-                       test_extension.c \
-                       test_proxy.h test_proxy.c \
-                       test_nat.h test_nat.c test_nat_tags.c
-
 # ----------------------------------------------------------------------
 # Install and distribution rules
 
@@ -99,4 +87,6 @@ EXTRA_DIST =          nua.docs $(BUILT_SOURCES)
 
 include $(top_srcdir)/rules/sofia.am
 
+INCLUDES = ${INTERNAL_INCLUDES}
+
 TAG_DLL_FLAGS =                LIST=nua_tag_list
index b625e258ef58d8cbbf75eb1920b2ea09d69f744f..7e3787b134d35e3680e5e53946e1f7176db84dde 100644 (file)
@@ -43,8 +43,6 @@
 #include <sofia-sip/su_debug.h>
 
 #define SU_ROOT_MAGIC_T   struct nua_s
-#define SU_MSG_ARG_T      struct event_s
-#define NUA_SAVED_EVENT_T su_msg_t *
 
 #include <sofia-sip/sip_status.h>
 #include <sofia-sip/sip_header.h>
@@ -192,7 +190,7 @@ void nua_shutdown(nua_t *nua)
 
   if (nua)
     nua->nua_shutdown_started = 1;
-  nua_signal(nua, NULL, NULL, 1, nua_r_shutdown, 0, NULL, TAG_END());
+  nua_signal(nua, NULL, NULL, nua_r_shutdown, 0, NULL, TAG_END());
 }
 
 /** Destroy the @nua stack.
@@ -227,6 +225,8 @@ void nua_destroy(nua_t *nua)
       return;
     }
 
+    nua->nua_callback = NULL;
+
     su_task_deinit(nua->nua_server);
     su_task_deinit(nua->nua_client);
 
@@ -574,7 +574,7 @@ void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
 
   enter;
 
-  nua_signal(nua, NULL, NULL, 0, nua_r_set_params, 0, NULL, ta_tags(ta));
+  nua_signal(nua, NULL, NULL, nua_r_set_params, 0, NULL, ta_tags(ta));
 
   ta_end(ta);
 }
@@ -587,7 +587,7 @@ void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
 
   enter;
 
-  nua_signal(nua, NULL, NULL, 0, nua_r_get_params, 0, NULL, ta_tags(ta));
+  nua_signal(nua, NULL, NULL, nua_r_get_params, 0, NULL, ta_tags(ta));
 
   ta_end(ta);
 }
@@ -597,7 +597,7 @@ void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
   if (NH_IS_VALID((nh))) { \
     ta_list ta; \
     ta_start(ta, tag, value); \
-    nua_signal((nh)->nh_nua, nh, NULL, 0, event, 0, NULL, ta_tags(ta));        \
+    nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta));   \
     ta_end(ta); \
   } \
   else { \
@@ -881,7 +881,7 @@ void nua_respond(nua_handle_t *nh,
   if (NH_IS_VALID(nh)) {
     ta_list ta;
     ta_start(ta, tag, value);
-    nua_signal(nh->nh_nua, nh, NULL, 0, nua_r_respond,
+    nua_signal(nh->nh_nua, nh, NULL, nua_r_respond,
               status, phrase, ta_tags(ta));
     ta_end(ta);
   }
@@ -922,197 +922,7 @@ void nua_handle_destroy(nua_handle_t *nh)
 
   if (NH_IS_VALID(nh) && !NH_IS_DEFAULT(nh)) {
     nh->nh_valid = NULL;       /* Events are no more delivered to appl. */
-    nua_signal(nh->nh_nua, nh, NULL, 1, nua_r_destroy, 0, NULL, TAG_END());
-  }
-}
-
-/*# Send a request to the protocol thread */
-void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
-               nua_event_t event,
-               int status, char const *phrase,
-               tag_type_t tag, tag_value_t value, ...)
-{
-  su_msg_r sumsg = SU_MSG_R_INIT;
-  size_t len, xtra, e_len, l_len = 0, l_xtra = 0;
-  ta_list ta;
-
-  if (nua == NULL)
-    return;
-
-  ta_start(ta, tag, value);
-
-  e_len = offsetof(event_t, e_tags);
-  len = tl_len(ta_args(ta));
-  xtra = tl_xtra(ta_args(ta), len);
-
-  if (su_msg_create(sumsg, nua->nua_server, su_task_null,
-                   nua_stack_signal,
-                   e_len + len + l_len + xtra + l_xtra) == 0) {
-    event_t *e = su_msg_data(sumsg);
-    tagi_t *t = e->e_tags;
-    void *b = (char *)t + len + l_len;
-
-    tagi_t *tend = (tagi_t *)b;
-    char *bend = (char *)b + xtra + l_xtra;
-
-    t = tl_dup(t, ta_args(ta), &b);
-
-    assert(tend == t); (void)tend; assert(b == bend); (void)bend;
-
-    e->e_always = always;
-    e->e_event = event;
-    e->e_nh = event == nua_r_destroy ? nh : nua_handle_ref(nh);
-    e->e_status = status;
-    e->e_phrase = phrase;
-
-    SU_DEBUG_7(("nua(%p): signal %s\n", (void *)nh,
-               nua_event_name(event) + 4));
-
-    if (su_msg_send(sumsg) != 0 && event != nua_r_destroy)
-      nua_handle_unref(nh);
-  }
-  else {
-    /* XXX  - we should return error code to application but we just abort() */
-    assert(ENOMEM == 0);
-  }
-
-  ta_end(ta);
-}
-
-/*# Receive event from protocol machine and hand it over to application */
-void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
-{
-  nua_t *nua;
-  nua_handle_t *nh = e->e_nh;
-
-  enter;
-
-  if (nh) {
-    if (!nh->nh_ref_by_user && nh->nh_valid) {
-      nh->nh_ref_by_user = 1;
-      nua_handle_ref(nh);
-    }
-  }
-
-  if (!nh || !nh->nh_valid) {  /* Handle has been destroyed */
-    if (nua_log->log_level >= 7) {
-      char const *name = nua_event_name(e->e_event) + 4;
-      SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name));
-    }
-    if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
-#if HAVE_NUA_HANDLE_DEBUG
-      SU_DEBUG_0(("nua(%p): freed by application\n", (void *)nh));
-#else
-      SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
-#endif
-    }
-    if (e->e_msg)
-      msg_destroy(e->e_msg), e->e_msg = NULL;
-    return;
-  }
-
-  nua = nh->nh_nua; assert(nua);
-
-  if (e->e_event == nua_r_shutdown && e->e_status >= 200)
-    nua->nua_shutdown_final = 1;
-
-  if (!nua->nua_callback)
-    return;
-
-  if (NH_IS_DEFAULT(nh))
-    nh = NULL;
-
-  su_msg_save(nua->nua_current, sumsg);
-
-  e->e_nh = NULL;
-
-  nua->nua_callback(e->e_event, e->e_status, e->e_phrase,
-                   nua, nua->nua_magic,
-                   nh, nh ? nh->nh_magic : NULL,
-                   e->e_msg ? sip_object(e->e_msg) : NULL,
-                   e->e_tags);
-
-  if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
-#if HAVE_NUA_HANDLE_DEBUG
-    SU_DEBUG_0(("nua(%p): freed by application\n", (void *)nh));
-#else
-    SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
-#endif
-  }
-
-  if (!su_msg_is_non_null(nua->nua_current))
-    return;
-
-  if (e->e_msg)
-    msg_destroy(e->e_msg), e->e_msg = NULL;
-
-  su_msg_destroy(nua->nua_current);
-}
-
-/** Get current request message. @NEW_1_12_4.
- *
- * @note A response message is returned when processing response message.
- *
- * @sa #nua_event_e, nua_respond(), NUTAG_WITH_CURRENT()
- */
-msg_t *nua_current_request(nua_t const *nua)
-{
-  return nua && nua->nua_current ? su_msg_data(nua->nua_current)->e_msg : NULL;
-}
-
-/** Get request message from saved nua event. @NEW_1_12_4. 
- *
- * @sa nua_save_event(), nua_respond(), NUTAG_WITH_SAVED(), 
- */
-msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
-{
-  return saved && saved[0] ? su_msg_data(saved)->e_msg : NULL;
-}
-
-/** Save nua event and its arguments.
- *
- * @sa #nua_event_e, nua_event_data() nua_saved_event_request(), nua_destroy_event()
- */
-int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1])
-{
-  if (nua && return_saved) {
-    su_msg_save(return_saved, nua->nua_current);
-    if (su_msg_is_non_null(return_saved)) {
-      /* Remove references to tasks */
-      su_msg_remove_refs(return_saved);
-      return 1;
-    }
-  }
-  return 0;
-}
-
-/** Get event data.
- *
- * @sa #nua_event_e, nua_event_save(), nua_saved_event_request(), nua_destroy_event().
- */
-nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1])
-{
-  return saved ? su_msg_data(saved) : NULL;
-}
-
-/** Destroy saved event.
- *
- * @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request().
- */
-void nua_destroy_event(nua_saved_event_t saved[1])
-{
-  if (su_msg_is_non_null(saved)) {
-    event_t *e = su_msg_data(saved);
-    nua_handle_t *nh = e->e_nh;
-
-    if (e->e_msg)
-      msg_destroy(e->e_msg), e->e_msg = NULL;
-
-    if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
-      SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
-    }
-
-    su_msg_destroy(saved);
+    nua_signal(nh->nh_nua, nh, NULL, nua_r_destroy, 0, NULL, TAG_END());
   }
 }
 
index 1c02537999b6deab82f8a8739fb4d3c24b69eba4..df9643871fb4fa4d1c4bc11668a3bf7c700ff4cb 100644 (file)
@@ -52,7 +52,6 @@
 #include <sofia-sip/su_debug.h>
 
 #define SU_ROOT_MAGIC_T   struct nua_s
-#define SU_MSG_ARG_T      struct event_s
 
 #include <sofia-sip/su_wait.h>
 
index 9750c0684c570981f7894e3f9461ba3699c68967..88f3ffd6086bd6fb4462e41023c4f994593461b8 100644 (file)
@@ -50,7 +50,11 @@ typedef struct nua_server_request nua_server_request_t;
 typedef struct nua_client_request nua_client_request_t; 
 typedef struct nua_dialog_peer_info nua_dialog_peer_info_t;
 
-typedef su_msg_r nua_saved_signal_t;
+#ifndef NUA_SAVED_SIGNAL_T
+#define NUA_SAVED_SIGNAL_T struct nua_saved_signal *
+#endif
+
+typedef NUA_SAVED_SIGNAL_T nua_saved_signal_t;
 
 typedef struct {
   sip_method_t sm_method; 
@@ -80,6 +84,7 @@ typedef struct {
 
 } nua_server_methods_t;
 
+
 /* Server side transaction */
 struct nua_server_request {
   struct nua_server_request *sr_next, **sr_prev;
@@ -132,7 +137,7 @@ struct nua_server_request {
   size_t sr_sdp_len;           /**< SDP length */
 
   /**< Save 200 OK nua_respond() signal until PRACK has been received */
-  nua_saved_signal_t sr_signal;        
+  nua_saved_signal_t sr_signal[1];
 };
 
 #define SR_STATUS(sr, status, phrase) \
@@ -141,6 +146,8 @@ struct nua_server_request {
 #define SR_STATUS1(sr, statusphrase)                                   \
   sr_status(sr, statusphrase)
 
+#define SR_HAS_SAVED_SIGNAL(sr) ((sr)->sr_signal[0] != NULL)
+
 su_inline 
 int sr_status(nua_server_request_t *sr, int status, char const *phrase)
 {
@@ -261,7 +268,7 @@ struct nua_client_request
   nua_owner_t        *cr_owner;
   nua_dialog_usage_t *cr_usage;
 
-  nua_saved_signal_t cr_signal;
+  nua_saved_signal_t cr_signal[1];
   tagi_t const      *cr_tags;
 
   nua_client_methods_t const *cr_methods;
index 023d2237c72898ec1fcf22edc0fb9c8cd12536fe..723c1a2f02a6802dedd7b81b1bcead510c81c8ec 100644 (file)
@@ -890,7 +890,18 @@ int nua_refer_server_respond(nua_server_request_t *sr, tagi_t const *tags)
 
 /** @NUA_EVENT nua_i_refer
  *
- * Incoming @b REFER request used to transfer calls.
+ * Incoming @b REFER request used to transfer calls. The tag list will
+ * contain tag NUTAG_REFER_EVENT() with the @Event header constructed from
+ * the REFER request. It will also contain the SIPTAG_REFERRED_BY() tag with
+ * the @ReferredBy header containing the identity of the party sending the
+ * REFER. The @ReferredBy structure contained in the tag is constructed from
+ * the @From header if the @ReferredBy header was not present in the REFER
+ * request.
+ * 
+ * The application can let the nua to send NOTIFYs from the call it
+ * initiates with nua_invite() if it includes in the nua_invite() arguments
+ * both the NUTAG_NOTIFY_REFER() with the handle with which nua_i_refer was
+ * received and the NUTAG_REFER_EVENT() from #nua_i_refer event tags.
  *
  * @param status status code of response sent automatically by stack
  * @param phrase a short textual description of @a status code
index fda891f5d39edfa94170eaad3a5d3a80d0804c81..17ec33ae542ea774f28dfaa2cd0510ae50b00d81 100644 (file)
@@ -1941,7 +1941,9 @@ sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh,
   char _transport[16];
   va_list va;
   sip_contact_t *m;
-  url_t url = URL_INIT_AS(sip);
+  url_t url;
+
+  url_init(&url, url_sip);
 
   if (!v) return NULL;
 
index 95ddb8b311f583db0d6cab7ef692b46a638544a8..93feb9c510a3dcff3ef6921f9f8b53df23165c7f 100644 (file)
@@ -2611,20 +2611,16 @@ int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags)
   if (sri == NULL) {
     
   }
-  else if (su_msg_is_non_null(sri->sr_signal)) {
-    su_msg_r signal;
-    event_t *e;
+  else if (SR_HAS_SAVED_SIGNAL(sri)) {
+    nua_signal_data_t const *e;
     
-    su_msg_save(signal, sri->sr_signal);
-    
-    e = su_msg_data(signal);
+    e = nua_signal_data(sri->sr_signal);
+
     sri->sr_application = SR_STATUS(sri, e->e_status, e->e_phrase);
     
     nua_server_params(sri, e->e_tags);
     nua_server_respond(sri, e->e_tags);
     nua_server_report(sri);
-    
-    su_msg_destroy(signal);
   }
   else if (ss->ss_state < nua_callstate_ready
           && !ss->ss_alerting
@@ -3106,7 +3102,6 @@ static int nua_update_client_report(nua_client_request_t *cr,
   nua_handle_t *nh = cr->cr_owner;
   nua_dialog_usage_t *du = cr->cr_usage;
   nua_session_usage_t *ss = nua_dialog_usage_private(du);
-  unsigned next_state = ss->ss_state;
 
   nua_stack_event(nh->nh_nua, nh, 
                  nta_outgoing_getresponse(orq),
@@ -3122,6 +3117,8 @@ static int nua_update_client_report(nua_client_request_t *cr,
     return 1;
 
   if (cr->cr_offer_sent) {
+    unsigned next_state = ss->ss_state;
+
     if (status < 200)
       ;
     else if (du->du_cr && du->du_cr->cr_orq && du->du_cr->cr_status >= 200) {
index ad46787cea4d85ca49e3c983ee41b0156987f66e..5e8bb149d0244d0e8bffaad946d3313d6f3c65d6 100644 (file)
 #include <sofia-sip/su_tag_io.h>
 
 #define SU_ROOT_MAGIC_T   struct nua_s
-#define SU_MSG_ARG_T      struct event_s
+#define SU_MSG_ARG_T      struct nua_ee_data
 #define SU_TIMER_ARG_T    struct nua_client_request
 
 #define NUA_SAVED_EVENT_T su_msg_t *
+#define NUA_SAVED_SIGNAL_T su_msg_t *
 
 #define NTA_AGENT_MAGIC_T    struct nua_s
 #define NTA_LEG_MAGIC_T      struct nua_handle_s
  *
  * ======================================================================== */
 
+/* ---------------------------------------------------------------------- */
+/* Internal types */
+
+/** Extended event data. */
+typedef struct nua_ee_data {
+  nua_t *ee_nua;
+  nua_event_data_t ee_data[1];
+} nua_ee_data_t;               
+
+/** @internal Linked stack frames from nua event callback */
+struct nua_event_frame_s {
+  nua_event_frame_t *nf_next;
+  nua_saved_event_t nf_saved[1];
+};
+
+
+static void nua_event_deinit(nua_ee_data_t *ee);
+static void nua_application_event(nua_t *, su_msg_r, nua_ee_data_t *ee);
+static void nua_stack_signal(nua_t *nua, su_msg_r, nua_ee_data_t *ee);
+
 nua_handle_t *nh_create(nua_t *nua, tag_type_t t, tag_value_t v, ...);
 static void nh_append(nua_t *nua, nua_handle_t *nh);
 static void nh_remove(nua_t *nua, nua_handle_t *nh);
@@ -279,18 +300,18 @@ int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
   }
 
   if (tags) {
-    e_len = offsetof(event_t, e_tags);
+    e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags);
     len = tl_len(tags);
     xtra = tl_xtra(tags, len);
   }
   else {
-    e_len = sizeof(event_t), len = 0, xtra = 0;
+    e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0;
   }
   p_len = phrase ? strlen(phrase) + 1 : 1;
 
-  if (su_msg_create(sumsg, nua->nua_client, su_task_null,
-                   nua_event, e_len + len + xtra + p_len) == 0) {
-    event_t *e = su_msg_data(sumsg);
+  if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) {
+    nua_ee_data_t *ee = su_msg_data(sumsg);
+    nua_event_data_t *e = ee->ee_data;
     void *p;
 
     if (tags) {
@@ -303,21 +324,138 @@ int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
     else
       p = e + 1;
 
+    ee->ee_nua = nua_stack_ref(nua);
     e->e_event = event;
-    e->e_nh = nh ? nua_handle_ref(nh) : nua->nua_dhandle;
+    e->e_nh = nh ? nua_handle_ref(nh) : NULL;
     e->e_status = status;
     e->e_phrase = strcpy(p, phrase ? phrase : "");
     if (msg)
       e->e_msg = msg, su_home_threadsafe(msg_home(msg));
 
-    if (su_msg_send(sumsg) != 0 && nh)
-      nua_handle_unref(nh);
+    su_msg_deinitializer(sumsg, nua_event_deinit);
+
+    su_msg_send_to(sumsg, nua->nua_client, nua_application_event);
   }
 
   return event;
 }
 
-/* ----------------------------------------------------------------------
+static
+void nua_event_deinit(nua_ee_data_t *ee)
+{
+  nua_t *nua = ee->ee_nua;
+  nua_event_data_t *e = ee->ee_data;
+  nua_handle_t *nh = e->e_nh;
+
+  if (e->e_msg)
+    msg_destroy(e->e_msg), e->e_msg = NULL;
+
+  if (nh)
+    nua_handle_unref(nh), e->e_nh = NULL;
+
+  if (nua)
+    nua_stack_unref(nua), ee->ee_nua = NULL;
+}
+
+/*# Receive event from protocol machine and hand it over to application */
+static
+void nua_application_event(nua_t *dummy, su_msg_r sumsg, nua_ee_data_t *ee)
+{
+  nua_t *nua = ee->ee_nua;
+  nua_event_data_t *e = ee->ee_data;
+  nua_handle_t *nh = e->e_nh;
+
+  enter;
+
+  ee->ee_nua = NULL;
+  e->e_nh = NULL;
+
+  if (nh == NULL) {
+    /* Xyzzy */
+  }
+  else if (nh->nh_valid) {
+    if (!nh->nh_ref_by_user) {
+      /* Application must now call nua_handle_destroy() */
+      nh->nh_ref_by_user = 1;
+      nua_handle_ref(nh);      
+    }
+  }
+  else if (!nh->nh_valid) {    /* Handle has been destroyed */
+    if (nua_log->log_level >= 7) {
+      char const *name = nua_event_name(e->e_event) + 4;
+      SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name));
+    }
+    nua_handle_unref(nh);
+    nua_stack_unref(nua);
+    return;
+  }
+
+  if (e->e_event == nua_r_shutdown && e->e_status >= 200)
+    nua->nua_shutdown_final = 1;
+
+  if (nua->nua_callback) {
+    nua_event_frame_t frame[1];
+    
+    su_msg_save(frame->nf_saved, sumsg);
+    frame->nf_next = nua->nua_current, nua->nua_current = frame;
+
+    nua->nua_callback(e->e_event, e->e_status, e->e_phrase,
+                     nua, nua->nua_magic,
+                     nh, nh ? nh->nh_magic : NULL,
+                     e->e_msg ? sip_object(e->e_msg) : NULL,
+                     e->e_tags);
+
+    su_msg_destroy(frame->nf_saved);
+    nua->nua_current = frame->nf_next;
+  }
+
+  nua_handle_unref(nh);
+  nua_stack_unref(nua);
+}
+
+/** Get current request message. @NEW_1_12_4.
+ *
+ * @note A response message is returned when processing response message.
+ *
+ * @sa #nua_event_e, nua_respond(), NUTAG_WITH_CURRENT()
+ */
+msg_t *nua_current_request(nua_t const *nua)
+{
+  if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved))
+    return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg;
+  return NULL;
+}
+
+/** Get request message from saved nua event. @NEW_1_12_4. 
+ *
+ * @sa nua_save_event(), nua_respond(), NUTAG_WITH_SAVED(), 
+ */
+msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
+{
+  return saved && saved[0] ? su_msg_data(saved)->ee_data->e_msg : NULL;
+}
+
+/** Save nua event and its arguments.
+ *
+ * @sa #nua_event_e, nua_event_data() nua_saved_event_request(), nua_destroy_event()
+ */
+int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1])
+{
+  if (return_saved) {
+    if (nua && nua->nua_current) {
+      su_msg_save(return_saved, nua->nua_current->nf_saved);
+      return su_msg_is_non_null(return_saved);
+    }
+    else
+      *return_saved = NULL;
+  }
+
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** @internal
  * Post signal to stack itself
  */
 void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
@@ -325,16 +463,73 @@ void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
 {
   ta_list ta;
   ta_start(ta, tag, value);
-  nua_signal((nh)->nh_nua, nh, NULL, 1, event, 0, NULL, ta_tags(ta));
+  nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta));
   ta_end(ta);
 }
 
 
+/*# Send a request to the protocol thread */
+int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg,
+              nua_event_t event,
+              int status, char const *phrase,
+              tag_type_t tag, tag_value_t value, ...)
+{
+  su_msg_r sumsg = SU_MSG_R_INIT;
+  size_t len, xtra, ee_len, l_len = 0, l_xtra = 0;
+  ta_list ta;
+  int retval = -1;
+
+  if (nua == NULL)
+    return -1;
+
+  if (nua->nua_shutdown_started && event != nua_r_shutdown)
+    return -1;
+
+  ta_start(ta, tag, value);
+
+  ee_len = offsetof(nua_ee_data_t, ee_data[0].e_tags);
+  len = tl_len(ta_args(ta));
+  xtra = tl_xtra(ta_args(ta), len);
+
+  if (su_msg_new(sumsg, ee_len + len + l_len + xtra + l_xtra) == 0) {
+    nua_ee_data_t *ee = su_msg_data(sumsg);
+    nua_event_data_t *e = ee->ee_data;
+    tagi_t *t = e->e_tags;
+    void *b = (char *)t + len + l_len;
+
+    tagi_t *tend = (tagi_t *)b;
+    char *bend = (char *)b + xtra + l_xtra;
+
+    t = tl_dup(t, ta_args(ta), &b);
+
+    assert(tend == t); (void)tend; assert(b == bend); (void)bend;
+
+    e->e_always = event == nua_r_destroy || event == nua_r_shutdown;
+    e->e_event = event;
+    e->e_nh = nh ? nua_handle_ref(nh) : NULL;
+    e->e_status = status;
+    e->e_phrase = phrase;
+
+    SU_DEBUG_7(("nua(%p): signal %s\n", (void *)nh,
+               nua_event_name(event) + 4));
+
+    su_msg_deinitializer(sumsg, nua_event_deinit);
+      
+    retval = su_msg_send_to(sumsg, nua->nua_server, nua_stack_signal);
+  }
+
+  ta_end(ta);
+
+  return retval;
+}
+
 /* ----------------------------------------------------------------------
  * Receiving events from client
  */
-void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
+static
+void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee)
 {
+  nua_event_data_t *e = ee->ee_data;
   nua_handle_t *nh = e->e_nh;
   tagi_t *tags = e->e_tags;
   nua_event_t event;
@@ -342,11 +537,6 @@ void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
 
   assert(tags);
 
-  if (nua_log->log_level >= 7) {
-    char const *name = nua_event_name(e->e_event) + 4;
-    SU_DEBUG_7(("nua(%p): recv %s\n", (void *)nh, name));
-  }
-
   if (nh) {
     if (!nh->nh_prev)
       nh_append(nua, nh);
@@ -359,6 +549,7 @@ void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
 
   if (nua_log->log_level >= 5) {
     char const *name = nua_event_name(e->e_event);
+
     if (e->e_status == 0)
       SU_DEBUG_5(("nua(%p): signal %s\n", (void *)nh, name + 4));
     else
@@ -377,8 +568,7 @@ void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
                    901, "Stack is going down",
                    NULL);
   }
-
- switch (event) {
+  else switch (event) {
   case nua_r_get_params:
     nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, event, tags);
     break;
@@ -463,11 +653,44 @@ void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
     nua_stack_event(nh->nh_nua, nh, NULL, event, NUA_INTERNAL_ERROR, NULL);
   }
 
-  if (su_msg_is_non_null(nua->nua_signal))
-    su_msg_destroy(nua->nua_signal);
+  su_msg_destroy(nua->nua_signal);
+}
 
-  if (nh != nua->nua_dhandle)
-    nua_handle_unref(nh);
+/* ====================================================================== */
+/* Signal and event handling */
+
+/** Get event data.
+ *
+ * @sa #nua_event_e, nua_event_save(), nua_saved_event_request(), nua_destroy_event().
+ */
+nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1])
+{
+  return saved && saved[0] ? su_msg_data(saved)->ee_data : NULL;
+}
+
+/** Destroy saved event.
+ *
+ * @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request().
+ */
+void nua_destroy_event(nua_saved_event_t saved[1])
+{
+  if (saved) su_msg_destroy(saved);
+}
+
+/** @internal Move signal. */
+void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1])
+{
+  su_msg_save(a, b);
+}
+
+void nua_destroy_signal(nua_saved_signal_t saved[1])
+{
+  if (saved) su_msg_destroy(saved);
+}
+
+nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1])
+{
+  return nua_event_data(saved);
 }
 
 /* ====================================================================== */
@@ -1114,6 +1337,8 @@ int nua_stack_process_request(nua_handle_t *nh,
        (Call/Transaction Does Not Exist) status code and pass that to the
        server transaction.
     */
+    if (method == sip_method_info)
+      /* accept out-of-dialog info */; else
     if (method != sip_method_message || !NH_PGET(nh, win_messenger_enable))
       sm = NULL;
   }
@@ -1242,11 +1467,12 @@ void nua_server_request_destroy(nua_server_request_t *sr)
   if (sr == NULL)
     return;
 
+  if (SR_HAS_SAVED_SIGNAL(sr))
+    nua_destroy_signal(sr->sr_signal);
+
   if (sr->sr_irq)
     nta_incoming_destroy(sr->sr_irq), sr->sr_irq = NULL;
 
-  su_msg_destroy(sr->sr_signal);
-
   if (sr->sr_request.msg)
     msg_destroy(sr->sr_request.msg), sr->sr_request.msg = NULL;
 
@@ -1379,8 +1605,9 @@ nua_stack_respond(nua_t *nua, nua_handle_t *nh,
     sr->sr_application = status;
     if (tags && nua_stack_set_params(nua, nh, nua_i_none, tags) < 0)
       SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
-    else
+    else {
       sr->sr_status = status, sr->sr_phrase = phrase;
+    }
   }
 
   nua_server_params(sr, tags);
@@ -1771,12 +1998,12 @@ int nua_client_create(nua_handle_t *nh,
   cr->cr_auto = 1;
 
   if (su_msg_is_non_null(nh->nh_nua->nua_signal)) {
-    nua_event_data_t const *e = su_msg_data(nh->nh_nua->nua_signal);
+    nua_event_data_t const *e = su_msg_data(nh->nh_nua->nua_signal)->ee_data;
 
     if (tags == e->e_tags && event == e->e_event) {
       cr->cr_auto = 0;
       if (tags) {
-       su_msg_save(cr->cr_signal, nh->nh_nua->nua_signal);
+       nua_move_signal(cr->cr_signal, nh->nh_nua->nua_signal);
        cr->cr_tags = tags;
       }
     }
@@ -1860,7 +2087,7 @@ void nua_client_request_destroy(nua_client_request_t *cr)
 
   nh = cr->cr_owner;
 
-  su_msg_destroy(cr->cr_signal);
+  nua_destroy_signal(cr->cr_signal);
 
   nua_client_request_remove(cr);
   nua_client_bind(cr, NULL);
@@ -2575,9 +2802,11 @@ int nua_base_client_check_restart(nua_client_request_t *cr,
 
       cr->cr_challenged = 1;
 
-      if (invalid)
+      if (invalid) {
        /* Bad username/password */
+       SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh));
        auc_clear_credentials(&nh->nh_auth, NULL, NULL);
+      }
       else if (auc_has_authorization(&nh->nh_auth)) 
        return nua_client_restart(cr, 100, "Request Authorized by Cache");
 
@@ -2594,7 +2823,7 @@ int nua_base_client_check_restart(nua_client_request_t *cr,
   if (500 <= status && status < 600 && 
       sip->sip_retry_after && 
       sip->sip_retry_after->af_delta < 32) {
-    char phrase[18];           /* Retry-After: XXXX\0 */
+    char phrase[18];           /* Retry After XXXX\0 */
 
     if (cr->cr_timer == NULL)
       cr->cr_timer = su_timer_create(su_root_task(nh->nh_nua->nua_root), 0);
index fac582f5f55f1d36ce9fb2f1147d939a70e940f2..e8a6226066f505fccacb762a62f505e8cc282c62 100644 (file)
@@ -75,7 +75,7 @@ SOFIA_BEGIN_DECLS
 #include "nua_params.h"
 #endif
 
-typedef struct event_s event_t;
+typedef struct event_s event_t, nua_signal_data_t;
 
 #define       NONE ((void *)-1)
 
@@ -109,7 +109,7 @@ typedef struct register_usage nua_registration_t;
 #define nua_handle_unref(nh) nua_handle_unref_by((nh), __func__)
 
 su_inline nua_handle_t *nua_handle_ref_by(nua_handle_t *nh,
-                                             char const *by)
+                                         char const *by)
 {
   if (nh)
     SU_DEBUG_0(("nua_handle_ref(%p) => "MOD_ZU" by %s\n", nh, 
@@ -120,11 +120,16 @@ su_inline nua_handle_t *nua_handle_ref_by(nua_handle_t *nh,
 
 su_inline int nua_handle_unref_by(nua_handle_t *nh, char const *by)
 {
-  if (nh)
-    SU_DEBUG_0(("nua_handle_unref(%p) => "MOD_ZU" by %s\n", nh, 
-               su_home_refcount((su_home_t *)nh) - 1,
-               by));
-  return su_home_unref((su_home_t *)nh);
+  if (nh) {
+    size_t refcount = su_home_refcount((su_home_t *)nh) - 1;
+    int freed =  su_home_unref((su_home_t *)nh);
+    if (freed) refcount = 0;
+    SU_DEBUG_0(("nua_handle_unref(%p) => "MOD_ZU" by %s\n",
+               nh, refcount, by));
+    return freed;
+  }
+
+  return 0; 
 }
 
 #endif
@@ -197,6 +202,8 @@ int nh_is_special(nua_handle_t *nh)
   return nh == NULL || nh->nh_special;
 }
 
+typedef struct nua_event_frame_s nua_event_frame_t;
+
 extern char const nua_internal_error[];
 
 #define NUA_INTERNAL_ERROR 900, nua_internal_error
@@ -214,7 +221,7 @@ struct nua_s {
   nua_callback_f       nua_callback;
   nua_magic_t         *nua_magic;
 
-  nua_saved_event_t    nua_current[1];
+  nua_event_frame_t   *nua_current;
   nua_saved_event_t    nua_signal[1];
 
   /* Engine state flags */
@@ -277,10 +284,19 @@ struct nua_s {
 #define __func__ "nua"
 #endif
 
+su_inline nua_t *nua_stack_ref(nua_t *nua)
+{ 
+  return (nua_t *)su_home_ref(nua->nua_home);
+}
+
+su_inline void nua_stack_unref(nua_t *nua)
+{ 
+  su_home_unref(nua->nua_home);
+}
+
 /* Internal prototypes */
 int  nua_stack_init(su_root_t *root, nua_t *nua);
 void nua_stack_deinit(su_root_t *root, nua_t *nua);
-void nua_stack_signal(nua_t *nua, su_msg_r msg, event_t *e);
 
 int nua_stack_init_transport(nua_t *nua, tagi_t const *tags);
 
@@ -305,6 +321,10 @@ typedef int nua_stack_signal_handler(nua_t *,
                                     nua_event_t, 
                                     tagi_t const *);
 
+void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1]);
+nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1]);
+void nua_destroy_signal(nua_saved_signal_t saved[1]);
+
 nua_stack_signal_handler 
   nua_stack_set_params, nua_stack_get_params,
   nua_stack_register, 
@@ -332,6 +352,8 @@ int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
                    nua_event_t event, int status, char const *phrase,
                    tagi_t const *tags);
 
+void nua_move_event(nua_saved_event_t a[1], nua_saved_event_t b[1]);
+
 nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic, tagi_t *tags);
 
 nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
@@ -431,11 +453,9 @@ typedef unsigned longlong ull;
 /* ---------------------------------------------------------------------- */
 /* Application side prototypes */
 
-void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
-               nua_event_t event, int status, char const *phrase,
-               tag_type_t tag, tag_value_t value, ...);
-
-void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e);
+int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg,
+              nua_event_t event, int status, char const *phrase,
+              tag_type_t tag, tag_value_t value, ...);
 
 SOFIA_END_DECLS
 
index 689edbea05c4c163b216e588d7627795ef20a6c2..d7c7feddb4d84c2483e6a12caa80eda27038fdbc 100644 (file)
@@ -463,7 +463,8 @@ int test_basic_call_2(struct context *ctx)
 #else
   /* sf.net bug #1816647: Outbound contact does not make it to dialogs */
   /* Now we use first registered contact if aor does not match */
-  TEST_S(sip->sip_contact->m_url->url_user, "b");
+  if (ctx->proxy_tests)
+    TEST_S(sip->sip_contact->m_url->url_user, "b");
 #endif
   TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
   TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
@@ -1043,7 +1044,8 @@ int test_basic_call_5(struct context *ctx)
   TEST(e->data->e_status, 200);
   TEST_1(sip = sip_object(e->data->e_msg));
   TEST_1(sip->sip_contact);
-  TEST_S(sip->sip_contact->m_url->url_user, "b");
+  if (ctx->proxy_tests)                /* Use Contact from registration? */
+    TEST_S(sip->sip_contact->m_url->url_user, "b");
   TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
   TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
   TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
index 92311cb609adfc865e4239b36a07ea49bb3090d8..b12b75f5336ff9e8799640ea71bedf18ee5f8086 100644 (file)
@@ -408,6 +408,7 @@ int test_deinit(struct context *ctx)
 
     nua_shutdown(ctx->a.nua);
     run_a_until(ctx, nua_r_shutdown, until_final_response);
+    free_events_in_list(ctx, ctx->a.events);
     free_events_in_list(ctx, ctx->a.specials);
     nua_destroy(ctx->a.nua), ctx->a.nua = NULL;
   }
@@ -418,6 +419,7 @@ int test_deinit(struct context *ctx)
 
     nua_shutdown(ctx->b.nua);
     run_b_until(ctx, nua_r_shutdown, until_final_response);
+    free_events_in_list(ctx, ctx->b.events);
     free_events_in_list(ctx, ctx->b.specials);
     nua_destroy(ctx->b.nua), ctx->b.nua = NULL;
   }
@@ -428,6 +430,7 @@ int test_deinit(struct context *ctx)
 
     nua_shutdown(ctx->c.nua);
     run_c_until(ctx, nua_r_shutdown, until_final_response);
+    free_events_in_list(ctx, ctx->c.events);
     free_events_in_list(ctx, ctx->c.specials);
     nua_destroy(ctx->c.nua), ctx->c.nua = NULL;
   }
@@ -436,7 +439,7 @@ int test_deinit(struct context *ctx)
 
   test_nat_destroy(ctx->nat), ctx->nat = NULL;
 
-  su_root_destroy(ctx->root);
+  su_root_destroy(ctx->root), ctx->root = NULL;
 
   END();
 }
index 0e75b799c8913630340a202a6031d2a703b53ffe..1d035fcae19eb6ee843121e195a3c50f9327bc09 100644 (file)
@@ -22,7 +22,8 @@
  *
  */
 
-/**@CFILE test_nua.h
+/**@@internal
+ * @file test_nua.h
  * @brief High-level tester framework for Sofia SIP User Agent Engine
  *
  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
index c6e59ac0725e827137c8b9b3166eeec8378f0cf7..afc2819a45f377ce4391580b448213a3c1026bb2 100644 (file)
@@ -206,6 +206,7 @@ struct proxy_tr
   sip_t *sip;                  /* request headers */
 
   sip_method_t method;         /* request method */
+  char const *method_name;
   int status;                  /* best status */
   url_t *target;               /* request-URI */
 
@@ -343,6 +344,9 @@ test_proxy_deinit(su_root_t *root, struct proxy *proxy)
 {
   struct proxy_tr *t;
 
+  while (proxy->transactions)
+    proxy_tr_destroy(proxy->transactions);
+
   if ((t = proxy->stateless)) {
     proxy->stateless = NULL;
     proxy_tr_destroy(t);
@@ -698,7 +702,7 @@ static int domain_request(union proxy_or_domain *pod,
 {
   int (*process)(struct proxy_tr *) = NULL;
   sip_method_t method = sip->sip_request->rq_method;
-
+  
   assert(pod->domain->magic = domain_init);
 
   if (leg == pod->domain->uleg)
@@ -732,6 +736,7 @@ static int proxy_tr_with(struct proxy *proxy,
     t->sip = sip_object(t->msg);
 
     t->method = sip->sip_request->rq_method;
+    t->method_name = sip->sip_request->rq_method_name;
     t->target = sip->sip_request->rq_url;
     t->now = nta_incoming_received(irq, NULL);
 
@@ -767,7 +772,7 @@ static int proxy_transaction(struct proxy_tr *t)
 
   return target_transaction(t, t->target, NULL);
 }
-  
+
 static int respond_transaction(struct proxy_tr *t,
                               int status, char const *phrase,
                               tag_type_t tag, tag_value_t value,
@@ -925,6 +930,7 @@ static int target_transaction(struct proxy_tr *t,
                              tport_t *tport)
 {
   struct client_tr *c = su_zalloc(t->proxy->home, sizeof *c);
+  int stateless = t->method == sip_method_ack;
 
   if (c == NULL)
     return 500;
@@ -935,8 +941,7 @@ static int target_transaction(struct proxy_tr *t,
 
   if (c->msg)
     c->rq = sip_request_create(msg_home(c->msg),
-                              c->sip->sip_request->rq_method,
-                              c->sip->sip_request->rq_method_name,
+                              t->method, t->method_name,
                               (url_string_t *)target,
                               NULL);
 
@@ -957,15 +962,18 @@ static int target_transaction(struct proxy_tr *t,
                                     NULL,
                                     msg_ref_create(c->msg),
                                     NTATAG_TPORT(tport),
+                                    NTATAG_STATELESS(stateless),
                                     TAG_END());
 
-  if (c->client)
-    return client_tr_insert(&t->clients, c), 0;
+  if (!c->client) {
+    msg_destroy(c->msg);
+    su_free(t->proxy->home, c);
+    return 500;
+  }
 
-  msg_destroy(c->msg);
-  su_free(t->proxy->home, c);
+  client_tr_insert(&t->clients, c);
 
-  return 500;
+  return stateless ? 200 : 0;
 }
 
 static int challenge_transaction(struct proxy_tr *t)
@@ -1095,6 +1103,8 @@ void proxy_tr_destroy(struct proxy_tr *t)
     su_free(t->proxy->home, c);
   }
 
+  msg_destroy(t->msg);
+
   nta_incoming_destroy(t->server);
 
   su_free(t->proxy->home, t);
index 1ee17cf24880bbab2cbd55b09943b7e94d6e7e28..cb79b12d2b0c4a53aa4a421e0ce09b77839b9e42 100644 (file)
@@ -1018,6 +1018,15 @@ int test_unregister(struct context *ctx)
       TEST_1(e = e->next);
       TEST_E(e->data->e_event, nua_r_unregister);
     }
+    if (e->data->e_status == 401) {
+      TEST_1(!e->next);
+      free_events_in_list(ctx, c->events);
+      AUTHENTICATE(c, NULL, c->reg->nh,
+                  NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+      run_c_until(ctx, -1, save_until_final_response);
+      TEST_1(e = c->events->head);
+      TEST_E(e->data->e_event, nua_r_unregister);
+    }
     TEST(e->data->e_status, 200);
     TEST_1(sip = sip_object(e->data->e_msg));
     TEST_1(sip->sip_from->a_url->url_user);
index c0a1071e3fc3521c5c02254c4c82c51fae6dbc44..e35a92a57dfca9d927232104678611d623d39c6f 100644 (file)
@@ -398,6 +398,9 @@ typedef void su_msg_function(su_root_magic_t *magic,
                             su_msg_r msg,
                             su_msg_arg_t *arg);
 
+/** Message deinitialize. */
+typedef void su_msg_deinit_func(su_msg_arg_t *arg);
+
 /** Message delivery function pointer type. */
 typedef su_msg_function *su_msg_f;
 
@@ -526,6 +529,7 @@ SOFIAPUBFUN int su_msg_create(su_msg_r msg,
                              su_task_r const to, su_task_r const from, 
                              su_msg_f wakeup, isize_t size);
 SOFIAPUBFUN int su_msg_report(su_msg_r msg, su_msg_f report);
+SOFIAPUBFUN int su_msg_deinitializer(su_msg_r msg, su_msg_deinit_func *);
 SOFIAPUBFUN int su_msg_reply(su_msg_r reply, su_msg_cr msg,
                             su_msg_f wakeup, isize_t size);
 SOFIAPUBFUN void su_msg_destroy(su_msg_r msg);
@@ -537,6 +541,11 @@ SOFIAPUBFUN _su_task_r su_msg_from(su_msg_cr msg);
 SOFIAPUBFUN _su_task_r su_msg_to(su_msg_cr msg);
 SOFIAPUBFUN int su_msg_send(su_msg_r msg);
 
+SOFIAPUBFUN int su_msg_new(su_msg_r msg, size_t size);
+SOFIAPUBFUN int su_msg_send_to(su_msg_r msg,
+                              su_task_r const to, 
+                              su_msg_f wakeup);
+
 /** Does reference contain a message? */
 #if SU_HAVE_INLINE
 static SU_INLINE
index 13b0b51e59ad921af699c74810d020e5389c4727..715888c02136bb0699fd052c3a0f17f38eb5c8b1 100644 (file)
@@ -268,8 +268,14 @@ static int su_base_port_execute_msgs(su_msg_t *queue)
 
     queue = msg->sum_next, msg->sum_next = NULL;
 
-    if (f) 
-      f(SU_ROOT_MAGIC(msg->sum_to->sut_root), &msg, msg->sum_data);
+    if (f) {
+      su_root_t *root = msg->sum_to->sut_root;
+
+      if (msg->sum_to->sut_port == NULL)
+       msg->sum_to->sut_root = NULL;
+      f(SU_ROOT_MAGIC(root), &msg, msg->sum_data);
+    }
+
     su_msg_delivery_report(&msg);
     n++;
   }
index 475c10948e7b4a67ec27582a14ca4b356d86cf0f..adb77160315d5ca5b592fb95366f48c26ac6244e 100644 (file)
@@ -61,12 +61,13 @@ SOFIA_BEGIN_DECLS
 
 /** @internal Message */
 struct su_msg_s {
-  isize_t        sum_size;
+  size_t         sum_size;
   su_msg_t      *sum_next;
   su_task_r      sum_to;
   su_task_r      sum_from;
   su_msg_f       sum_func;
   su_msg_f       sum_report;
+  su_msg_deinit_func *sum_deinit;
   su_msg_arg_t   sum_data[1];          /* minimum size, may be extended */
 };
 
@@ -101,11 +102,11 @@ typedef struct su_port_vtable {
   struct _GSource *(*su_port_gsource)(su_port_t *port);
   int (*su_port_send)(su_port_t *self, su_msg_r rmsg);
   int (*su_port_register)(su_port_t *self,
-                      su_root_t *root, 
-                      su_wait_t *wait, 
-                      su_wakeup_f callback,
-                      su_wakeup_arg_t *arg,
-                      int priority);
+                         su_root_t *root, 
+                         su_wait_t *wait, 
+                         su_wakeup_f callback,
+                         su_wakeup_arg_t *arg,
+                         int priority);
   int (*su_port_unregister)(su_port_t *port,
                            su_root_t *root, 
                            su_wait_t *wait,    
index 2a7ffb228cc060dbd01f53fbace811fc193bd8ff..daf176cefb67ae5741f8cad6805ce43333180219 100644 (file)
@@ -875,6 +875,30 @@ int su_root_has_thread(su_root_t *root)
  * Messages
  */
 
+/**
+ * Allocate a su message of given size.
+ *
+ * Allocate a su message with given data size. 
+ *
+ * @param  rmsg   handle to the new message (may be uninitialized prior calling)
+ * @param  size   size of the message data
+ *
+ * @retval  0 if successful,
+ * @retval -1 if message allocation fails.  
+ */
+int su_msg_new(su_msg_r rmsg, size_t size)
+{
+  su_msg_t *msg;
+  size_t total = sizeof(*msg) + (size_t)size;
+
+  *rmsg = msg = su_zalloc(NULL, (isize_t)total);
+  if (!*rmsg)
+    return -1;
+
+  msg->sum_size = total;
+  return 0;
+}
+
 /**
  * Allocates a message of given size.
  *
@@ -896,20 +920,13 @@ int su_msg_create(su_msg_r        rmsg,
                  su_msg_f        wakeup,
                  isize_t         size)
 {
-  su_msg_t *msg;
-
-  msg = su_zalloc(NULL, sizeof(*msg) + size);
-
-  if (msg) {
-    msg->sum_size = sizeof(*msg) + size;
-    SU_TASK_COPY(msg->sum_to, to, su_msg_create);
-    SU_TASK_COPY(msg->sum_from, from, su_msg_create);
-    msg->sum_func = wakeup;
-    *rmsg = msg;
+  if (su_msg_new(rmsg, (size_t) size) == 0) {
+    SU_TASK_COPY(rmsg[0]->sum_to, to, su_msg_create);
+    SU_TASK_COPY(rmsg[0]->sum_from, from, su_msg_create);
+    rmsg[0]->sum_func = wakeup;
     return 0;
   } 
 
-  *rmsg = NULL;
   return -1;
 }
 
@@ -931,11 +948,31 @@ int su_msg_report(su_msg_r msg,
   return -1;
 }
 
+/** Add a deinitializer function to a message.
+ *
+ * The deinitializer function is called when the message gets destroyed. It
+ * is called even if the message was never delivered. Note that the thread
+ * destroying the message and calling the deinit function is not necessarily
+ * the same that sent the message nor the original recipient.
+ *
+ * @param rmsg   message reference
+ * @param deinit pointer to deinitializer function
+ */
+int su_msg_deinitializer(su_msg_r rmsg,
+                        su_msg_deinit_func *deinit)
+{
+  if (rmsg && rmsg[0]) {
+    rmsg[0]->sum_deinit = deinit;
+    return 0;
+  }
+  return -1;
+}
+
 /**
  * Allocates a reply message of given size.
  *
  * @param reply     handle to the new message (may be uninitialized prior calling)
- * @param msg       the incoming message
+ * @param rmsg       the incoming message
  * @param wakeup    function that is called when message is delivered
  * @param size      size of the message data
  *
@@ -943,17 +980,17 @@ int su_msg_report(su_msg_r msg,
  * @retval -1 otherwise.
  */
 
-int su_msg_reply(su_msg_r reply, su_msg_cr msg,
+int su_msg_reply(su_msg_r reply, su_msg_cr rmsg,
                 su_msg_f wakeup, isize_t size)
 {
-  su_msg_r msg0;
+  su_msg_r rmsg0;
 
-  assert(msg != reply);
+  assert(rmsg != reply);
 
-  *msg0 = *(su_msg_t **) msg;
+  *rmsg0 = *(su_msg_t **) rmsg;
   *reply = NULL;
 
-  return su_msg_create(reply, su_msg_from(msg0), su_msg_to(msg0), wakeup, size);
+  return su_msg_create(reply, su_msg_from(rmsg0), su_msg_to(rmsg0), wakeup, size);
 }
 
 
@@ -964,38 +1001,38 @@ int su_msg_reply(su_msg_r reply, su_msg_cr msg,
  * sending task. The sending task calls the delivery report function when it
  * has received the message.
  */
-void su_msg_delivery_report(su_msg_r msg)
+void su_msg_delivery_report(su_msg_r rmsg)
 {
   su_task_r swap;
 
-  if (!msg || !msg[0])
+  if (!rmsg || !rmsg[0])
     return;
 
-  if (!msg[0]->sum_report) {
-    su_msg_destroy(msg);
+  if (!rmsg[0]->sum_report) {
+    su_msg_destroy(rmsg);
     return;
   }
 
-  *swap = *msg[0]->sum_from;
-  *msg[0]->sum_from = *msg[0]->sum_to;
-  *msg[0]->sum_to = *swap;
+  *swap = *rmsg[0]->sum_from;
+  *rmsg[0]->sum_from = *rmsg[0]->sum_to;
+  *rmsg[0]->sum_to = *swap;
 
-  msg[0]->sum_func = msg[0]->sum_report;
-  msg[0]->sum_report = NULL;
-  su_msg_send(msg);
+  rmsg[0]->sum_func = rmsg[0]->sum_report;
+  rmsg[0]->sum_report = NULL;
+  su_msg_send(rmsg);
 }
 
 /** Save a message. */
-void su_msg_save(su_msg_r save, su_msg_r msg)
+void su_msg_save(su_msg_r save, su_msg_r rmsg)
 {
   if (save) {
-    if (msg)
-      save[0] = msg[0];
+    if (rmsg)
+      save[0] = rmsg[0];
     else
       save[0] = NULL;
   }
-  if (msg)
-    msg[0] = NULL;
+  if (rmsg)
+    rmsg[0] = NULL;
 }
 
 /**
@@ -1011,6 +1048,9 @@ void su_msg_destroy(su_msg_r rmsg)
     SU_TASK_ZAP(rmsg[0]->sum_to, su_msg_destroy);
     SU_TASK_ZAP(rmsg[0]->sum_from, su_msg_destroy);
 
+    if (rmsg[0]->sum_deinit)
+      rmsg[0]->sum_deinit(rmsg[0]->sum_data);
+
     su_free(NULL, rmsg[0]);
   }
 
@@ -1048,13 +1088,13 @@ isize_t su_msg_size(su_msg_cr rmsg)
  * If the message handle contains NULL the function @c su_msg_from
  * returns NULL.
  *
- * @param msg       message handle
+ * @param rmsg       message handle
  *
  * @return The task handle of the sender is returned.  
  */
-_su_task_r su_msg_from(su_msg_cr msg)
+_su_task_r su_msg_from(su_msg_cr rmsg)
 {
-  return msg[0] ? msg[0]->sum_from : NULL;
+  return rmsg[0] ? rmsg[0]->sum_from : NULL;
 }
 
 /** Get destination task.
@@ -1065,24 +1105,24 @@ _su_task_r su_msg_from(su_msg_cr msg)
  * If the message handle contains NULL the function @c su_msg_to
  * returns NULL.
  *
- * @param msg       message handle
+ * @param rmsg       message handle
  *
  * @return The task handle of the recipient is returned.  
  */
-_su_task_r su_msg_to(su_msg_cr msg)
+_su_task_r su_msg_to(su_msg_cr rmsg)
 {
-  return msg[0] ? msg[0]->sum_to : NULL;
+  return rmsg[0] ? rmsg[0]->sum_to : NULL;
 }
 
 /** Remove references to 'from' and 'to' tasks from a message. 
  *
- * @param msg       message handle
+ * @param rmsg       message handle
  */
-void su_msg_remove_refs(su_msg_cr msg)
+void su_msg_remove_refs(su_msg_cr rmsg)
 {
-  if (msg[0]) {
-    su_task_deinit(msg[0]->sum_to);
-    su_task_deinit(msg[0]->sum_from);
+  if (rmsg[0]) {
+    su_task_deinit(rmsg[0]->sum_to);
+    su_task_deinit(rmsg[0]->sum_from);
   }
 }
 
@@ -1115,3 +1155,36 @@ int su_msg_send(su_msg_r rmsg)
 
   return 0;            
 }
+
+/** Send message to the @a to_task and mark @a from_task as sender */
+SOFIAPUBFUN int su_msg_send_to(su_msg_r rmsg,
+                              su_task_r const to_task,
+                              su_msg_f wakeup)
+{
+  assert(rmsg); assert(to_task);
+
+  if (rmsg[0]) {
+    su_msg_t *msg = rmsg[0];
+
+    if (wakeup)
+      msg->sum_func = wakeup;
+
+    if (msg->sum_to->sut_port && 
+       msg->sum_to->sut_port != to_task->sut_port) {
+      SU_TASK_ZAP(msg->sum_to, "su_msg_send_to"); 
+    }
+
+    if (to_task->sut_port != NULL) {
+      msg->sum_to->sut_port = NULL;
+      msg->sum_to->sut_root = to_task->sut_root;
+
+      return su_port_send(to_task->sut_port, rmsg);
+    }
+
+    su_msg_destroy(rmsg);
+    errno = EINVAL;
+    return -1;
+  }
+
+  return 0;
+}
index d23f73372c8870a01e9deeaab971398b83e8245a..a11b2fd396abf626898aaeb6130a92c3b6865706 100644 (file)
@@ -96,7 +96,7 @@ struct hentry_s
 #define HENTRY_IS_USED(e) ((e).e_n != 0)
 #define HENTRY_REMOVE(e) ((e)->e_n = 0, (e)->e_hash = 0)
 #define HENTRY_IS_EQUAL(a, b) ((a).e_n == (b).e_n)
-#define HALLOC(home, old, newsize) (su_realloc(home, old, newsize))
+#define HALLOC(home, old, newsize) (su_realloc(home, old, (isize_t)newsize))
 
 HTABLE2_BODIES2(htable2_t, htable2, ht2_, entry_t, size_t,
               HENTRY_HASH, HENTRY_IS_USED, HENTRY_REMOVE, HENTRY_IS_EQUAL,
index 987f75163ac9c39d66add52a92ea1806495acce0..a88c1e25578c007abd8f20c007afa61e987f0857 100644 (file)
@@ -559,16 +559,10 @@ int main(int argc, char *argv[])
     su_perror("su_timer_create"), exit(1);
   su_timer_set(t, (su_timer_f)do_exit, NULL);
 
-  su_clone_pause(ping);
-  su_clone_pause(pong);
-
   su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong), 
                init_ping, 0);
   su_msg_send(start_msg);
 
-  su_clone_resume(ping);
-  su_clone_resume(pong);
-
   su_root_run(root);
 
   su_clone_wait(root, ping);
index f99c86f7588e103a3898c6696d9ae4cb4bd8d3b6..d5673f9f7a4ff4492c7d31f8d37bc0720a08af22 100644 (file)
@@ -41,6 +41,7 @@ char const *name = "torture_su_root";
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #define TSTFLAGS rt->rt_flags
 #include <sofia-sip/tstdef.h>
@@ -50,6 +51,7 @@ typedef struct test_ep_s   test_ep_t;
 
 #define SU_ROOT_MAGIC_T  root_test_t
 #define SU_WAKEUP_ARG_T  test_ep_t
+#define SU_MSG_ARG_T     root_test_t *
 
 #include <sofia-sip/su_wait.h>
 #include <sofia-sip/su_alloc.h>
@@ -83,6 +85,9 @@ struct root_test_s {
 
   su_clone_r rt_clone;
 
+  unsigned   rt_msg_received;
+  unsigned   rt_msg_destroyed;
+
   unsigned   rt_fail_init:1;
   unsigned   rt_fail_deinit:1;
   unsigned   rt_success_init:1;
@@ -591,6 +596,22 @@ static int set_execute_bit_and_return_3(void *void_rt)
   return 3;
 }
 
+static void deinit_simple_msg(su_msg_arg_t *arg)
+{
+  root_test_t *rt = *arg;
+  rt->rt_msg_destroyed++;
+}
+
+static void receive_simple_msg(root_test_t *rt, 
+                              su_msg_r msg,
+                              su_msg_arg_t *arg)
+{
+  assert(rt == *arg);
+  rt->rt_msg_received = 
+    su_task_cmp(su_msg_from(msg), su_task_null) == 0 &&
+    su_task_cmp(su_msg_to(msg), su_task_null) == 0;
+}
+
 static int clone_test(root_test_t rt[1])
 {
   BEGIN();
@@ -629,7 +650,21 @@ static int clone_test(root_test_t rt[1])
                       &retval), 0);
   TEST(retval, 3);
   TEST_1(rt->rt_executed);
-       
+
+  /* Deliver message with su_msg_send() */
+  TEST(su_msg_new(m, sizeof &rt), 0);
+  *su_msg_data(m) = rt;
+
+  rt->rt_msg_received = 0;
+  rt->rt_msg_destroyed = 0;
+  
+  TEST(su_msg_deinitializer(m, deinit_simple_msg), 0);
+  TEST(su_msg_send_to(m, su_clone_task(rt->rt_clone), receive_simple_msg), 0);
+  
+  while (rt->rt_msg_destroyed == 0)
+    su_root_step(rt->rt_root, 1);
+
+  TEST(rt->rt_msg_received, 1);
 
   /* Make sure 3-way handshake is done as expected */
   TEST(su_msg_create(m,
index 9d8683bb58e80a77b72459be9c91d2bf40998de9..f87191bc966e2a6d4ec21a4681802d5a8341287e 100644 (file)
@@ -166,7 +166,7 @@ typedef struct {
   (n)->tpn_comp ? ";comp=" : "", (n)->tpn_comp ? (n)->tpn_comp : "",    \
   (n)->tpn_ident ? "/" : "", (n)->tpn_ident ? (n)->tpn_ident : ""
 
-/** Create first primary transport. */
+/**Create master transport. */
 TPORT_DLL tport_t *tport_tcreate(tp_stack_t *stack,
                                 tport_stack_class_t const *tpac,
                                 su_root_t *root,
index 730104054ce56e3b29f424f29badb52edd893e80..d8bed43f999e0b26a52b30bff7f7395a355e0b9b 100644 (file)
@@ -798,7 +798,7 @@ static int udp_test(tp_test_t *tt)
 int pending_server_close, pending_client_close;
 
 void server_closed_callback(tp_stack_t *tt, tp_client_t *client,
-                            tport_t *tp, msg_t *msg, int error)
+                           tport_t *tp, msg_t *msg, int error)
 {
   assert(msg == NULL);
   assert(client == NULL);
@@ -809,7 +809,7 @@ void server_closed_callback(tp_stack_t *tt, tp_client_t *client,
 }
 
 void client_closed_callback(tp_stack_t *tt, tp_client_t *client,
-                            tport_t *tp, msg_t *msg, int error)
+                           tport_t *tp, msg_t *msg, int error)
 {
   assert(msg == NULL);
   assert(client == NULL);
@@ -1232,6 +1232,26 @@ static int sctp_test(tp_test_t *tt)
   END();
 }
 
+struct called {
+  int n, error, pending, released;
+};
+
+static
+void tls_error_callback(tp_stack_t *tt, tp_client_t *client,
+                       tport_t *tp, msg_t *msg, int error)
+{
+  struct called *called = (struct called *)client;
+
+  tt->tt_status = -1;
+
+  called->n++, called->error = error;
+
+  if (called->pending) {
+    called->released = tport_release(tp, called->pending, msg, NULL, client, 0);
+    called->pending = 0;
+  }
+}
+
 static int tls_test(tp_test_t *tt)
 {
   BEGIN(); 
@@ -1242,6 +1262,7 @@ static int tls_test(tp_test_t *tt)
   int i;
   char ident[16];
   tport_t *tp, *tp0;
+  struct called called[1] = {{ 0, 0, 0, 0 }};
 
   TEST_S(dst->tpn_proto, "tls");
 
@@ -1249,9 +1270,21 @@ static int tls_test(tp_test_t *tt)
   TEST_1(!new_test_msg(tt, &msg, "tls-first", 1, 1024));
   TEST_1(tp = tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
   TEST_1(tp0 = tport_ref(tp));
+  TEST_1(called->pending = tport_pend(tp, msg, tls_error_callback, (tp_client_t *)called));
+
+  i = tport_test_run(tt, 5);
   msg_destroy(msg);
 
-  TEST(tport_test_run(tt, 5), 1);
+  if (i < 0) {
+    if (called->n) {
+      TEST(called->released, 0);
+      puts("test_tport: skipping TLS tests");
+      tport_unref(tp0);
+      return 0;
+    }
+  }
+
+  TEST(i, 1);
 
   TEST_1(!check_msg(tt, tt->tt_rmsg, "tls-first"));
   msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
index bbad7a9b83c9a8fb604f72d2d788b515d90cc55c..6ff369adf279cd27e2d7824c29b9a80df1eceb2e 100644 (file)
@@ -405,7 +405,8 @@ static int
   tport_base_wakeup(tport_t *self, int events),
   tport_connected(su_root_magic_t *m, su_wait_t *w, tport_t *self),
   tport_resolve(tport_t *self, msg_t *msg, tp_name_t const *tpn),
-  tport_send_error(tport_t *, msg_t *, tp_name_t const *),
+  tport_send_error(tport_t *, msg_t *, tp_name_t const *, char const *who),
+  tport_send_fatal(tport_t *, msg_t *, tp_name_t const *, char const *who),
   tport_queue(tport_t *self, msg_t *msg),
   tport_queue_rest(tport_t *self, msg_t *msg, msg_iovec_t iov[], size_t iovused),
   tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error),
@@ -469,7 +470,12 @@ msg_t *tport_destroy_alloc(tp_stack_t *stack, int flags,
 /** Name for "any" transport. @internal */
 static char const tpn_any[] = "*";
 
-/** Create the master transport. 
+/** Create the master transport.
+ *
+ * Master transport object is used to bind the protocol using transport with
+ * actual transport objects corresponding to TCP, UDP, etc. 
+ *
+ * @sa tport_tbind()
  *
  * @TAGS
  * TPTAG_LOG(), TPTAG_DUMP(), tags used with tport_set_params(), especially
@@ -2985,6 +2991,7 @@ void tport_deliver(tport_t *self,
 
   ref = tport_incref(self);
 
+
   if (self->tp_pri->pri_vtable->vtp_deliver) {
     self->tp_pri->pri_vtable->vtp_deliver(self, msg, now);
   }
@@ -3405,28 +3412,28 @@ int tport_send_msg(tport_t *self, msg_t *msg,
       if (tport_is_connection_oriented(self)) {
        iov[i].mv_len -= (su_ioveclen_t)(n - total);
        iov[i].mv_base = (char *)iov[i].mv_base + (n - total);
-       if (tport_queue_rest(self, msg, &iov[i], iovused - i) >= 0)
+       if (tport_queue_rest(self, msg, &iov[i], iovused - i) < 0)
+         return tport_send_fatal(self, msg, tpn, "tport_queue_rest");
+       else
          return 0;
       }
       else {
        char const *comp = tpn->tpn_comp;
        
-       SU_DEBUG_1(("tport(%p): send truncated for %s/%s:%s%s%s\n", 
-                   (void *)self, tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port,
+       SU_DEBUG_1(("%s(%p): send truncated for %s/%s:%s%s%s\n", 
+                   "tport_vsend", (void *)self, tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port,
                    comp ? ";comp=" : "", comp ? comp : ""));
 
-       su_seterrno(EIO);
+       msg_set_errno(msg, EIO);
+       return /* tport_send_fatal(self, msg, tpn, "tport_send") */ -1;
       }
-
-      return -1;
     }
+
     total += iov[i].mv_len;
   }
 
   /* We have sent a complete message */
-
-  self->tp_slogged = NULL;
-  self->tp_stats.sent_msgs ++;
+  tport_sent_message(self, msg, 0);
 
   if (!tport_is_secondary(self))
     return 0;
@@ -3465,9 +3472,9 @@ ssize_t tport_vsend(tport_t *self,
     return 0;
 
   if (n == -1) 
-    return tport_send_error(self, msg, tpn);
+    return tport_send_error(self, msg, tpn, "tport_vsend");
 
-  self->tp_stats.sent_bytes += n;
+  tport_sent_bytes(self, n, n);        /* Sigcomp will decrease on_line accodingly */
 
   if (n > 0 && self->tp_master->mr_dump_file)
     tport_dump_iovec(self, msg, n, iov, iovused, "sent", "to");
@@ -3481,8 +3488,8 @@ ssize_t tport_vsend(tport_t *self,
     if (tpn == NULL || tport_is_connection_oriented(self))
       tpn = self->tp_name;
     
-    SU_DEBUG_7(("tport_vsend(%p): "MOD_ZU" bytes of "MOD_ZU" to %s/%s:%s%s\n", 
-               (void *)self, n, m, tpn->tpn_proto, tpn->tpn_host, 
+    SU_DEBUG_7(("%s(%p): "MOD_ZU" bytes of "MOD_ZU" to %s/%s:%s%s\n", 
+               "tport_vsend", (void *)self, n, m, tpn->tpn_proto, tpn->tpn_host, 
                tpn->tpn_port, 
                (ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : ""));
   }
@@ -3491,45 +3498,56 @@ ssize_t tport_vsend(tport_t *self,
 }
 
 static
-int tport_send_error(tport_t *self, msg_t *msg, 
-                    tp_name_t const *tpn)
+int tport_send_error(tport_t *self, msg_t *msg, tp_name_t const *tpn,
+                    char const *who)
 {
   int error = su_errno();
-  su_addrinfo_t *ai = msg_addrinfo(msg);
-  char const *comp = (ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : "";
 
   if (error == EPIPE) {
     /*Xyzzy*/
   }
 
   if (su_is_blocking(error)) {
-    SU_DEBUG_5(("tport_vsend(%p): %s with (s=%d %s/%s:%s%s)\n", 
-                               (void *)self, "EAGAIN", (int)self->tp_socket, 
+    su_addrinfo_t *ai = msg_addrinfo(msg);
+    char const *comp = (ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : "";
+    SU_DEBUG_5(("%s(%p): %s with (s=%d %s/%s:%s%s)\n", 
+               who, (void *)self, "EAGAIN", (int)self->tp_socket, 
                tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp));
     return 0;
   }
 
   msg_set_errno(msg, error);
 
+  return tport_send_fatal(self, msg, tpn, who);
+}
+
+static
+int tport_send_fatal(tport_t *self, msg_t *msg, tp_name_t const *tpn,
+                    char const *who)
+{
+  su_addrinfo_t *ai = msg_addrinfo(msg);
+  char const *comp = (ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : "";
+
+  int error = msg_errno(msg);
+  
   if (self->tp_addrinfo->ai_family == AF_INET) {
-    SU_DEBUG_3(("tport_vsend(%p): %s with (s=%d %s/%s:%s%s)\n", 
-               (void *)self, su_strerror(error), (int)self->tp_socket, 
+    SU_DEBUG_3(("%s(%p): %s with (s=%d %s/%s:%s%s)\n", 
+               who, (void *)self, su_strerror(error), (int)self->tp_socket, 
                tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp));
   }
 #if SU_HAVE_IN6
   else if (self->tp_addrinfo->ai_family == AF_INET6) {
     su_sockaddr_t const *su = (su_sockaddr_t const *)ai->ai_addr;
-    SU_DEBUG_3(("tport_vsend(%p): %s with "
-               "(s=%d, IP6=%s/%s:%s%s (scope=%i) addrlen=%u)\n", 
-               (void *)self, su_strerror(error), (int)self->tp_socket, 
+    SU_DEBUG_3(("%s(%p): %s with (s=%d, IP6=%s/%s:%s%s"
+               " (scope=%i) addrlen=%u)\n",
+               who, (void *)self, su_strerror(error), (int)self->tp_socket, 
                tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp,
                su->su_scope_id, (unsigned)ai->ai_addrlen));
   }
 #endif
   else {
-    SU_DEBUG_3(("\ttport_vsend(%p): %s with "
-               "(s=%d, AF=%u addrlen=%u)%s\n", 
-               (void *)self, su_strerror(error), 
+    SU_DEBUG_3(("%s(%p): %s with (s=%d, AF=%u addrlen=%u)%s\n", 
+               who, (void *)self, su_strerror(error), 
                (int)self->tp_socket, ai->ai_family, (unsigned)ai->ai_addrlen, comp));
   }
 
@@ -3856,9 +3874,8 @@ void tport_send_queue(tport_t *self)
     /* We have sent a complete message */
     
     self->tp_queue[qhead] = NULL;
+    tport_sent_message(self, msg, 0);
     msg_destroy(msg);
-    self->tp_stats.sent_msgs++;
-    self->tp_slogged = NULL;
 
     qhead = (qhead + 1) % N;
   }
@@ -4403,7 +4420,7 @@ tport_t *tport_by_name(tport_t const *self, tp_name_t const *tpn)
       su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in6);
       su->su_family = AF_INET6;
     }
-    else if (host_is_ip_address(host)) {
+    else if (host_is_ip6_address(host)) {
       su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in6);
       su->su_family = AF_INET6;
     }
@@ -4613,27 +4630,10 @@ int tport_name_by_url(su_home_t *home,
 /** Check if transport named is already resolved */
 int tport_name_is_resolved(tp_name_t const *tpn)
 {
-  size_t n;
-
   if (!tpn->tpn_host)
     return 0;
-  
-  if (tpn->tpn_host[0] == '[')
-    return 1;
-
-  n = strspn(tpn->tpn_host, ".0123456789");
 
-  if (tpn->tpn_host[n] == '\0')
-    return 1;
-
-  if (strchr(tpn->tpn_host, ':')) {
-    n = strspn(tpn->tpn_host, ":0123456789abcdefABCDEF");
-
-    if (tpn->tpn_host[n] == '\0')
-      return 1;
-  }
-
-  return 0;
+  return host_is_ip_address(tpn->tpn_host);
 }
 
 /** Duplicate name.
@@ -4742,3 +4742,79 @@ char *tport_hostport(char buf[], isize_t bufsize,
 
   return buf;
 }
+
+/** @internal Update receive statistics. */
+void tport_recv_bytes(tport_t *self, ssize_t bytes, ssize_t on_line)
+{
+  self->tp_stats.recv_bytes += bytes;
+  self->tp_stats.recv_on_line += on_line;
+
+  if (self != self->tp_pri->pri_primary) {
+    self = self->tp_pri->pri_primary;
+    self->tp_stats.recv_bytes += bytes;
+    self->tp_stats.recv_on_line += on_line;
+  }
+  self = self->tp_master->mr_master;
+  self->tp_stats.recv_bytes += bytes;
+  self->tp_stats.recv_on_line += on_line;
+}
+
+/** @internal Update message-based receive statistics. */
+void tport_recv_message(tport_t *self, msg_t *msg, int error)
+{
+  error = error != 0;
+
+  self->tp_stats.recv_msgs++;
+  self->tp_stats.recv_errors += error;
+
+  if (self != self->tp_pri->pri_primary) {
+    self = self->tp_pri->pri_primary;
+    self->tp_stats.recv_msgs++;
+    self->tp_stats.recv_errors += error;
+  }
+
+  self = self->tp_master->mr_master;
+
+  self->tp_stats.recv_msgs++;
+  self->tp_stats.recv_errors += error;
+}
+
+/** @internal Update send statistics. */
+void tport_sent_bytes(tport_t *self, ssize_t bytes, ssize_t on_line)
+{
+  self->tp_stats.sent_bytes += bytes;
+  self->tp_stats.sent_on_line += on_line;
+
+  if (self != self->tp_pri->pri_primary) {
+    self = self->tp_pri->pri_primary;
+    self->tp_stats.sent_bytes += bytes;
+    self->tp_stats.sent_on_line += on_line;
+  }
+
+  self = self->tp_master->mr_master;
+  self->tp_stats.sent_bytes += bytes;
+  self->tp_stats.sent_on_line += on_line;
+}
+
+/** @internal Update message-based send statistics. */
+void tport_sent_message(tport_t *self, msg_t *msg, int error)
+{
+  self->tp_slogged = NULL;
+
+  error = error != 0;
+
+  self->tp_stats.sent_msgs++;
+  self->tp_stats.sent_errors += error;
+
+  if (self != self->tp_pri->pri_primary) {
+    self = self->tp_pri->pri_primary;
+    self->tp_stats.sent_msgs++;
+    self->tp_stats.sent_errors += error;
+  }
+
+  self = self->tp_master->mr_master;
+
+  self->tp_stats.sent_msgs++;
+  self->tp_stats.sent_errors += error;
+
+}
index a17e4854641c2ab6bf86ee9027b12dff8ddc998f..cf3b2205d07919cb7573e84de4b847c08cfaace6 100644 (file)
@@ -221,8 +221,8 @@ struct tport_s {
   /* ==== Statistics  ===================================================== */
   
   struct {
-    uint64_t sent_bytes, sent_on_line, recv_bytes, recv_on_line;
-    uint64_t sent_msgs, recv_msgs;
+    uint64_t sent_msgs, sent_errors, sent_bytes, sent_on_line;
+    uint64_t recv_msgs, recv_errors, recv_bytes, recv_on_line;
   } tp_stats;
 };
 
@@ -528,6 +528,12 @@ int tport_recv_stun_dgram(tport_t const *self, msg_t **in_out_msg,
 int tport_stun_server_add_socket(tport_t *tp);
 int tport_stun_server_remove_socket(tport_t *tp);
 
+void tport_recv_bytes(tport_t *self, ssize_t bytes, ssize_t on_line);
+void tport_recv_message(tport_t *self, msg_t *msg, int error);
+
+void tport_sent_bytes(tport_t *self, ssize_t bytes, ssize_t on_line);
+void tport_sent_message(tport_t *self, msg_t *msg, int error);
+
 /* ---------------------------------------------------------------------- */
 /* Compressor plugin */
 extern tport_comp_vtable_t const *tport_comp_vtable;
index befab5d3ce9be549b50733202b51dc89e3428017..791cd39ca7048dc27415f2224ade9b6a71ec37be 100644 (file)
@@ -34,6 +34,7 @@
 #include "tport_internal.h"
 
 #include <string.h>
+#include <sofia-sip/string0.h>
 
 tport_comp_vtable_t const *tport_comp_vtable = NULL;
 
index 8c06dee2517d83f05321f3681cbd7058f6a4939b..5c8f6bdeaad884612195e125cb7fe063f8fde5a6 100644 (file)
@@ -242,6 +242,8 @@ int tport_recv_sctp(tport_t *self)
     return 0;    /* End of stream */
   }
 
+  tport_recv_bytes(self, n, n);
+
   veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
   if (veclen < 0)
     return -1;
index 52ce9716758b160f047cf9ed5647062ef749cbd3..26ccf4661a6409d447a8f4ca9d38a1fde174e3e2 100644 (file)
@@ -281,6 +281,8 @@ int tport_recv_stream(tport_t *self)
 
     N -= n, self->tp_ping += n;
 
+    tport_recv_bytes(self, n, n);
+
     if (N == 0) {
       /* outbound-10 section 3.5.1  - send pong */
       if (self->tp_ping >= 4)
@@ -305,6 +307,8 @@ int tport_recv_stream(tport_t *self)
 
   assert(n <= N);
 
+  tport_recv_bytes(self, n, n);
+
   /* Check if message contains only whitespace */
   /* This can happen if multiple PINGs are received at once */
   if (initial) {
index 2f9860dac670d0b395ba24eb559e7cedc56b84a3..d4abd7c8c8ce3f8ff815f3fcb167ada827e335f1 100644 (file)
@@ -46,6 +46,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <string.h>
+#include <sofia-sip/string0.h>
 
 /* ---------------------------------------------------------------------- */
 /* TLS */
index db5288369fdf4a2640dbe4d0b3ce0d50f13bc7e3..74e15b38a3fd3fa3fcfc6b1f338ebdbd9ddb0e96 100644 (file)
@@ -293,6 +293,8 @@ int tport_recv_dgram(tport_t *self)
     return 0;
   }
 
+  tport_recv_bytes(self, n, n);
+
   SU_CANONIZE_SOCKADDR(from);
 
   if (self->tp_master->mr_dump_file)
index 35fcd32168d0ec6121759b572c6749396e46f41c..ef4a339853711721c7018ce7e8b0fa29ab577c7e 100644 (file)
@@ -204,7 +204,7 @@ SOFIAPUBFUN char *url_unescape(char *d, char const *s);
  * @endcode
  */
 #define URL_INIT_AS(type)  \
-{ { 0 }, url_##type, 0, url_##type != url_any ? #type : "*" }
+  { "\0", url_##type, 0, url_##type != url_any ? #type : "*" }
 
 /** Init a url structure as given type */
 SOFIAPUBFUN void url_init(url_t *url, enum url_type_e type);
index a1e3f54693a625057cb1f05c106c5ce59e44a79e..76b371b99960e60f5f4102af3338dbbc3ff86aba 100644 (file)
@@ -802,8 +802,8 @@ int url_d(url_t *url, char *s)
   if (s && !url_canonize(s, s, SIZE_MAX, 
                         /* Allow all URI characters but ? */
                         /* Allow unescaped /;?@, - but do not convert */
-                        (unsigned)(SYN33('/') | SYN33(';') | SYN33('=') | SYN33('@') |
-                        SYN33(',')),
+                        SYN33('/') | SYN33(';') | SYN33('=') | SYN33('@') |
+                        SYN33(','),
                         /* Convert escaped :&+$ to unescaped */
                         ":&+$"))
     return -1;
@@ -812,7 +812,7 @@ int url_d(url_t *url, char *s)
   if (s && !url_canonize(s, s, SIZE_MAX,
                         /* Allow all URI characters but ? */
                         /* Allow unescaped ;=@, - but do not convert */
-                        (unsigned)(SYN33(';') | SYN33('=') | SYN33('@') | SYN33(',')),
+                        SYN33(';') | SYN33('=') | SYN33('@') | SYN33(','),
                         /* Convert escaped /:&+$ to unescaped */
                         "/:&+$"))
     return -1;
index 771052c799029ffcf900481a3355a4f2b6a83585..b9061ba93c865888131b507c6518f11c386f81ea 100644 (file)
@@ -1,6 +1,9 @@
 # common Makefile targets for libsofia-sip-ua(-glib) modules
 # ----------------------------------------------------------
 
+sofiasrcdir = ${top_srcdir}/libsofia-sip-ua
+sofiabuilddir = ${top_builddir}/libsofia-sip-ua
+
 AM_CFLAGS = $(CWFLAG) $(SOFIA_COVERAGE) $(SOFIA_CFLAGS) $(openssl_CFLAGS)
 
 SOFIA_COVERAGE = $(COVERAGE_FLAGS)
@@ -19,7 +22,7 @@ clean-built-sources:
 
 # rules for building tag files
 
-TAG_AWK=$(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+TAG_AWK=${sofiasrcdir}/su/tag_dll.awk
 
 *_tag_ref.c: $(TAG_AWK)
 
@@ -36,25 +39,25 @@ _tag.c_tag_ref.c:
        cd $(@D) && $(MAKE) $(@F)
 
 INTERNAL_INCLUDES = \
-       -I$(srcdir)/../features -I../features \
-       -I$(srcdir)/../ipt -I../ipt \
-       -I$(srcdir)/../iptsec -I../iptsec \
-       -I$(srcdir)/../bnf -I../bnf \
-       -I$(srcdir)/../http -I../http \
-       -I$(srcdir)/../msg -I../msg \
-       -I$(srcdir)/../nth -I../nth \
-       -I$(srcdir)/../nta -I../nta \
-       -I$(srcdir)/../nea -I../nea \
-       -I$(srcdir)/../nua -I../nua \
-       -I$(srcdir)/../soa -I../soa \
-       -I$(srcdir)/../sdp -I../sdp \
-       -I$(srcdir)/../sip -I../sip \
-       -I$(srcdir)/../soa -I../soa \
-       -I$(srcdir)/../sresolv -I../sresolv \
-       -I$(srcdir)/../tport -I../tport \
-       -I$(srcdir)/../stun -I../stun \
-       -I$(srcdir)/../url -I../url \
-       -I$(srcdir)/../su -I../su
+    -I${sofiasrcdir}/features -I${sofiabuilddir}/features \
+    -I${sofiasrcdir}/ipt -I${sofiabuilddir}/ipt \
+    -I${sofiasrcdir}/iptsec -I${sofiabuilddir}/iptsec \
+    -I${sofiasrcdir}/bnf -I${sofiabuilddir}/bnf \
+    -I${sofiasrcdir}/http -I${sofiabuilddir}/http \
+    -I${sofiasrcdir}/msg -I${sofiabuilddir}/msg \
+    -I${sofiasrcdir}/nth -I${sofiabuilddir}/nth \
+    -I${sofiasrcdir}/nta -I${sofiabuilddir}/nta \
+    -I${sofiasrcdir}/nea -I${sofiabuilddir}/nea \
+    -I${sofiasrcdir}/nua -I${sofiabuilddir}/nua \
+    -I${sofiasrcdir}/soa -I${sofiabuilddir}/soa \
+    -I${sofiasrcdir}/sdp -I${sofiabuilddir}/sdp \
+    -I${sofiasrcdir}/sip -I${sofiabuilddir}/sip \
+    -I${sofiasrcdir}/soa -I${sofiabuilddir}/soa \
+    -I${sofiasrcdir}/sresolv -I${sofiabuilddir}/sresolv \
+    -I${sofiasrcdir}/tport -I${sofiabuilddir}/tport \
+    -I${sofiasrcdir}/stun -I${sofiabuilddir}/stun \
+    -I${sofiasrcdir}/url -I${sofiabuilddir}/url \
+    -I${sofiasrcdir}/su -I${sofiabuilddir}/su
 
 PHONY = built-sources clean-built-sources
 
@@ -63,4 +66,3 @@ include $(top_srcdir)/rules/valcheck.am
 if HAVE_LCOV
 include $(top_srcdir)/rules/lcov.am
 endif
-
diff --git a/libs/sofia-sip/tests/Makefile.am b/libs/sofia-sip/tests/Makefile.am
new file mode 100644 (file)
index 0000000..fedc633
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# Tests using check
+#
+
+EXTRA_DIST = check_nua.c
+
+TESTS =
+check_PROGRAMS =
+
+include $(top_srcdir)/rules/sofia.am
+
+INCLUDES = ${INTERNAL_INCLUDES}
+
+AM_CFLAGS += @CHECK_CFLAGS@
+
+if HAVE_CHECK
+TESTS += check_sofia
+check_PROGRAMS += check_sofia
+
+check_sofia_SOURCES = check_sofia.c check_sofia.h \
+       suite_for_nua.c
+
+check_sofia_LDADD = \
+       ${sofiabuilddir}/nua/libtestnua.la \
+       ${sofiabuilddir}/nua/libtestproxy.la \
+       ${sofiabuilddir}/nua/libtestnat.la \
+       ${sofiabuilddir}/libsofia-sip-ua.la @CHECK_LIBS@
+endif
diff --git a/libs/sofia-sip/tests/check_sofia.c b/libs/sofia-sip/tests/check_sofia.c
new file mode 100644 (file)
index 0000000..f8fd707
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE check_sofia.c
+ *
+ * @brief Check-driven tester for Sofia SIP User Agent library
+ *
+ * @author Pekka Pessi <Pekka.Pessi@nokia.com>
+ *
+ * @copyright (C) 2007 Nokia Corporation.
+ */
+
+#include "config.h"
+
+#include "check_sofia.h"
+
+#include <stdlib.h>
+
+/* Globals used by <sofia-sip/tstdef.h> */
+int tstflags;                  
+char const name[] = "check_sofia";
+
+int main(int argc, char *argv[])
+{
+  int failed = 0;
+
+  Suite *suite;
+  SRunner *runner;
+
+  suite = suite_for_nua();
+  runner = srunner_create(suite);
+
+  srunner_set_xml(runner, "/tmp/result.xml");
+  srunner_run_all(runner, CK_NORMAL);
+
+  failed = srunner_ntests_failed(runner);
+  srunner_free(runner);
+
+  exit(failed ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
diff --git a/libs/sofia-sip/tests/check_sofia.h b/libs/sofia-sip/tests/check_sofia.h
new file mode 100644 (file)
index 0000000..d641347
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CHECK_SOFIA_H
+
+#include <check.h>
+Suite *suite_for_nua(void);
+
+#endif
+
diff --git a/libs/sofia-sip/tests/suite_for_nua.c b/libs/sofia-sip/tests/suite_for_nua.c
new file mode 100644 (file)
index 0000000..d0655a2
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE check_sofia.c
+ *
+ * @brief Check-driven tester for Sofia SIP User Agent library
+ *
+ * @author Pekka Pessi <Pekka.Pessi@nokia.com>
+ *
+ * @copyright (C) 2007 Nokia Corporation.
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include "check_sofia.h"
+
+int print_headings = 0;
+struct context ctx[1] = {{{ SU_HOME_INIT(ctx) }}};
+
+SOFIAPUBVAR su_log_t nua_log[];
+SOFIAPUBVAR su_log_t soa_log[];
+SOFIAPUBVAR su_log_t nea_log[];
+SOFIAPUBVAR su_log_t nta_log[];
+SOFIAPUBVAR su_log_t tport_log[];
+SOFIAPUBVAR su_log_t su_log_default[];
+
+static void init_context(void)
+{
+  int level = 1;
+
+  su_init();
+  memset(ctx, 0, sizeof ctx);
+  su_home_init(ctx->home);
+  endpoint_init(ctx, &ctx->a, 'a');
+  endpoint_init(ctx, &ctx->b, 'b');
+  endpoint_init(ctx, &ctx->c, 'c');
+
+  su_log_soft_set_level(nua_log, level);
+  su_log_soft_set_level(soa_log, level);
+  su_log_soft_set_level(su_log_default, level);
+  su_log_soft_set_level(nea_log, level);
+  su_log_soft_set_level(nta_log, level);
+  su_log_soft_set_level(tport_log, level);
+}
+
+static void clean_context(void)
+{
+  test_deinit(ctx);
+  su_home_deinit(ctx->home);
+  memset(ctx, 0, sizeof ctx);
+  su_deinit();
+}
+
+/* Each testcase is run in different process */
+
+START_TEST(check_api) { fail_if(test_nua_api_errors(ctx)); } END_TEST
+START_TEST(check_tag_filter) { fail_if(test_tag_filter()); } END_TEST
+START_TEST(check_params) { fail_if(test_nua_params(ctx)); } END_TEST
+START_TEST(check_destroy) { fail_if(test_nua_destroy(ctx)); } END_TEST
+START_TEST(check_stack_errors) { fail_if(test_stack_errors(ctx)); } END_TEST
+
+START_TEST(without_proxy)
+{
+  fail_if(test_nua_init(ctx, 0, NULL, 0, TAG_END()));
+  fail_if(test_register(ctx));
+  fail_if(test_connectivity(ctx));
+  fail_if(test_basic_call(ctx));
+  fail_if(test_rejects(ctx));
+  fail_if(test_call_cancel(ctx));
+  fail_if(test_call_destroy(ctx));
+  fail_if(test_early_bye(ctx));
+  fail_if(test_offer_answer(ctx));
+  fail_if(test_reinvites(ctx));
+  fail_if(test_session_timer(ctx));
+  fail_if(test_refer(ctx));
+  fail_if(test_100rel(ctx));
+  fail_if(test_simple(ctx));
+  fail_if(test_events(ctx));
+  fail_if(test_extension(ctx));
+  fail_if(test_unregister(ctx));
+  fail_if(test_deinit(ctx));
+}
+END_TEST
+
+START_TEST(with_proxy)
+{
+  fail_if(test_nua_init(ctx, 1, NULL, 0, TAG_END()));
+  fail_if(test_register(ctx));
+  fail_if(test_connectivity(ctx));
+  fail_if(test_basic_call(ctx));
+  fail_if(test_rejects(ctx));
+  fail_if(test_call_cancel(ctx));
+  fail_if(test_call_destroy(ctx));
+  fail_if(test_early_bye(ctx));
+  fail_if(test_offer_answer(ctx));
+  fail_if(test_reinvites(ctx));
+  fail_if(test_session_timer(ctx));
+  fail_if(test_refer(ctx));
+  fail_if(test_100rel(ctx));
+  fail_if(test_simple(ctx));
+  fail_if(test_events(ctx));
+  fail_if(test_extension(ctx));
+  fail_if(test_unregister(ctx));
+  fail_if(test_deinit(ctx));
+}
+END_TEST
+
+START_TEST(with_proxy_and_nat)
+{
+  fail_if(test_nua_init(ctx, 1, NULL, 1, TAG_END()));
+  fail_if(test_register(ctx));
+  fail_if(test_connectivity(ctx));
+  fail_if(test_nat_timeout(ctx));
+  fail_if(test_basic_call(ctx));
+  fail_if(test_rejects(ctx));
+  fail_if(test_call_cancel(ctx));
+  fail_if(test_call_destroy(ctx));
+  fail_if(test_early_bye(ctx));
+  fail_if(test_offer_answer(ctx));
+  fail_if(test_reinvites(ctx));
+  fail_if(test_session_timer(ctx));
+  fail_if(test_refer(ctx));
+  fail_if(test_100rel(ctx));
+  fail_if(test_simple(ctx));
+  fail_if(test_events(ctx));
+  fail_if(test_extension(ctx));
+  fail_if(test_unregister(ctx));
+  fail_if(test_deinit(ctx));
+}
+END_TEST
+
+Suite *suite_for_nua(void)
+{
+  Suite *suite = suite_create("nua");
+  TCase *tc;
+
+  tc = tcase_create("api");
+  tcase_add_unchecked_fixture(tc, init_context, clean_context);
+  tcase_add_test(tc, check_api);
+  tcase_add_test(tc, check_tag_filter);
+  tcase_add_test(tc, check_params);
+  tcase_add_test(tc, check_destroy);
+  tcase_add_test(tc, check_stack_errors);
+  tcase_set_timeout(tc, 5);
+  suite_add_tcase(suite, tc);
+
+  tc = tcase_create("without-proxy");
+  tcase_add_unchecked_fixture(tc, init_context, clean_context);
+  tcase_add_test(tc, without_proxy);
+  tcase_set_timeout(tc, 60);
+  suite_add_tcase(suite, tc);
+
+  tc = tcase_create("with-proxy");
+  tcase_add_unchecked_fixture(tc, init_context, clean_context);
+  tcase_add_test(tc, with_proxy);
+  tcase_set_timeout(tc, 120);
+  suite_add_tcase(suite, tc);
+
+  tc = tcase_create("with-proxy-and-nat");
+  tcase_add_unchecked_fixture(tc, init_context, clean_context);
+  tcase_add_test(tc, with_proxy_and_nat);
+  tcase_set_timeout(tc, 120);
+  suite_add_tcase(suite, tc);
+
+  return suite;
+}
index c421299a2a1d4d9e0c2c33d33b35b90e9ba1c038..124a17e34a46bb4d530141320b2e3ea293c64fdf 100644 (file)
 # ----------------------------------------------------------------------
 # Header paths
 
-sofiasrc=$(top_srcdir)/libsofia-sip-ua
-sofiabld=$(top_builddir)/libsofia-sip-ua
-
-INCLUDES =     -I$(sofiasrc)/features -I$(sofiabld)/features \
-               -I$(sofiasrc)/ipt -I$(sofiabld)/ipt \
-               -I$(sofiasrc)/iptsec -I$(sofiabld)/iptsec \
-               -I$(sofiasrc)/bnf -I$(sofiabld)/bnf \
-               -I$(sofiasrc)/http -I$(sofiabld)/http \
-               -I$(sofiasrc)/msg -I$(sofiabld)/msg \
-               -I$(sofiasrc)/nth -I$(sofiabld)/nth \
-               -I$(sofiasrc)/nta -I$(sofiabld)/nta \
-               -I$(sofiasrc)/nea -I$(sofiabld)/nea \
-               -I$(sofiasrc)/nua -I$(sofiabld)/nua \
-               -I$(sofiasrc)/soa -I$(sofiabld)/soa \
-               -I$(sofiasrc)/sdp -I$(sofiabld)/sdp \
-               -I$(sofiasrc)/sip -I$(sofiabld)/sip \
-               -I$(sofiasrc)/soa -I$(sofiabld)/soa \
-               -I$(sofiasrc)/sresolv -I$(sofiabld)/sresolv \
-               -I$(sofiasrc)/tport -I$(sofiabld)/tport \
-               -I$(sofiasrc)/stun -I$(sofiabld)/stun \
-               -I$(sofiasrc)/url -I$(sofiabld)/url \
-               -I$(sofiasrc)/su -I$(sofiabld)/su
-
-
-AM_CFLAGS =            $(SOFIA_CFLAGS)
+include $(top_srcdir)/rules/sofia.am
+
+INCLUDES =     ${INTERNAL_INCLUDES}
 
 # ----------------------------------------------------------------------
 # Build targets