From 0c141d9b81a31fd0cd2e14ec31cdcdd8c61588a8 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 11 Feb 2009 17:41:05 +0000 Subject: [PATCH] Tue Feb 10 07:17:20 CST 2009 Pekka Pessi * check_nua: moved s2_fast_forward() to s2 library git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11879 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- .../sofia-sip/libsofia-sip-ua/nua/Makefile.am | 5 +- .../libsofia-sip-ua/nua/check_etsi.c | 16 +- .../libsofia-sip-ua/nua/check_register.c | 10 +- .../libsofia-sip-ua/nua/check_session.c | 26 +- .../libsofia-sip-ua/nua/check_simple.c | 6 +- libs/sofia-sip/libsofia-sip-ua/nua/test_s2.c | 21 - libs/sofia-sip/libsofia-sip-ua/nua/test_s2.h | 4 +- libs/sofia-sip/s2check/s2dns.c | 636 ++++++++++++++++++ libs/sofia-sip/s2check/s2dns.h | 57 ++ libs/sofia-sip/s2check/s2time.c | 51 ++ libs/sofia-sip/s2check/s2util.h | 44 ++ 11 files changed, 823 insertions(+), 53 deletions(-) create mode 100644 libs/sofia-sip/s2check/s2dns.c create mode 100644 libs/sofia-sip/s2check/s2dns.h create mode 100644 libs/sofia-sip/s2check/s2time.c create mode 100644 libs/sofia-sip/s2check/s2util.h diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am index 8262156746..86709a3c1b 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am +++ b/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am @@ -52,7 +52,10 @@ check_nua_SOURCES = check_nua.c check_nua.h \ check_etsi.c check_simple.c \ test_s2.h test_s2.c -check_nua_LDADD = $(nua_libs) @CHECK_LIBS@ +check_nua_LDADD = $(nua_libs) ${top_builddir}/s2check/libs2.a \ + @CHECK_LIBS@ + +check_nua_CFLAGS = $(CFLAGS) -I$(top_srcdir)/s2check nua_libs = libnua.la \ ../iptsec/libiptsec.la \ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c index 6be45c856d..f74de3d8f0 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c @@ -244,22 +244,22 @@ START_TEST(SIP_CC_OE_CE_TI_008) fail_unless(s2_check_callstate(nua_callstate_terminated)); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; s2_respond_to(invite, d1, SIP_404_NOT_FOUND, TAG_END()); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; s2_respond_to(invite, d1, SIP_404_NOT_FOUND, TAG_END()); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(21); + s2_fast_forward(21, s2->root);; s2_respond_to(invite, d1, SIP_404_NOT_FOUND, TAG_END()); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(1); + s2_fast_forward(1, s2->root);; s2_respond_to(invite, d1, SIP_404_NOT_FOUND, TAG_END()); s2_free_message(invite); @@ -294,19 +294,19 @@ START_TEST(SIP_CC_OE_CE_TI_011_012) fail_unless(s2_check_callstate(nua_callstate_ready)); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(21); + s2_fast_forward(21, s2->root);; respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); fail_unless(s2_check_request(SIP_METHOD_ACK)); - s2_fast_forward(1); + s2_fast_forward(1, s2->root);; respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); s2_free_message(invite); fail_if(s2_check_request_timeout(SIP_METHOD_ACK, 500)); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c index e6f6b6de27..48caf60808 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c @@ -335,7 +335,7 @@ START_TEST(register_1_2_2_2) s2_free_message(m); su_root_step(s2->root, 20); su_root_step(s2->root, 20); - s2_fast_forward(120); /* Default keepalive interval */ + s2_fast_forward(120, s2->root);; /* Default keepalive interval */ mark_point(); m = s2_wait_for_request(SIP_METHOD_OPTIONS); @@ -346,7 +346,7 @@ START_TEST(register_1_2_2_2) s2_free_message(m); su_root_step(s2->root, 20); su_root_step(s2->root, 20); - s2_fast_forward(120); /* Default keepalive interval */ + s2_fast_forward(120, s2->root);; /* Default keepalive interval */ mark_point(); receive_natted = "received=4.255.255.10"; @@ -400,7 +400,7 @@ START_TEST(register_1_2_2_3) receive_natted = "received=4.255.255.10"; - s2_fast_forward(3600); + s2_fast_forward(3600, s2->root);; mark_point(); m = s2_wait_for_request(SIP_METHOD_REGISTER); @@ -637,7 +637,7 @@ START_TEST(register_1_3_3_1) if (!tport_is_udp(m->tport)) /* Drop UDP */ break; s2_free_message(m); - s2_fast_forward(4); + s2_fast_forward(4, s2->root);; } tcp = tport_ref(m->tport); @@ -695,7 +695,7 @@ START_TEST(register_1_3_3_1) su_root_step(s2->root, 5); su_root_step(s2->root, 5); su_root_step(s2->root, 5); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; } } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_session.c index 2a4423fb3a..c98e4de6cd 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/check_session.c @@ -1054,11 +1054,11 @@ START_TEST(call_2_3_1) SIPTAG_REQUIRE_STR("timer"), TAG_END()); - s2_fast_forward(300); + s2_fast_forward(300, s2->root);; ack = invite_timer_round(nh, "300;refresher=uac", rr); fail_if(ack->sip->sip_route && su_strmatch(ack->sip->sip_route->r_url->url_user, "record")); - s2_fast_forward(300); + s2_fast_forward(300, s2->root);; invite_timer_round(nh, "300;refresher=uac", NULL); bye_by_nua(nh, TAG_END()); @@ -1082,9 +1082,9 @@ START_TEST(call_2_3_2) SIPTAG_REQUIRE_STR("timer"), TAG_END()); - s2_fast_forward(300); + s2_fast_forward(300, s2->root);; invite_timer_round(nh, "300", NULL); - s2_fast_forward(300); + s2_fast_forward(300, s2->root);; invite_timer_round(nh, "300", NULL); bye_by_nua(nh, TAG_END()); @@ -1551,7 +1551,7 @@ START_TEST(call_2_6_2) /* We get nua_r_invite with 100 trying (and 500 in sip->sip_status) */ fail_unless(s2_check_event(nua_r_invite, 100)); - s2_fast_forward(10); + s2_fast_forward(10, s2->root);; fail_unless(s2_check_callstate(nua_callstate_calling)); @@ -1605,7 +1605,7 @@ START_TEST(call_2_6_3) fail_unless(s2_check_event(nua_i_ack, 200)); fail_unless(s2_check_callstate(nua_callstate_ready)); - s2_fast_forward(10); + s2_fast_forward(10, s2->root);; nua_set_hparams(nh, NUTAG_REFRESH_WITHOUT_SDP(1), TAG_END()); fail_unless(s2_check_event(nua_r_set_params, 200)); @@ -1752,7 +1752,7 @@ START_TEST(call_3_1_2) if (i == 3) break; fail_unless(s2_check_event(nua_r_invite, 100)); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; } fail_unless(s2_check_event(nua_r_invite, 500)); @@ -1822,7 +1822,7 @@ START_TEST(call_3_2_2) if (i == 3) break; fail_unless(s2_check_event(nua_r_invite, 100)); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; } fail_unless(s2_check_event(nua_r_invite, 500)); @@ -2344,7 +2344,7 @@ START_TEST(bye_4_2_1) SIPTAG_REQUIRE_STR("timer"), TAG_END()); - s2_fast_forward(300); + s2_fast_forward(300, s2->root);; invite_timer_round(nh, "300", NULL); nua_bye(nh, TAG_END()); @@ -2357,7 +2357,7 @@ START_TEST(bye_4_2_1) s2_free_message(bye); fail_unless(s2_check_event(nua_r_bye, 407)); - s2_fast_forward(300); + s2_fast_forward(300, s2->root);; nua_authenticate(nh, NUTAG_AUTH("Digest:\"s2test\":abc:abc"), TAG_END()); bye = s2_wait_for_request(SIP_METHOD_BYE); @@ -2388,10 +2388,10 @@ START_TEST(bye_4_2_2) SIPTAG_REQUIRE_STR("timer"), TAG_END()); - s2_fast_forward(300); + s2_fast_forward(300, s2->root);; invite_timer_round(nh, "300", NULL); - s2_fast_forward(140); + s2_fast_forward(140, s2->root);; nua_bye(nh, TAG_END()); @@ -2403,7 +2403,7 @@ START_TEST(bye_4_2_2) s2_free_message(bye); fail_unless(s2_check_event(nua_r_bye, 407)); - s2_fast_forward(160); + s2_fast_forward(160, s2->root);; nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END()); bye = s2_wait_for_request(SIP_METHOD_BYE); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c index d5bc3b5afa..d616f666ac 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c @@ -290,7 +290,7 @@ START_TEST(subscribe_6_1_2) s2_free_event(notify); /* Wait for refresh */ - s2_fast_forward(600); + s2_fast_forward(600, s2->root);; subscribe = s2_wait_for_request(SIP_METHOD_SUBSCRIBE); s2_respond_to(subscribe, dialog, SIP_200_OK, SIPTAG_EXPIRES_STR("600"), @@ -377,7 +377,7 @@ START_TEST(subscribe_6_1_4) su_home_unref((void *)dialog), dialog = su_home_new(sizeof *dialog); fail_if(!dialog); - s2_fast_forward(5); + s2_fast_forward(5, s2->root);; /* nua re-establishes the subscription */ notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); s2_free_event(notify); @@ -460,7 +460,7 @@ START_TEST(fetch_6_2_3) fail_unless(s2_check_substate(event, nua_substate_embryonic)); s2_free_event(event); - s2_fast_forward(600); + s2_fast_forward(600, s2->root);; event = s2_wait_for_event(nua_i_notify, 408); fail_if(!event); fail_unless(s2_check_substate(event, nua_substate_terminated)); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.c b/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.c index 35ed88591a..99c6db08fa 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.c @@ -108,27 +108,6 @@ char const s2_auth3_credentials[] = "Digest:\"s2test3\":abc:abc"; int s2_nua_thread = 0; -/* -- Delay scenarios --------------------------------------------------- */ - -static unsigned long time_offset; - -extern void (*_su_time)(su_time_t *tv); - -static void _su_time_fast_forwarder(su_time_t *tv) -{ - tv->tv_sec += time_offset; -} - -void s2_fast_forward(unsigned long seconds) -{ - if (_su_time == NULL) - _su_time = _su_time_fast_forwarder; - - time_offset += seconds; - - su_root_step(s2->root, 0); -} - /* -- NUA events -------------------------------------------------------- */ struct event *s2_remove_event(struct event *e) diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.h b/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.h index f93d290f5d..1d1a423ad9 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_s2.h @@ -32,6 +32,8 @@ #include #include +#include "s2util.h" + struct tester { su_home_t home[1]; @@ -119,8 +121,6 @@ extern char const s2_auth3_credentials[]; extern int s2_nua_thread; -void s2_fast_forward(unsigned long seconds); - void s2_case(char const *tag, char const *title, char const *description); diff --git a/libs/sofia-sip/s2check/s2dns.c b/libs/sofia-sip/s2check/s2dns.c new file mode 100644 index 0000000000..c6ae81b44c --- /dev/null +++ b/libs/sofia-sip/s2check/s2dns.c @@ -0,0 +1,636 @@ +/* ---------------------------------------------------------------------- */ +/* S2 DNS server */ + +#include +#include +#include + +#include "s2dns.h" + +#include +#include +#include + +extern uint16_t _sres_default_port; /* Ugly hack */ + +static struct s2dns { + su_root_t *root; + su_socket_t socket; + su_wait_t wait[1]; + int reg; +} s2dns; + +static +struct s2_dns_response { + struct s2_dns_response *next; + uint16_t qlen, dlen; + struct m_header { + /* Header defined in RFC 1035 section 4.1.1 (page 26) */ + uint16_t mh_id; /* Query ID */ + uint16_t mh_flags; /* Flags */ + uint16_t mh_qdcount; /* Question record count */ + uint16_t mh_ancount; /* Answer record count */ + uint16_t mh_nscount; /* Authority records count */ + uint16_t mh_arcount; /* Additional records count */ + } header[1]; + uint8_t data[1500]; +} *zonedata; + +enum { + FLAGS_QR = (1 << 15), + FLAGS_QUERY = (0 << 11), + FLAGS_IQUERY = (1 << 11), + FLAGS_STATUS = (2 << 11), + FLAGS_OPCODE = (15 << 11), /* mask */ + FLAGS_AA = (1 << 10), /* */ + FLAGS_TC = (1 << 9), + FLAGS_RD = (1 << 8), + FLAGS_RA = (1 << 7), + + FLAGS_RCODE = (15 << 0), /* mask of return code */ + + FLAGS_OK = 0, /* No error condition. */ + FLAGS_FORMAT_ERR = 1, /* Server could not interpret query. */ + FLAGS_SERVER_ERR = 2, /* Server error. */ + FLAGS_NAME_ERR = 3, /* No domain name. */ + FLAGS_UNIMPL_ERR = 4, /* Not implemented. */ + FLAGS_AUTH_ERR = 5, /* Refused */ +}; + +uint32_t s2_dns_ttl = 3600; + +static int s2_dns_query(su_root_magic_t *magic, + su_wait_t *w, + su_wakeup_arg_t *arg); + +void s2_dns_setup(su_root_t *root) +{ + int n; + su_socket_t socket; + su_wait_t *wait; + su_sockaddr_t su[1]; + socklen_t sulen = sizeof su->su_sin; + + assert(root); + + memset(su, 0, sulen); + su->su_len = sulen; + su->su_family = AF_INET; + + /* su->su_port = htons(1053); */ + + socket = su_socket(su->su_family, SOCK_DGRAM, 0); + + n = bind(socket, &su->su_sa, sulen); assert(n == 0); + n = getsockname(socket, &su->su_sa, &sulen); assert(n == 0); + + _sres_default_port = ntohs(su->su_port); + + s2dns.root = root; + wait = s2dns.wait; + n = su_wait_create(wait, socket, SU_WAIT_IN); assert(n == 0); + s2dns.reg = su_root_register(root, wait, s2_dns_query, NULL, 0); + assert(s2dns.reg > 0); + s2dns.socket = socket; +} + +void s2_dns_teardown(void) +{ + struct s2_dns_response *r, *next; + su_root_deregister(s2dns.root, s2dns.reg), s2dns.reg = -1; + su_close(s2dns.socket), s2dns.socket = -1; + s2dns.root = NULL; + + for (r = zonedata, zonedata = NULL; r; r = next) { + next = r->next; + free(r); + } +} + +static int +s2_dns_query(su_root_magic_t *magic, + su_wait_t *w, + su_wakeup_arg_t *arg) +{ + union { + struct m_header header[1]; + uint8_t buffer[1500]; + } request; + ssize_t len; + + su_socket_t socket; + su_sockaddr_t su[1]; + socklen_t sulen = sizeof su; + uint16_t flags; + struct s2_dns_response *r; + size_t const hlen = sizeof r->header; + + (void)arg; + + socket = s2dns.socket; + + len = su_recvfrom(socket, request.buffer, sizeof request.buffer, 0, + &su->su_sa, &sulen); + + flags = ntohs(request.header->mh_flags); + + if (len < (ssize_t)hlen) + return 0; + if ((flags & FLAGS_QR) == FLAGS_QR) + return 0; + if ((flags & FLAGS_RCODE) != FLAGS_OK) + return 0; + + if ((flags & FLAGS_OPCODE) != FLAGS_QUERY + || ntohs(request.header->mh_qdcount) != 1) { + flags |= FLAGS_QR | FLAGS_UNIMPL_ERR; + request.header->mh_flags = htons(flags); + su_sendto(socket, request.buffer, len, 0, &su->su_sa, sulen); + return 0; + } + + for (r = zonedata; r; r = r->next) { + if (memcmp(r->data, request.buffer + hlen, r->qlen) == 0) + break; + } + + if (r) { + flags |= FLAGS_QR | FLAGS_AA | FLAGS_OK; + request.header->mh_flags = htons(flags); + request.header->mh_ancount = htons(r->header->mh_ancount); + request.header->mh_nscount = htons(r->header->mh_nscount); + request.header->mh_arcount = htons(r->header->mh_arcount); + memcpy(request.buffer + hlen + r->qlen, + r->data + r->qlen, + r->dlen - r->qlen); + len = hlen + r->dlen; + } + else { + flags |= FLAGS_QR | FLAGS_AA | FLAGS_NAME_ERR; + } + + request.header->mh_flags = htons(flags); + su_sendto(socket, request.buffer, len, 0, &su->su_sa, sulen); + return 0; +} + +static char const *default_domain; + +/* Set default domain */ +char const * +s2_dns_default(char const *domain) +{ + assert(domain == NULL || strlen(domain)); + assert(domain == NULL || domain[strlen(domain) - 1] == '.'); + return default_domain = domain; +} + +static void put_uint16(struct s2_dns_response *m, uint16_t h) +{ + uint8_t *p = m->data + m->dlen; + + assert(m->dlen + (sizeof h) < sizeof m->data); + p[0] = h >> 8; p[1] = h; + m->dlen += (sizeof h); +} + +static void put_uint32(struct s2_dns_response *m, uint32_t w) +{ + uint8_t *p = m->data + m->dlen; + + assert(m->dlen + (sizeof w) < sizeof m->data); + p[0] = w >> 24; p[1] = w >> 16; p[2] = w >> 8; p[3] = w; + m->dlen += (sizeof w); +} + +static void put_domain(struct s2_dns_response *m, char const *domain) +{ + char const *label; + size_t llen; + + if (domain && domain[0] == 0) + domain = default_domain; + + /* Copy domain into query label at a time */ + for (label = domain; label && label[0]; label += llen) { + assert(!(label[0] == '.' && label[1] != '\0')); + llen = strcspn(label, "."); + assert(llen < 64); + assert(m->dlen + llen + 1 < sizeof m->data); + m->data[m->dlen++] = (uint8_t)llen; + if (llen == 0) + return; + + memcpy(m->data + m->dlen, label, llen); + m->dlen += (uint16_t)llen; + + if (label[llen] == '\0') { + if (default_domain) { + label = default_domain, llen = 0; + continue; + } + break; + } + if (label[llen + 1]) + llen++; + } + + assert(m->dlen < sizeof m->data); + m->data[m->dlen++] = '\0'; +} + +static void put_string(struct s2_dns_response *m, char const *string) +{ + uint8_t *p = m->data + m->dlen; + size_t len = strlen(string); + + assert(len <= 255); + assert(m->dlen + len + 1 < sizeof m->data); + + *p++ = (uint8_t)len; + memcpy(p, string, len); + m->dlen += len + 1; +} + +static uint16_t put_len_at(struct s2_dns_response *m) +{ + uint16_t at = m->dlen; + assert(m->dlen + sizeof(at) < sizeof m->data); + memset(m->data + m->dlen, 0, sizeof(at)); + m->dlen += sizeof(at); + return at; +} + +static void put_len(struct s2_dns_response *m, uint16_t start) +{ + uint8_t *p = m->data + start; + uint16_t len = m->dlen - (start + 2); + p[0] = len >> 8; p[1] = len; +} + +static void put_data(struct s2_dns_response *m, void const *data, uint16_t len) +{ + assert(m->dlen + len < sizeof m->data); + memcpy(m->data + m->dlen, data, len); + m->dlen += len; +} + +static void put_query(struct s2_dns_response *m, char const *domain, + uint16_t qtype) +{ + assert(m->header->mh_qdcount == 0); + put_domain(m, domain), put_uint16(m, qtype), put_uint16(m, sres_class_in); + m->header->mh_qdcount++; + m->qlen = m->dlen; +} + +static void put_a_record(struct s2_dns_response *m, + char const *domain, + struct in_addr addr) +{ + uint16_t start; + + put_domain(m, domain); + put_uint16(m, sres_type_a); + put_uint16(m, sres_class_in); + put_uint32(m, s2_dns_ttl); + start = put_len_at(m); + + put_data(m, &addr, sizeof addr); + put_len(m, start); +} + +static void put_aaaa_record(struct s2_dns_response *m, + char const *domain, + struct in6_addr addr) +{ + uint16_t start; + + put_domain(m, domain); + put_uint16(m, sres_type_aaaa); + put_uint16(m, sres_class_in); + put_uint32(m, s2_dns_ttl); + start = put_len_at(m); + + put_data(m, &addr, sizeof addr); + put_len(m, start); +} + +static void put_cname_record(struct s2_dns_response *m, + char const *domain, + char const *cname) +{ + uint16_t start; + + put_domain(m, domain); + put_uint16(m, sres_type_cname); + put_uint16(m, sres_class_in); + put_uint32(m, s2_dns_ttl); + start = put_len_at(m); + + put_data(m, (void *)cname, strlen(cname)); + put_len(m, start); +} + +static void put_srv_record(struct s2_dns_response *m, + char const *domain, + uint16_t prio, uint16_t weight, + uint16_t port, char const *target) +{ + uint16_t start; + put_domain(m, domain); + put_uint16(m, sres_type_srv); + put_uint16(m, sres_class_in); + put_uint32(m, s2_dns_ttl); + start = put_len_at(m); + + put_uint16(m, prio); + put_uint16(m, weight); + put_uint16(m, port); + put_domain(m, target); + put_len(m, start); +} + +static void put_naptr_record(struct s2_dns_response *m, + char const *domain, + uint16_t order, uint16_t preference, + char const *flags, + char const *services, + char const *regexp, + char const *replace) +{ + uint16_t start; + put_domain(m, domain); + put_uint16(m, sres_type_naptr); + put_uint16(m, sres_class_in); + put_uint32(m, s2_dns_ttl); + start = put_len_at(m); + + put_uint16(m, order); + put_uint16(m, preference); + put_string(m, flags); + put_string(m, services); + put_string(m, regexp); + put_domain(m, replace); + put_len(m, start); +} + +static void put_srv_record_from_uri(struct s2_dns_response *m, + char const *base, + uint16_t prio, uint16_t weight, + url_t const *uri, char const *server) +{ + char domain[1024] = "none"; + char const *service = url_port(uri); + uint16_t port; + + if (uri->url_type == url_sips) { + strcpy(domain, "_sips._tcp."); + } + else if (uri->url_type == url_sip) { + if (url_has_param(uri, "transport=udp")) { + strcpy(domain, "_sip._udp."); + } + else if (url_has_param(uri, "transport=tcp")) { + strcpy(domain, "_sip._tcp."); + } + } + + assert(strcmp(domain, "none")); + + strcat(domain, base); + + if (m->header->mh_qdcount == 0) + put_query(m, domain, sres_type_srv); + + port = (uint16_t)strtoul(service, NULL, 10); + + put_srv_record(m, domain, prio, weight, port, server); +} + +static +void s2_add_to_zone(struct s2_dns_response *_r) +{ + size_t size = offsetof(struct s2_dns_response, data[_r->dlen]); + struct s2_dns_response *r = malloc(size); assert(r); + + memcpy(r, _r, size); + r->next = zonedata; + zonedata = r; +} + + +static void make_server(char *server, char const *prefix, char const *domain) +{ + strcpy(server, prefix); + + if (strlen(server) == 0 || server[strlen(server) - 1] != '.') { + strcat(server, "."); + strcat(server, domain); + } +} + +/** Set up DNS domain */ +void s2_dns_domain(char const *domain, int use_naptr, + /* char *prefix, int priority, url_t const *uri, */ + ...) +{ + struct s2_dns_response m[1]; + + char server[1024], target[1024]; + + va_list va0, va; + char const *prefix; int priority; url_t const *uri; + struct in_addr localhost; + + assert(s2dns.reg != 0); + + su_inet_pton(AF_INET, "127.0.0.1", &localhost); + + va_start(va0, use_naptr); + + if (use_naptr) { + memset(m, 0, sizeof m); + put_query(m, domain, sres_type_naptr); + + va_copy(va, va0); + + for (;(prefix = va_arg(va, char *));) { + char *services = NULL; + + priority = va_arg(va, int); + uri = va_arg(va, url_t *); assert(uri); + + if (uri->url_type == url_sips) { + services = "SIPS+D2T"; + strcpy(target, "_sips._tcp."); + } + else if (uri->url_type == url_sip) { + if (url_has_param(uri, "transport=udp")) { + services = "SIP+D2U"; + strcpy(target, "_sip._udp."); + } + else if (url_has_param(uri, "transport=tcp")) { + services = "SIP+D2T"; + strcpy(target, "_sip._tcp."); + } + } + + strcat(target, domain); + assert(services); + put_naptr_record(m, domain, 1, priority, "s", services, "", target); + m->header->mh_ancount++; + } + + va_end(va); + va_copy(va, va0); + + for (;(prefix = va_arg(va, char *));) { + priority = va_arg(va, int); + uri = va_arg(va, url_t *); assert(uri); + + make_server(server, prefix, domain); + + put_srv_record_from_uri(m, domain, priority, 10, uri, server); + m->header->mh_arcount++; + + put_a_record(m, server, localhost); + m->header->mh_arcount++; + } + va_end(va); + + s2_add_to_zone(m); + } + + /* Add SRV records */ + va_copy(va, va0); + for (;(prefix = va_arg(va, char *));) { + priority = va_arg(va, int); + uri = va_arg(va, url_t *); assert(uri); + + make_server(server, prefix, domain); + + memset(m, 0, sizeof m); + put_srv_record_from_uri(m, domain, priority, 10, uri, server); + m->header->mh_ancount++; + + strcpy(server, prefix); strcat(server, domain); + + put_a_record(m, server, localhost); + m->header->mh_arcount++; + + s2_add_to_zone(m); + } + va_end(va); + + /* Add A records */ + va_copy(va, va0); + for (;(prefix = va_arg(va, char *));) { + (void)va_arg(va, int); + (void)va_arg(va, url_t *); + + memset(m, 0, sizeof m); + make_server(server, prefix, domain); + + put_query(m, server, sres_type_a); + put_a_record(m, server, localhost); + m->header->mh_ancount++; + + s2_add_to_zone(m); + } + va_end(va); + + va_end(va0); +} + +/** Insert DNS record */ +void s2_dns_record( + char const *qdomain, unsigned qtype, + /* unsigned atype, domain, */ + ...) +{ + struct s2_dns_response m[1]; + char const *domain; + va_list va; + unsigned atype; + unsigned ancount = 0, arcount = 0; + + memset(m, 0, (sizeof m)); + + va_start(va, qtype); + + put_query(m, qdomain, qtype); + + for (domain = va_arg(va, char const *); domain; domain = va_arg(va, char const *)) { + if (!domain[0]) + domain = qdomain; + + if (strcmp(domain, "@") == 0) + domain = default_domain; + + atype = va_arg(va, unsigned); + + if (atype == qtype) + ancount++; + else + arcount++; + + switch(atype) { + case sres_type_naptr: + { + unsigned order = va_arg(va, unsigned); + unsigned priority = va_arg(va, unsigned); + char const *flags = va_arg(va, char const *); + char const *services = va_arg(va, char const *); + char const *regexp = va_arg(va, char const *); + char const *target = va_arg(va, char const *); + + put_naptr_record(m, domain, order, priority, + flags, services, regexp, target); + } + break; + case sres_type_srv: + { + unsigned priority = va_arg(va, unsigned); + unsigned weight = va_arg(va, unsigned); + unsigned port = va_arg(va, unsigned); + char const *target = va_arg(va, char const *); + + put_srv_record(m, domain, priority, weight, port, target); + } + break; + case sres_type_aaaa: +#if SU_HAVE_IN6 + { + char const *address = va_arg(va, char const *); /* target */ + struct in6_addr aaaa; + + inet_pton(AF_INET6, address, &aaaa); + + put_aaaa_record(m, domain, aaaa); + } + break; +#endif + case sres_type_a: + { + char const *address = va_arg(va, char const *); /* target */ + struct in_addr a; + + inet_pton(AF_INET, address, &a); + + put_a_record(m, domain, a); + } + break; + case sres_type_cname: + put_cname_record(m, domain, va_arg(va, char const *)); + } + } + + m->header->mh_ancount = ancount; + m->header->mh_arcount = arcount; + + s2_add_to_zone(m); + + va_end(va); +} + diff --git a/libs/sofia-sip/s2check/s2dns.h b/libs/sofia-sip/s2check/s2dns.h new file mode 100644 index 0000000000..01f6607211 --- /dev/null +++ b/libs/sofia-sip/s2check/s2dns.h @@ -0,0 +1,57 @@ +/* + * This file is part of the Sofia-SIP package + * + * Copyright (C) 2009 Nokia Corporation. + * + * Contact: Pekka Pessi + * + * 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 + * + */ + +#ifndef S2DNS_H +/** Defined when has been included. */ +#define S2DNS_H + +/**@internal @file s2dns.h + * + * @brief Internal DNS server for testing + * + * @author Pekka Pessi + */ + +#include + +SOFIA_BEGIN_DECLS + +void s2_dns_setup(su_root_t *root); +void s2_dns_teardown(void); + +char const *s2_dns_default(char const *domain); + +extern uint32_t s2_dns_ttl; + +void s2_dns_domain(char const *domain, int use_naptr, + /* char *prefix, int priority, url_t const *uri, */ + ...); + +void s2_dns_record(char const *domain, unsigned qtype, + /* unsigned atype, domain, */ + ...); + +SOFIA_END_DECLS + +#endif /* S2DNS_H */ diff --git a/libs/sofia-sip/s2check/s2time.c b/libs/sofia-sip/s2check/s2time.c new file mode 100644 index 0000000000..ccb075905e --- /dev/null +++ b/libs/sofia-sip/s2check/s2time.c @@ -0,0 +1,51 @@ +/* + * This file is part of the Sofia-SIP package + * + * Copyright (C) 2009 Nokia Corporation. + * + * Contact: Pekka Pessi + * + * 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 + * + */ + +#include "config.h" + +#include "s2util.h" + +/* -- Delay scenarios --------------------------------------------------- */ + +static unsigned long time_offset; + +extern void (*_su_time)(su_time_t *tv); + +static void _su_time_fast_forwarder(su_time_t *tv) +{ + tv->tv_sec += time_offset; +} + +void s2_fast_forward(unsigned long seconds, + su_root_t *root) +{ + if (_su_time == NULL) + _su_time = _su_time_fast_forwarder; + + time_offset += seconds; + + if (root) + su_root_step(root, 0); +} + diff --git a/libs/sofia-sip/s2check/s2util.h b/libs/sofia-sip/s2check/s2util.h new file mode 100644 index 0000000000..c991342f91 --- /dev/null +++ b/libs/sofia-sip/s2check/s2util.h @@ -0,0 +1,44 @@ +/* + * This file is part of the Sofia-SIP package + * + * Copyright (C) 2009 Nokia Corporation. + * + * Contact: Pekka Pessi + * + * 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 + * + */ + +#ifndef S2UTIL_H +/** Defined when has been included. */ +#define S2UTIL_H + +/**@internal @file s2util.h + * + * @brief Miscellaneous testing utilities + * + * @author Pekka Pessi + */ + +#include + +SOFIA_BEGIN_DECLS + +void s2_fast_forward(unsigned long seconds, su_root_t *root); + +SOFIA_END_DECLS + +#endif /* S2UTIL_H */