[Freeswitch-svn] [commit] r11844 - in freeswitch/trunk/libs/sofia-sip: . libsofia-sip-ua/nua libsofia-sip-ua/sresolv

FreeSWITCH SVN mikej at freeswitch.org
Wed Feb 11 09:12:33 PST 2009


Author: mikej
Date: Wed Feb 11 11:12:33 2009
New Revision: 11844

Log:
Fri Jan 23 11:13:41 CST 2009  Pekka Pessi <first.last at nokia.com>
  * sresolv: caching SRES_RECORD_ERR in case a CNAME is returned, too
  
  Tracing the CNAMEs when doing cache lookups.



Added:
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c
Modified:
   freeswitch/trunk/libs/sofia-sip/.update
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c

Modified: freeswitch/trunk/libs/sofia-sip/.update
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/.update	(original)
+++ freeswitch/trunk/libs/sofia-sip/.update	Wed Feb 11 11:12:33 2009
@@ -1 +1 @@
-Wed Feb 11 11:08:29 CST 2009
+Wed Feb 11 11:12:10 CST 2009

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c	Wed Feb 11 11:12:33 2009
@@ -0,0 +1,522 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at 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_events.c
+ *
+ * @brief NUA module tests for SIP events
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @copyright (C) 2008 Nokia Corporation.
+ */
+
+#include "config.h"
+
+#include "check_nua.h"
+
+#include "test_s2.h"
+
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/soa.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_string.h>
+#include <sofia-sip/su_tag_io.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* define XXX as 1 in order to see all failing test cases */
+#ifndef XXX
+#define XXX (0)
+#endif
+
+/* ====================================================================== */
+
+static nua_t *nua;
+static soa_session_t *soa = NULL;
+static struct dialog *dialog = NULL;
+
+#define CRLF "\r\n"
+
+void s2_dialog_setup(void)
+{
+  nua = s2_nua_setup("simple",
+		     SIPTAG_ORGANIZATION_STR("Pussy Galore's Flying Circus"),
+                     NUTAG_OUTBOUND("no-options-keepalive, no-validate"),
+		     TAG_END());
+
+  soa = soa_create(NULL, s2->root, NULL);
+
+  fail_if(!soa);
+
+  soa_set_params(soa,
+		 SOATAG_USER_SDP_STR("m=audio 5008 RTP/AVP 8 0" CRLF
+				     "m=video 5010 RTP/AVP 34" CRLF),
+		 TAG_END());
+
+  dialog = su_home_new(sizeof *dialog); fail_if(!dialog);
+
+  s2_register_setup();
+}
+
+void s2_dialog_teardown(void)
+{
+  s2_teardown_started("simple");
+
+  s2_register_teardown();
+
+  nua_shutdown(nua);
+
+  fail_unless(s2_check_event(nua_r_shutdown, 200));
+
+  s2_nua_teardown();
+}
+
+
+static char const presence_open[] =
+    "<?xml version='1.0' encoding='UTF-8'?>\n"
+    "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+    "   entity='pres:bob at example.org'>\n"
+    "  <tuple id='ksac9udshce'>\n"
+    "    <status><basic>open</basic></status>\n"
+    "    <contact priority='1.0'>sip:bob at example.org</contact>\n"
+    "  </tuple>\n"
+    "</presence>\n";
+
+static char const presence_closed[] =
+    "<?xml version='1.0' encoding='UTF-8'?>\n"
+    "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+    "   entity='pres:bob at example.org'>\n"
+    "  <tuple id='ksac9udshce'>\n"
+    "    <status><basic>closed</basic></status>\n"
+    "  </tuple>\n"
+    "</presence>\n";
+
+static char const *event_type = "presence";
+static char const *event_mime_type = "application/pidf+xml";
+static char const *event_state = presence_open;
+static char const *subscription_state = "active;expires=600";
+
+static struct event *
+respond_to_subscribe(struct message *subscribe,
+		     nua_event_t expect_event,
+		     enum nua_substate expect_substate,
+		     int status, char const *phrase,
+		     tag_type_t tag, tag_value_t value, ...)
+{
+  struct event *event;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+  s2_respond_to(subscribe, dialog, status, phrase,
+		ta_tags(ta));
+  ta_end(ta);
+
+  event = s2_wait_for_event(expect_event, status); fail_if(!event);
+  fail_unless(s2_check_substate(event, expect_substate));
+  return event;
+}
+
+static struct event *
+notify_to_nua(enum nua_substate expect_substate,
+	      tag_type_t tag, tag_value_t value, ...)
+{
+  struct event *event;
+  struct message *response;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+  fail_if(s2_request_to(dialog, SIP_METHOD_NOTIFY, NULL,
+			SIPTAG_CONTENT_TYPE_STR(event_mime_type),
+			SIPTAG_PAYLOAD_STR(event_state),
+			ta_tags(ta)));
+  ta_end(ta);
+
+  response = s2_wait_for_response(200, SIP_METHOD_NOTIFY);
+  fail_if(!response);
+  s2_free_message(response);
+
+  event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event);
+  fail_unless(s2_check_substate(event, expect_substate));
+
+  return event;
+}
+
+static int send_notify_before_response = 0;
+
+static struct event *
+subscription_by_nua(nua_handle_t *nh,
+		    enum nua_substate current,
+		    tag_type_t tag, tag_value_t value, ...)
+{
+  struct message *subscribe;
+  struct event *notify, *event;
+  ta_list ta;
+  enum nua_substate substate = nua_substate_active;
+  char const *substate_str = subscription_state;
+  char const *expires = "600";
+
+  subscribe = s2_wait_for_request(SIP_METHOD_SUBSCRIBE);
+  if (event_type)
+    fail_if(!subscribe->sip->sip_event ||
+	    strcmp(event_type, subscribe->sip->sip_event->o_type));
+
+  if (subscribe->sip->sip_expires && subscribe->sip->sip_expires->ex_delta == 0) {
+    substate = nua_substate_terminated;
+    substate_str = "terminated;reason=timeout";
+    expires = "0";
+  }
+
+  ta_start(ta, tag, value);
+
+  if (send_notify_before_response) {
+    s2_save_uas_dialog(dialog, subscribe->sip);
+    notify = notify_to_nua(substate,
+			   SIPTAG_EVENT(subscribe->sip->sip_event),
+			   SIPTAG_SUBSCRIPTION_STATE_STR(substate_str),
+			   ta_tags(ta));
+    event = respond_to_subscribe(subscribe, nua_r_subscribe, substate,
+				 SIP_200_OK,
+				 SIPTAG_EXPIRES_STR(expires),
+				 TAG_END());
+    s2_free_event(event);
+  }
+  else {
+    event = respond_to_subscribe(subscribe, nua_r_subscribe, current,
+				 SIP_202_ACCEPTED,
+				 SIPTAG_EXPIRES_STR(expires),
+				 TAG_END());
+    s2_free_event(event);
+    notify = notify_to_nua(substate,
+			   SIPTAG_EVENT(subscribe->sip->sip_event),
+			   SIPTAG_SUBSCRIPTION_STATE_STR(substate_str),
+			   ta_tags(ta));
+  }
+
+  s2_free_message(subscribe);
+
+  return notify;
+}
+
+static void
+unsubscribe_by_nua(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  struct message *subscribe, *response;
+  struct event *event;
+
+  nua_unsubscribe(nh, TAG_END());
+  subscribe = s2_wait_for_request(SIP_METHOD_SUBSCRIBE);
+
+  s2_respond_to(subscribe, dialog, SIP_200_OK, SIPTAG_EXPIRES_STR("0"), TAG_END());
+
+  event = s2_wait_for_event(nua_r_unsubscribe, 200); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_active));
+  s2_free_event(event);
+
+  fail_if(s2_request_to(dialog, SIP_METHOD_NOTIFY, NULL,
+			SIPTAG_EVENT(subscribe->sip->sip_event),
+			SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=tiemout"),
+			SIPTAG_CONTENT_TYPE_STR(event_mime_type),
+			SIPTAG_PAYLOAD_STR(event_state),
+			TAG_END()));
+
+  event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_terminated));
+  s2_free_event(event);
+
+  response = s2_wait_for_response(200, SIP_METHOD_NOTIFY);
+  fail_if(!response);
+  s2_free_message(response); s2_free_message(subscribe);
+}
+
+/* ====================================================================== */
+/* 6 - Subscribe/notify */
+
+START_TEST(subscribe_6_1_1)
+{
+  nua_handle_t *nh;
+  struct event *notify;
+  s2_case("6.1.1", "Basic subscription",
+	  "NUA sends SUBSCRIBE, waits for NOTIFY, sends un-SUBSCRIBE");
+
+  nh = nua_handle(nua, NULL, SIPTAG_TO(s2->local), TAG_END());
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END());
+  notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
+  s2_free_event(notify);
+  unsubscribe_by_nua(nh, TAG_END());
+  nua_handle_destroy(nh);
+}
+END_TEST
+
+START_TEST(subscribe_6_1_2)
+{
+  nua_handle_t *nh;
+  struct message *subscribe, *response;
+  struct event *notify, *event;
+
+  s2_case("6.1.2", "Basic subscription with refresh",
+	  "NUA sends SUBSCRIBE, waits for NOTIFY, "
+	  "sends re-SUBSCRIBE, waits for NOTIFY, "
+	  "sends un-SUBSCRIBE");
+
+  send_notify_before_response = 1;
+
+  nh = nua_handle(nua, NULL, SIPTAG_TO(s2->local), TAG_END());
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END());
+  notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
+  s2_free_event(notify);
+
+  /* Wait for refresh */
+  s2_fast_forward(600);
+  subscribe = s2_wait_for_request(SIP_METHOD_SUBSCRIBE);
+  s2_respond_to(subscribe, dialog, SIP_200_OK,
+		SIPTAG_EXPIRES_STR("600"),
+		TAG_END());
+
+  event = s2_wait_for_event(nua_r_subscribe, 200); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_active));
+  s2_free_event(event);
+
+  fail_if(s2_request_to(dialog, SIP_METHOD_NOTIFY, NULL,
+			SIPTAG_EVENT(subscribe->sip->sip_event),
+			SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=600"),
+			SIPTAG_CONTENT_TYPE_STR(event_mime_type),
+			SIPTAG_PAYLOAD_STR(event_state),
+			TAG_END()));
+  event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_active));
+  s2_free_event(event);
+  response = s2_wait_for_response(200, SIP_METHOD_NOTIFY);
+  fail_if(!response);
+  s2_free_message(response);
+
+  unsubscribe_by_nua(nh, TAG_END());
+
+  nua_handle_destroy(nh);
+}
+END_TEST
+
+START_TEST(subscribe_6_1_3)
+{
+  nua_handle_t *nh;
+  struct message *response;
+  struct event *notify, *event;
+
+  s2_case("6.1.3", "Subscription terminated by notifier",
+	  "NUA sends SUBSCRIBE, waits for NOTIFY, "
+	  "gets NOTIFY terminating the subscription,");
+
+  nh = nua_handle(nua, NULL, SIPTAG_TO(s2->local), TAG_END());
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END());
+  notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
+  s2_free_event(notify);
+
+  fail_if(s2_request_to(dialog, SIP_METHOD_NOTIFY, NULL,
+			SIPTAG_EVENT_STR(event_type),
+			SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
+			TAG_END()));
+  event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_terminated));
+  s2_free_event(event);
+  response = s2_wait_for_response(200, SIP_METHOD_NOTIFY);
+  fail_if(!response);
+  s2_free_message(response);
+
+  nua_handle_destroy(nh);
+}
+END_TEST
+
+START_TEST(subscribe_6_1_4)
+{
+  nua_handle_t *nh;
+  struct message *response;
+  struct event *notify, *event;
+
+  s2_case("6.1.4", "Subscription terminated by notifier, re-established",
+	  "NUA sends SUBSCRIBE, waits for NOTIFY, "
+	  "gets NOTIFY terminating the subscription,");
+
+  nh = nua_handle(nua, NULL, SIPTAG_TO(s2->local), TAG_END());
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END());
+  notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
+  s2_free_event(notify);
+
+  fail_if(s2_request_to(dialog, SIP_METHOD_NOTIFY, NULL,
+			SIPTAG_EVENT_STR(event_type),
+			SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=deactivated"),
+			TAG_END()));
+  event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_embryonic));
+  s2_free_event(event);
+  response = s2_wait_for_response(200, SIP_METHOD_NOTIFY);
+  fail_if(!response);
+  s2_free_message(response);
+
+  su_home_unref((void *)dialog), dialog = su_home_new(sizeof *dialog); fail_if(!dialog);
+
+  s2_fast_forward(5);
+  /* nua re-establishes the subscription */
+  notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
+  s2_free_event(notify);
+
+  /* Unsubscribe with nua_subscribe() Expires: 0 */
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END());
+  notify = subscription_by_nua(nh, nua_substate_active, TAG_END());
+  s2_free_event(notify);
+
+  nua_handle_destroy(nh);
+}
+END_TEST
+
+TCase *subscribe_tcase(void)
+{
+  TCase *tc = tcase_create("6.1 - Basic SUBSCRIBE_");
+  tcase_add_checked_fixture(tc, s2_dialog_setup, s2_dialog_teardown);
+  {
+    tcase_add_test(tc, subscribe_6_1_1);
+    tcase_add_test(tc, subscribe_6_1_2);
+    tcase_add_test(tc, subscribe_6_1_3);
+    tcase_add_test(tc, subscribe_6_1_4);
+  }
+  return tc;
+}
+
+START_TEST(fetch_6_2_1)
+{
+  nua_handle_t *nh;
+  struct event *notify;
+
+  s2_case("6.2.1", "Event fetch - NOTIFY after 202",
+	  "NUA sends SUBSCRIBE with Expires 0, waits for NOTIFY");
+
+  nh = nua_handle(nua, NULL, SIPTAG_TO(s2->local), TAG_END());
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END());
+  notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
+  s2_check_substate(notify, nua_substate_terminated);
+  s2_free_event(notify);
+  nua_handle_destroy(nh);
+}
+END_TEST
+
+START_TEST(fetch_6_2_2)
+{
+  nua_handle_t *nh;
+  struct event *notify;
+
+  s2_case("6.2.2", "Event fetch - NOTIFY before 200",
+	  "NUA sends SUBSCRIBE with Expires 0, waits for NOTIFY");
+
+  send_notify_before_response = 1;
+
+  nh = nua_handle(nua, NULL, SIPTAG_TO(s2->local), TAG_END());
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END());
+  notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
+  s2_check_substate(notify, nua_substate_terminated);
+  s2_free_event(notify);
+  nua_handle_destroy(nh);
+}
+END_TEST
+
+START_TEST(fetch_6_2_3)
+{
+  nua_handle_t *nh;
+  struct message *subscribe;
+  struct event *event;
+
+  s2_case("6.2.3", "Event fetch - no NOTIFY",
+	  "NUA sends SUBSCRIBE with Expires 0, waits for NOTIFY, times out");
+
+  nh = nua_handle(nua, NULL, SIPTAG_TO(s2->local), TAG_END());
+  nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END());
+  subscribe = s2_wait_for_request(SIP_METHOD_SUBSCRIBE);
+  s2_respond_to(subscribe, dialog, SIP_202_ACCEPTED,
+		SIPTAG_EXPIRES_STR("0"), TAG_END());
+  s2_free_message(subscribe);
+
+  event = s2_wait_for_event(nua_r_subscribe, 202); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_embryonic));
+  s2_free_event(event);
+
+  s2_fast_forward(600);
+
+  event = s2_wait_for_event(nua_i_notify, 408); fail_if(!event);
+  fail_unless(s2_check_substate(event, nua_substate_terminated));
+  s2_free_event(event);
+
+  nua_handle_destroy(nh);
+}
+END_TEST
+
+
+TCase *fetch_tcase(void)
+{
+  TCase *tc = tcase_create("6.2 - Event fetch");
+  tcase_add_checked_fixture(tc, s2_dialog_setup, s2_dialog_teardown);
+  {
+    tcase_add_test(tc, fetch_6_2_1);
+    tcase_add_test(tc, fetch_6_2_2);
+    tcase_add_test(tc, fetch_6_2_3);
+  }
+  return tc;
+}
+
+/* ====================================================================== */
+
+/* Test case template */
+
+START_TEST(empty)
+{
+  s2_case("0.0.0", "Empty test case",
+	  "Detailed explanation for empty test case.");
+
+  tport_set_params(s2->master, TPTAG_LOG(1), TAG_END());
+  s2_setup_logs(7);
+  s2_setup_logs(0);
+  tport_set_params(s2->master, TPTAG_LOG(0), TAG_END());
+}
+
+END_TEST
+
+static TCase *empty_tcase(void)
+{
+  TCase *tc = tcase_create("0 - Empty");
+  tcase_add_checked_fixture(tc, s2_dialog_setup, s2_dialog_teardown);
+  tcase_add_test(tc, empty);
+
+  return tc;
+}
+
+/* ====================================================================== */
+
+void check_simple_cases(Suite *suite)
+{
+  suite_add_tcase(suite, subscribe_tcase());
+  suite_add_tcase(suite, fetch_tcase());
+
+  if (0)			/* Template */
+    suite_add_tcase(suite, empty_tcase());
+}
+

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com	Wed Feb 11 11:12:33 2009
@@ -42,6 +42,11 @@
 		SRV 4 50 5051 sip02
 		SRV 5 10 5061 sip01
 
+cloop	CNAME	cloop0
+cloop0	CNAME	cloop1
+cloop1	CNAME	cloop2
+cloop2	CNAME	cloop0
+
 sip	CNAME	sip00
 
 subnet  A6	0 3ff0:0::

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c	Wed Feb 11 11:12:33 2009
@@ -495,7 +495,9 @@
 
 static char const *sres_toplevel(char buf[], size_t bsize, char const *domain);
 
-static sres_record_t *sres_create_record(sres_resolver_t *, sres_message_t *m);
+static sres_record_t *sres_create_record(sres_resolver_t *,
+					 sres_message_t *m,
+					 int nth);
 
 static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
 				       sres_soa_record_t *,
@@ -3539,7 +3541,7 @@
 
   total = errorcount + m->m_ancount + m->m_nscount + m->m_arcount;
 
-  answers = su_zalloc(chome, (total + 1) * sizeof answers[0]);
+  answers = su_zalloc(chome, (total + 2) * sizeof answers[0]);
   if (!answers)
     return -1;
 
@@ -3548,7 +3550,7 @@
     if (i < errorcount)
       rr = error = sres_create_error_rr(res->res_cache, query, err);
     else
-      rr = sres_create_record(res, m);
+      rr = sres_create_record(res, m, i - errorcount);
 
     if (!rr) {
       SU_DEBUG_5(("sres_create_record: %s\n", m->m_error));
@@ -3565,12 +3567,31 @@
   }
 
   if (i < total) {
+    SU_DEBUG_5(("sres_decode_msg: %s\n", "less records than promised"));
     for (i = 0; i < total; i++)
       sres_cache_free_record(res->res_cache, answers[i]);
     su_free(chome, answers);
     return -1;
   }
 
+  if (m->m_ancount > 0 && errorcount == 0 && query->q_type < sres_qtype_tsig) {
+    char b0[8], b1[8];
+    for (i = 0; i < m->m_ancount; i++) {
+      if (query->q_type == answers[i]->sr_type)
+	break;
+    }
+
+    if (i == m->m_ancount) {
+      /* The queried request was not found. CNAME? */
+      SU_DEBUG_5(("sres_decode_msg: sent query %s, got %s\n",
+		  sres_record_type(query->q_type, b0),
+		  sres_record_type(answers[0]->sr_type, b1)));
+      rr = sres_create_error_rr(res->res_cache, query, err = SRES_RECORD_ERR);
+      memmove(answers + 1, answers, (sizeof answers[0]) * total++);
+      answers[errorcount++] = rr;
+    }
+  }
+
   for (i = 0; i < total; i++) {
     rr = answers[i];
 
@@ -3591,7 +3612,7 @@
 
 static
 sres_record_t *
-sres_create_record(sres_resolver_t *res, sres_message_t *m)
+sres_create_record(sres_resolver_t *res, sres_message_t *m, int nth)
 {
   sres_cache_t *cache = res->res_cache;
   sres_record_t *sr, sr0[1];
@@ -3614,7 +3635,11 @@
 
   name[len] = 0;
 
-  SU_DEBUG_9(("RR received %s %s %s %d rdlen=%d\n", name,
+  SU_DEBUG_9(("%s RR received %s %s %s %d rdlen=%d\n",
+	      nth < m->m_ancount ? "ANSWER" :
+	      nth < m->m_ancount + m->m_nscount ? "AUTHORITY" :
+	      "ADDITIONAL",
+	      name,
 	      sres_record_type(sr->sr_type, btype),
 	      sres_record_class(sr->sr_class, bclass),
 	      sr->sr_ttl, sr->sr_rdlen));

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c	Wed Feb 11 11:12:33 2009
@@ -169,15 +169,98 @@
   su_home_unref(cache->cache_home);
 }
 
+struct frame {
+  struct frame *previous;
+  char const *domain;
+};
+
+/** Count or get matching records from cache */
+static int
+sres_cache_get0(sres_htable_t *htable,
+		sres_rr_hash_entry_t **iter,
+		uint16_t type,
+		char const *domain,
+		time_t now,
+		sres_record_t **cached,
+		int len,
+		struct frame *previous)
+{
+  sres_cname_record_t *cname = NULL;
+  int dcount = 0, derrorcount = 0, ccount = 0;
+
+  for (; iter && *iter; iter = sres_htable_next(htable, iter)) {
+    sres_record_t *rr = (*iter)->rr;
+
+    if (rr == NULL)
+      continue;
+    if (now > (*iter)->rr_expires)
+      continue;
+    if (rr->sr_name == NULL)
+      continue;
+    if (!su_casematch(rr->sr_name, domain))
+      continue;
+
+    if (rr->sr_type == type || type == sres_qtype_any) {
+      if (rr->sr_status == SRES_RECORD_ERR && type == sres_qtype_any)
+	continue;
+      if (cached) {
+	if (dcount >= len)
+	  return -1;
+	cached[dcount] = rr, rr->sr_refcount++;
+      }
+      dcount++;
+      if (rr->sr_status)
+	derrorcount++;
+    }
+
+    if (type != sres_type_cname && rr->sr_type == sres_type_cname) {
+      if (rr->sr_status == 0)
+	cname = rr->sr_cname;
+    }
+  }
+
+  if (cname && dcount == derrorcount) {
+    /* Nothing found, trace CNAMEs */
+    struct frame *f, frame = { previous, domain };
+    unsigned hash = sres_hash_key(domain = cname->cn_cname);
+
+    if (cached) {
+      if (dcount >= len)
+	return -1;
+      cached[dcount] = (sres_record_t *)cname;
+      cname->cn_record->r_refcount++;
+    }
+    dcount++;
+
+    /* Check for cname loops */
+    for (f = previous; f; f = f->previous) {
+      if (su_casematch(domain, f->domain))
+	break;
+    }
+
+    if (f == NULL) {
+      ccount = sres_cache_get0(htable, sres_htable_hash(htable, hash),
+			       type, domain, now,
+			       cached ? cached + dcount : NULL,
+			       cached ? len - dcount : 0,
+			       &frame);
+    }
+    if (ccount < 0)
+      return ccount;
+  }
+
+  return dcount + ccount;
+}
+
 /** Get a list of matching records from cache. */
 int sres_cache_get(sres_cache_t *cache,
 		   uint16_t type,
 		   char const *domain,
 		   sres_record_t ***return_cached)
 {
-  sres_record_t **result = NULL, *rr = NULL;
-  sres_rr_hash_entry_t **rr_iter, **rr_iter2;
-  int result_size, rr_count = 0;
+  sres_record_t **result = NULL;
+  sres_rr_hash_entry_t **slot;
+  int result_size, i, j;
   unsigned hash;
   time_t now;
   char b[8];
@@ -198,28 +281,16 @@
   time(&now);
 
   /* First pass: just count the number of rr:s for array allocation */
-  rr_iter2 = sres_htable_hash(cache->cache_hash, hash);
-
-  /* Find the domain records from the hash table */
-  for (rr_iter = rr_iter2;
-       rr_iter && *rr_iter;
-       rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
-    rr = (*rr_iter)->rr;
-
-    if (rr != NULL &&
-	now <= (*rr_iter)->rr_expires &&
-        (type == sres_qtype_any || rr->sr_type == type) &&
-        rr->sr_name != NULL &&
-        su_casematch(rr->sr_name, domain))
-      rr_count++;
-  }
+  slot = sres_htable_hash(cache->cache_hash, hash);
 
-  if (rr_count == 0) {
+  i = sres_cache_get0(cache->cache_hash, slot, type, domain, now,
+		      NULL, 0, NULL);
+  if (i <= 0) {
     UNLOCK(cache);
     return 0;
   }
 
-  result_size = (sizeof *result) * (rr_count + 1);
+  result_size = (sizeof *result) * (i + 1);
   result = su_zalloc(cache->cache_home, result_size);
   if (result == NULL) {
     UNLOCK(cache);
@@ -227,35 +298,30 @@
   }
 
   /* Second pass: add the rr pointers to the allocated array */
-
-  for (rr_iter = rr_iter2, rr_count = 0;
-       rr_iter && *rr_iter;
-       rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
-    rr = (*rr_iter)->rr;
-
-    if (rr != NULL &&
-	now <= (*rr_iter)->rr_expires &&
-        (type == sres_qtype_any || rr->sr_type == type) &&
-        rr->sr_name != NULL &&
-        su_casematch(rr->sr_name, domain)) {
-      SU_DEBUG_9(("rr found in cache: %s %02d\n",
-		  rr->sr_name, rr->sr_type));
-
-      result[rr_count++] = rr;
-      rr->sr_refcount++;
+  j = sres_cache_get0(cache->cache_hash, slot, type, domain, now,
+		      result, i, NULL);
+  if (i != j) {
+    /* Uh-oh. */
+    SU_DEBUG_9(("%s(%p, %s, \"%s\") got %d != %d\n", "sres_cache_get",
+		(void *)cache, sres_record_type(type, b), domain, i, j));
+    for (i = 0; i < result_size; i++) {
+      if (result[i])
+	result[i]->sr_refcount--;
     }
+    su_free(cache->cache_home, result);
+    return 0;
   }
 
-  result[rr_count] = NULL;
+  result[i] = NULL;
 
   UNLOCK(cache);
 
   SU_DEBUG_9(("%s(%p, %s, \"%s\") returned %d entries\n", "sres_cache_get",
-	      (void *)cache, sres_record_type(type, b), domain, rr_count));
+	      (void *)cache, sres_record_type(type, b), domain, i));
 
   *return_cached = result;
 
-  return rr_count;
+  return i;
 }
 
 sres_record_t *

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c	Wed Feb 11 11:12:33 2009
@@ -90,6 +90,10 @@
 #include <signal.h>
 #endif
 
+#include <sofia-sip/su_log.h>
+
+extern su_log_t sresolv_log[];
+
 char const name[] = "test_sresolv";
 
 struct sres_context_s
@@ -982,24 +986,133 @@
 int test_cname(sres_context_t *ctx)
 {
   sres_resolver_t *res = ctx->resolver;
-  sres_record_t **result;
-  const sres_cname_record_t *rr;
+  sres_record_t **result, *sr;
+  const sres_cname_record_t *cn;
   char const *domain = "sip.example.com";
 
   BEGIN();
 
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_naptr, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(sr = result[0]);
+  TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
+  TEST_1(cn = result[1]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "sip00.example.com.");
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_type_naptr, domain));
+  TEST_1(sr = result[0]);
+  TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
+  TEST_1(cn = result[1]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "sip00.example.com.");
+
+  sres_free_answers(res, result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_qtype_any, domain));
+  TEST_1(cn = result[0]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "sip00.example.com.");
+  /* We might have A record, or then not */
+
+  sres_free_answers(res, result), ctx->result = NULL;
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(cn = result[0]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "sip00.example.com.");
+  TEST_1(sr = result[1]);
+  TEST(sr->sr_record->r_class, sres_class_in);
+  TEST(sr->sr_record->r_type, sres_type_a);
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_type_a, domain));
+  TEST_1(cn = result[0]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "sip00.example.com.");
+  TEST_1(sr = result[1]);
+  TEST(sr->sr_record->r_class, sres_class_in);
+  TEST(sr->sr_record->r_type, sres_type_a);
+
+  sres_free_answers(res, result);
+
+  domain = "cloop.example.com";
+
   TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
   TEST_RUN(ctx);
 
   TEST_1(result = ctx->result);
-  TEST_1(rr = result[0]->sr_cname);
-  TEST(rr->cn_record->r_class, sres_class_in);
-  TEST(rr->cn_record->r_type, sres_type_cname);
-  TEST(rr->cn_record->r_ttl, 60);
-  TEST_S(rr->cn_cname, "sip00.example.com.");
+  TEST_1(sr = result[0]);
+  TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
+  TEST_1(cn = result[1]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop0.example.com.");
+  TEST_1(cn = result[2]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop1.example.com.");
+  TEST_1(cn = result[3]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop2.example.com.");
+  TEST_1(cn = result[4]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop0.example.com.");
+  TEST_1(result[5] == NULL);
 
   sres_free_answers(res, ctx->result), ctx->result = NULL;
 
+  TEST_1(result = sres_cached_answers(res, sres_type_a, domain));
+  TEST_1(sr = result[0]);
+  TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
+  TEST_1(cn = result[1]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop0.example.com.");
+  TEST_1(cn = result[2]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop1.example.com.");
+  TEST_1(cn = result[3]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop2.example.com.");
+  TEST_1(cn = result[4]->sr_cname);
+  TEST(cn->cn_record->r_class, sres_class_in);
+  TEST(cn->cn_record->r_type, sres_type_cname);
+  TEST(cn->cn_record->r_ttl, 60);
+  TEST_S(cn->cn_cname, "cloop0.example.com.");
+  TEST_1(result[5] == NULL);
+
+  sres_free_answers(res, result);
+
   END();
 }
 
@@ -1892,10 +2005,6 @@
   exit(exitcode);
 }
 
-#include <sofia-sip/su_log.h>
-
-extern su_log_t sresolv_log[];
-
 int main(int argc, char **argv)
 {
   int i;



More information about the Freeswitch-svn mailing list