blob: 17cb399a6c9a988215c247fc8f1d47f21c8eee5a [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "test.h"
21#include <pjsip_ua.h>
22#include <pjsip.h>
23#include <pjlib.h>
24
25#define THIS_FILE "regc_test.c"
26
27
28/************************************************************************/
29/* A module to inject error into outgoing sending operation */
30static pj_status_t mod_send_on_tx_request(pjsip_tx_data *tdata);
31
32static struct
33{
34 pjsip_module mod;
35 unsigned count;
36 unsigned count_before_reject;
37} send_mod =
38{
39 {
40 NULL, NULL, /* prev, next. */
41 { "mod-send", 8 }, /* Name. */
42 -1, /* Id */
43 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */
44 NULL, /* load() */
45 NULL, /* start() */
46 NULL, /* stop() */
47 NULL, /* unload() */
48 NULL, /* on_rx_request() */
49 NULL, /* on_rx_response() */
50 &mod_send_on_tx_request, /* on_tx_request. */
51 NULL, /* on_tx_response() */
52 NULL, /* on_tsx_state() */
53 },
54 0,
55 0xFFFF
56};
57
58
59static pj_status_t mod_send_on_tx_request(pjsip_tx_data *tdata)
60{
61 PJ_UNUSED_ARG(tdata);
62
63 if (++send_mod.count > send_mod.count_before_reject)
64 return PJ_ECANCELLED;
65 else
66 return PJ_SUCCESS;
67};
68
69
70/************************************************************************/
71/* Registrar for testing */
72static pj_bool_t regs_rx_request(pjsip_rx_data *rdata);
73
74enum contact_op
75{
76 NONE, /* don't put Contact header */
77 EXACT, /* return exact contact */
78 MODIFIED, /* return modified Contact header */
79};
80
81struct registrar_cfg
82{
83 pj_bool_t respond; /* should it respond at all */
84 unsigned status_code; /* final response status code */
85 pj_bool_t authenticate; /* should we authenticate? */
86 enum contact_op contact_op; /* What should we do with Contact */
87 unsigned expires_param; /* non-zero to put in expires param */
88 unsigned expires; /* non-zero to put in Expires header*/
89
90 pj_str_t more_contacts; /* Additional Contact headers to put*/
91};
92
93static struct registrar
94{
95 pjsip_module mod;
96 struct registrar_cfg cfg;
97 unsigned response_cnt;
98} registrar =
99{
100 {
101 NULL, NULL, /* prev, next. */
102 { "registrar", 9 }, /* Name. */
103 -1, /* Id */
104 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
105 NULL, /* load() */
106 NULL, /* start() */
107 NULL, /* stop() */
108 NULL, /* unload() */
109 &regs_rx_request, /* on_rx_request() */
110 NULL, /* on_rx_response() */
111 NULL, /* on_tx_request. */
112 NULL, /* on_tx_response() */
113 NULL, /* on_tsx_state() */
114 }
115};
116
117static pj_bool_t regs_rx_request(pjsip_rx_data *rdata)
118{
119 pjsip_msg *msg = rdata->msg_info.msg;
120 pjsip_hdr hdr_list;
121 int code;
122 pj_status_t status;
123
124 if (msg->line.req.method.id != PJSIP_REGISTER_METHOD)
125 return PJ_FALSE;
126
127 if (!registrar.cfg.respond)
128 return PJ_TRUE;
129
130 pj_list_init(&hdr_list);
131
132 if (registrar.cfg.authenticate &&
133 pjsip_msg_find_hdr(msg, PJSIP_H_AUTHORIZATION, NULL)==NULL)
134 {
135 pjsip_generic_string_hdr *hwww;
136 const pj_str_t hname = pj_str("WWW-Authenticate");
137 const pj_str_t hvalue = pj_str("Digest realm=\"test\"");
138
139 hwww = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname,
140 &hvalue);
141 pj_list_push_back(&hdr_list, hwww);
142
143 code = 401;
144
145 } else {
146 if (registrar.cfg.contact_op == EXACT ||
147 registrar.cfg.contact_op == MODIFIED)
148 {
149 pjsip_hdr *hsrc;
150
151 for (hsrc=msg->hdr.next; hsrc!=&msg->hdr; hsrc=hsrc->next) {
152 pjsip_contact_hdr *hdst;
153
154 if (hsrc->type != PJSIP_H_CONTACT)
155 continue;
156
157 hdst = (pjsip_contact_hdr*)
158 pjsip_hdr_clone(rdata->tp_info.pool, hsrc);
159
160 if (hdst->expires==0)
161 continue;
162
163 if (registrar.cfg.contact_op == MODIFIED) {
164 if (PJSIP_URI_SCHEME_IS_SIP(hdst->uri) ||
165 PJSIP_URI_SCHEME_IS_SIPS(hdst->uri))
166 {
167 pjsip_sip_uri *sip_uri = (pjsip_sip_uri*)
168 pjsip_uri_get_uri(hdst->uri);
169 sip_uri->host = pj_str("x-modified-host");
170 sip_uri->port = 1;
171 }
172 }
173
174 if (registrar.cfg.expires_param)
175 hdst->expires = registrar.cfg.expires_param;
176
177 pj_list_push_back(&hdr_list, hdst);
178 }
179 }
180
181 if (registrar.cfg.more_contacts.slen) {
182 pjsip_generic_string_hdr *hcontact;
183 const pj_str_t hname = pj_str("Contact");
184
185 hcontact = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname,
186 &registrar.cfg.more_contacts);
187 pj_list_push_back(&hdr_list, hcontact);
188 }
189
190 if (registrar.cfg.expires) {
191 pjsip_expires_hdr *hexp;
192
193 hexp = pjsip_expires_hdr_create(rdata->tp_info.pool,
194 registrar.cfg.expires);
195 pj_list_push_back(&hdr_list, hexp);
196 }
197
198 registrar.response_cnt++;
199
200 code = registrar.cfg.status_code;
201 }
202
203 status = pjsip_endpt_respond(endpt, NULL, rdata, code, NULL,
204 &hdr_list, NULL, NULL);
205 pj_assert(status == PJ_SUCCESS);
206
207 return PJ_TRUE;
208}
209
210
211/************************************************************************/
212/* Client registration test session */
213struct client
214{
215 /* Result/expected result */
216 int error;
217 int code;
218 pj_bool_t have_reg;
219 int expiration;
220 unsigned contact_cnt;
221 pj_bool_t auth;
222
223 /* Commands */
224 pj_bool_t destroy_on_cb;
225
226 /* Status */
227 pj_bool_t done;
228
229 /* Additional results */
230 int interval;
231 int next_reg;
232};
233
234/* regc callback */
235static void client_cb(struct pjsip_regc_cbparam *param)
236{
237 struct client *client = (struct client*) param->token;
238 pjsip_regc_info info;
239 pj_status_t status;
240
241 client->done = PJ_TRUE;
242
243 status = pjsip_regc_get_info(param->regc, &info);
244 pj_assert(status == PJ_SUCCESS);
245
246 client->error = (param->status != PJ_SUCCESS);
247 client->code = param->code;
248
249 if (client->error)
250 return;
251
252 client->have_reg = info.auto_reg && info.interval>0 &&
253 param->expiration>0;
254 client->expiration = param->expiration;
255 client->contact_cnt = param->contact_cnt;
256 client->interval = info.interval;
257 client->next_reg = info.next_reg;
258
259 if (client->destroy_on_cb)
260 pjsip_regc_destroy(param->regc);
261}
262
263
264/* Generic client test session */
265static struct client client_result;
266static int do_test(const char *title,
267 const struct registrar_cfg *srv_cfg,
268 const struct client *client_cfg,
269 const pj_str_t *registrar_uri,
270 unsigned contact_cnt,
271 const pj_str_t contacts[],
272 unsigned expires,
273 pj_bool_t leave_session,
274 pjsip_regc **p_regc)
275{
276 pjsip_regc *regc;
277 unsigned i;
278 const pj_str_t aor = pj_str("<sip:regc-test@pjsip.org>");
279 pjsip_tx_data *tdata;
280 pj_status_t status;
281
282 PJ_LOG(3,(THIS_FILE, " %s", title));
283
284 /* Modify registrar settings */
285 pj_memcpy(&registrar.cfg, srv_cfg, sizeof(*srv_cfg));
286
287 pj_bzero(&client_result, sizeof(client_result));
288 client_result.destroy_on_cb = client_cfg->destroy_on_cb;
289
290 status = pjsip_regc_create(endpt, &client_result, &client_cb, &regc);
291 if (status != PJ_SUCCESS)
292 return -100;
293
294 status = pjsip_regc_init(regc, registrar_uri, &aor, &aor, contact_cnt,
295 contacts, expires ? expires : 60);
296 if (status != PJ_SUCCESS) {
297 pjsip_regc_destroy(regc);
298 return -110;
299 }
300
301 if (client_cfg->auth) {
302 pjsip_cred_info cred;
303
304 pj_bzero(&cred, sizeof(cred));
305 cred.realm = pj_str("*");
306 cred.scheme = pj_str("digest");
307 cred.username = pj_str("user");
308 cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
309 cred.data = pj_str("password");
310
311 status = pjsip_regc_set_credentials(regc, 1, &cred);
312 if (status != PJ_SUCCESS) {
313 pjsip_regc_destroy(regc);
314 return -115;
315 }
316 }
317
318 /* Register */
319 status = pjsip_regc_register(regc, PJ_TRUE, &tdata);
320 if (status != PJ_SUCCESS) {
321 pjsip_regc_destroy(regc);
322 return -120;
323 }
324 status = pjsip_regc_send(regc, tdata);
325
326 /* That's it, wait until the callback is sent */
327 for (i=0; i<600 && !client_result.done; ++i) {
328 flush_events(100);
329 }
330
331 if (!client_result.done) {
332 PJ_LOG(3,(THIS_FILE, " error: test has timed out"));
333 pjsip_regc_destroy(regc);
334 return -200;
335 }
336
337 /* Destroy the regc, we're done with the test, unless we're
338 * instructed to leave the session open.
339 */
340 if (!leave_session && !client_cfg->destroy_on_cb)
341 pjsip_regc_destroy(regc);
342
343 /* Compare results with expected results */
344
345 if (client_result.error != client_cfg->error) {
346 PJ_LOG(3,(THIS_FILE, " error: expecting err=%d, got err=%d",
347 client_cfg->error, client_result.error));
348 return -210;
349 }
350 if (client_result.code != client_cfg->code &&
351 client_cfg->code != 502 && client_cfg->code != 503 &&
352 client_result.code != 502 && client_result.code != 503)
353 {
354 PJ_LOG(3,(THIS_FILE, " error: expecting code=%d, got code=%d",
355 client_cfg->code, client_result.code));
356 return -220;
357 }
358 if (client_result.expiration != client_cfg->expiration) {
359 PJ_LOG(3,(THIS_FILE, " error: expecting expiration=%d, got expiration=%d",
360 client_cfg->expiration, client_result.expiration));
361 return -240;
362 }
363 if (client_result.contact_cnt != client_cfg->contact_cnt) {
364 PJ_LOG(3,(THIS_FILE, " error: expecting contact_cnt=%d, got contact_cnt=%d",
365 client_cfg->contact_cnt, client_result.contact_cnt));
366 return -250;
367 }
368 if (client_result.have_reg != client_cfg->have_reg) {
369 PJ_LOG(3,(THIS_FILE, " error: expecting have_reg=%d, got have_reg=%d",
370 client_cfg->have_reg, client_result.have_reg));
371 return -260;
372 }
373 if (client_result.interval != client_result.expiration) {
374 PJ_LOG(3,(THIS_FILE, " error: interval (%d) is different than expiration (%d)",
375 client_result.interval, client_result.expiration));
376 return -270;
377 }
378 if (client_result.expiration > 0 && client_result.next_reg < 1) {
379 PJ_LOG(3,(THIS_FILE, " error: next_reg=%d, expecting positive number because expiration is %d",
380 client_result.next_reg, client_result.expiration));
381 return -280;
382 }
383
384 /* Looks like everything is okay. */
385 if (leave_session) {
386 *p_regc = regc;
387 }
388
389 return 0;
390}
391
392
393/************************************************************************/
394/* Customized tests */
395
396/* Check that client is sending register refresh */
397static int keep_alive_test(const pj_str_t *registrar_uri)
398{
399 enum { TIMEOUT = 40 };
400 struct registrar_cfg server_cfg =
401 /* respond code auth contact exp_prm expires more_contacts */
402 { PJ_TRUE, 200, PJ_FALSE, EXACT, TIMEOUT, 0, {NULL, 0}};
403 struct client client_cfg =
404 /* error code have_reg expiration contact_cnt auth? destroy*/
405 { PJ_FALSE, 200, PJ_TRUE, TIMEOUT, 1, PJ_FALSE,PJ_FALSE};
406 pj_str_t contact = pj_str("<sip:c@C>");
407
408
409 pjsip_regc *regc;
410 unsigned i;
411 int ret;
412
413 ret = do_test("register refresh (takes ~40 secs)", &server_cfg, &client_cfg, registrar_uri,
414 1, &contact, TIMEOUT, PJ_TRUE, &regc);
415 if (ret != 0)
416 return ret;
417
418 /* Reset server response_cnt */
419 registrar.response_cnt = 0;
420
421 /* Wait until keep-alive/refresh is done */
422 for (i=0; i<(TIMEOUT-1)*10 && registrar.response_cnt==0; ++i) {
423 flush_events(100);
424 }
425
426 if (registrar.response_cnt==0) {
427 PJ_LOG(3,(THIS_FILE, " error: no refresh is received"));
428 return -400;
429 }
430
431 if (client_result.error) {
432 PJ_LOG(3,(THIS_FILE, " error: got error"));
433 return -410;
434 }
435 if (client_result.code != 200) {
436 PJ_LOG(3,(THIS_FILE, " error: expecting code=%d, got code=%d",
437 200, client_result.code));
438 return -420;
439 }
440 if (client_result.expiration != TIMEOUT) {
441 PJ_LOG(3,(THIS_FILE, " error: expecting expiration=%d, got expiration=%d",
442 TIMEOUT, client_result.expiration));
443 return -440;
444 }
445 if (client_result.contact_cnt != 1) {
446 PJ_LOG(3,(THIS_FILE, " error: expecting contact_cnt=%d, got contact_cnt=%d",
447 TIMEOUT, client_result.contact_cnt));
448 return -450;
449 }
450 if (client_result.have_reg == 0) {
451 PJ_LOG(3,(THIS_FILE, " error: expecting have_reg=%d, got have_reg=%d",
452 1, client_result.have_reg));
453 return -460;
454 }
455 if (client_result.interval != TIMEOUT) {
456 PJ_LOG(3,(THIS_FILE, " error: interval (%d) is different than expiration (%d)",
457 client_result.interval, TIMEOUT));
458 return -470;
459 }
460 if (client_result.expiration > 0 && client_result.next_reg < 1) {
461 PJ_LOG(3,(THIS_FILE, " error: next_reg=%d, expecting positive number because expiration is %d",
462 client_result.next_reg, client_result.expiration));
463 return -480;
464 }
465
466 /* Success */
467 pjsip_regc_destroy(regc);
468 return 0;
469}
470
471
472/* Send error on refresh */
473static int refresh_error(const pj_str_t *registrar_uri,
474 pj_bool_t destroy_on_cb)
475{
476 enum { TIMEOUT = 40 };
477 struct registrar_cfg server_cfg =
478 /* respond code auth contact exp_prm expires more_contacts */
479 { PJ_TRUE, 200, PJ_FALSE, EXACT, TIMEOUT, 0, {NULL, 0}};
480 struct client client_cfg =
481 /* error code have_reg expiration contact_cnt auth? destroy*/
482 { PJ_FALSE, 200, PJ_TRUE, TIMEOUT, 1, PJ_FALSE,PJ_FALSE};
483 pj_str_t contact = pj_str("<sip:c@C>");
484
485 pjsip_regc *regc;
486 unsigned i;
487 int ret;
488
489 ret = do_test("refresh error (takes ~40 secs)", &server_cfg, &client_cfg, registrar_uri,
490 1, &contact, TIMEOUT, PJ_TRUE, &regc);
491 if (ret != 0)
492 return ret;
493
494 /* Reset server response_cnt */
495 registrar.response_cnt = 0;
496
497 /* inject error for transmission */
498 send_mod.count = 0;
499 send_mod.count_before_reject = 0;
500
501 /* reconfigure client */
502 client_result.done = PJ_FALSE;
503 client_result.destroy_on_cb = destroy_on_cb;
504
505 /* Wait until keep-alive/refresh is done */
506 for (i=0; i<TIMEOUT*10 && !client_result.done; ++i) {
507 flush_events(100);
508 }
509
510 send_mod.count_before_reject = 0xFFFF;
511
512 if (!destroy_on_cb)
513 pjsip_regc_destroy(regc);
514
515 if (!client_result.done) {
516 PJ_LOG(3,(THIS_FILE, " error: test has timed out"));
517 return -500;
518 }
519
520 /* Expecting error */
521 if (client_result.error==PJ_FALSE && client_result.code/100==2) {
522 PJ_LOG(3,(THIS_FILE, " error: expecting error got successfull result"));
523 return -510;
524 }
525
526 return PJ_SUCCESS;
527};
528
529
530/* Send error on refresh */
531static int update_test(const pj_str_t *registrar_uri)
532{
533 enum { TIMEOUT = 40 };
534 struct registrar_cfg server_cfg =
535 /* respond code auth contact exp_prm expires more_contacts */
536 { PJ_TRUE, 200, PJ_FALSE, EXACT, TIMEOUT, 0, {NULL, 0}};
537 struct client client_cfg =
538 /* error code have_reg expiration contact_cnt auth? destroy*/
539 { PJ_FALSE, 200, PJ_TRUE, TIMEOUT, 1, PJ_FALSE,PJ_FALSE};
540 pj_str_t contacts[] = {
541 { "<sip:a>", 7 },
542 { "<sip:b>", 7 },
543 { "<sip:c>", 7 }
544 };
545
546 pjsip_regc *regc;
547 pjsip_contact_hdr *h1, *h2;
548 pjsip_sip_uri *u1, *u2;
549 unsigned i;
550 pj_status_t status;
551 pjsip_tx_data *tdata = NULL;
552 int ret = 0;
553
554 /* initially only has 1 contact */
555 ret = do_test("update test", &server_cfg, &client_cfg, registrar_uri,
556 1, &contacts[0], TIMEOUT, PJ_TRUE, &regc);
557 if (ret != 0) {
558 return -600;
559 }
560
561 /*****
562 * replace the contact with new one
563 */
564 PJ_LOG(3,(THIS_FILE, " replacing contact"));
565 status = pjsip_regc_update_contact(regc, 1, &contacts[1]);
566 if (status != PJ_SUCCESS) {
567 ret = -610;
568 goto on_return;
569 }
570
571 status = pjsip_regc_register(regc, PJ_TRUE, &tdata);
572 if (status != PJ_SUCCESS) {
573 ret = -620;
574 goto on_return;
575 }
576
577 /* Check that the REGISTER contains two Contacts:
578 * - <sip:a>;expires=0,
579 * - <sip:b>
580 */
581 h1 = (pjsip_contact_hdr*)
582 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
583 if (!h1) {
584 ret = -630;
585 goto on_return;
586 }
587 if ((void*)h1->next == (void*)&tdata->msg->hdr)
588 h2 = NULL;
589 else
590 h2 = (pjsip_contact_hdr*)
591 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h1->next);
592 if (!h2) {
593 ret = -640;
594 goto on_return;
595 }
596 /* must not have other Contact header */
597 if ((void*)h2->next != (void*)&tdata->msg->hdr &&
598 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h2->next) != NULL)
599 {
600 ret = -645;
601 goto on_return;
602 }
603
604 u1 = (pjsip_sip_uri*) pjsip_uri_get_uri(h1->uri);
605 u2 = (pjsip_sip_uri*) pjsip_uri_get_uri(h2->uri);
606
607 if (*u1->host.ptr == 'a') {
608 if (h1->expires != 0) {
609 ret = -650;
610 goto on_return;
611 }
612 if (h2->expires == 0) {
613 ret = -660;
614 goto on_return;
615 }
616
617 } else {
618 pj_assert(*u1->host.ptr == 'b');
619 if (h1->expires == 0) {
620 ret = -670;
621 goto on_return;
622 }
623 if (h2->expires != 0) {
624 ret = -680;
625 goto on_return;
626 }
627 }
628
629 /* Destroy tdata */
630 pjsip_tx_data_dec_ref(tdata);
631 tdata = NULL;
632
633
634
635 /**
636 * First loop, it will update with more contacts. Second loop
637 * should do nothing.
638 */
639 for (i=0; i<2; ++i) {
640 if (i==0)
641 PJ_LOG(3,(THIS_FILE, " replacing with more contacts"));
642 else
643 PJ_LOG(3,(THIS_FILE, " updating contacts with same contacts"));
644
645 status = pjsip_regc_update_contact(regc, 2, &contacts[1]);
646 if (status != PJ_SUCCESS) {
647 ret = -710;
648 goto on_return;
649 }
650
651 status = pjsip_regc_register(regc, PJ_TRUE, &tdata);
652 if (status != PJ_SUCCESS) {
653 ret = -720;
654 goto on_return;
655 }
656
657 /* Check that the REGISTER contains two Contacts:
658 * - <sip:b>
659 * - <sip:c>
660 */
661 h1 = (pjsip_contact_hdr*)
662 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
663 if (!h1) {
664 ret = -730;
665 goto on_return;
666 }
667 if ((void*)h1->next == (void*)&tdata->msg->hdr)
668 h2 = NULL;
669 else
670 h2 = (pjsip_contact_hdr*)
671 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h1->next);
672 if (!h2) {
673 ret = -740;
674 goto on_return;
675 }
676 /* must not have other Contact header */
677 if ((void*)h2->next != (void*)&tdata->msg->hdr &&
678 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h2->next) != NULL)
679 {
680 ret = -745;
681 goto on_return;
682 }
683
684 /* both contacts must not have expires=0 parameter */
685 if (h1->expires == 0) {
686 ret = -750;
687 goto on_return;
688 }
689 if (h2->expires == 0) {
690 ret = -760;
691 goto on_return;
692 }
693
694 /* Destroy tdata */
695 pjsip_tx_data_dec_ref(tdata);
696 tdata = NULL;
697 }
698
699on_return:
700 if (tdata) pjsip_tx_data_dec_ref(tdata);
701 pjsip_regc_destroy(regc);
702 return ret;
703};
704
705
706/* send error on authentication */
707static int auth_send_error(const pj_str_t *registrar_uri,
708 pj_bool_t destroy_on_cb)
709{
710 enum { TIMEOUT = 40 };
711 struct registrar_cfg server_cfg =
712 /* respond code auth contact exp_prm expires more_contacts */
713 { PJ_TRUE, 200, PJ_TRUE, EXACT, 75, 0, {NULL, 0}};
714 struct client client_cfg =
715 /* error code have_reg expiration contact_cnt auth? destroy*/
716 { PJ_TRUE, 401, PJ_FALSE, -1, 0, PJ_TRUE, PJ_TRUE};
717 pj_str_t contact = pj_str("<sip:c@C>");
718
719 pjsip_regc *regc;
720 int ret;
721
722 client_cfg.destroy_on_cb = destroy_on_cb;
723
724 /* inject error for second request retry */
725 send_mod.count = 0;
726 send_mod.count_before_reject = 1;
727
728 ret = do_test("auth send error", &server_cfg, &client_cfg, registrar_uri,
729 1, &contact, TIMEOUT, PJ_TRUE, &regc);
730
731 send_mod.count_before_reject = 0xFFFF;
732
733 return ret;
734};
735
736
737
738
739/************************************************************************/
740enum
741{
742 OFF = 1,
743 ON = 2,
744 ON_OFF = 3,
745};
746
747int regc_test(void)
748{
749 struct test_rec {
750 unsigned check_contact;
751 unsigned add_xuid_param;
752
753 const char *title;
754 char *alt_registrar;
755 unsigned contact_cnt;
756 char *contacts[4];
757 unsigned expires;
758 struct registrar_cfg server_cfg;
759 struct client client_cfg;
760 } test_rec[] =
761 {
762 /* immediate error */
763 {
764 OFF, /* check_contact */
765 OFF, /* add_xuid_param */
766 "immediate error", /* title */
767 "sip:unresolved-host-xyy", /* alt_registrar */
768 1, /* contact cnt */
769 { "sip:user@127.0.0.1:5060" }, /* contacts[] */
770 600, /* expires */
771
772 /* registrar config: */
773 /* respond code auth contact exp_prm expires more_contacts */
774 { PJ_FALSE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}},
775
776 /* client expected results: */
777 /* error code have_reg expiration contact_cnt auth?*/
778 { PJ_FALSE, 502, PJ_FALSE, -1, 0, PJ_FALSE}
779 },
780
781 /* timeout test */
782 {
783 OFF, /* check_contact */
784 OFF, /* add_xuid_param */
785 "timeout test (takes ~32 secs)",/* title */
786 NULL, /* alt_registrar */
787 1, /* contact cnt */
788 { "sip:user@127.0.0.1:5060" }, /* contacts[] */
789 600, /* expires */
790
791 /* registrar config: */
792 /* respond code auth contact exp_prm expires more_contacts */
793 { PJ_FALSE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}},
794
795 /* client expected results: */
796 /* error code have_reg expiration contact_cnt auth? */
797 { PJ_FALSE, 408, PJ_FALSE, -1, 0, PJ_FALSE}
798 },
799
800 /* Basic successful registration scenario:
801 * a good registrar returns the Contact header as is and
802 * add expires parameter. In this test no additional bindings
803 * are returned.
804 */
805 {
806 ON_OFF, /* check_contact */
807 ON_OFF, /* add_xuid_param */
808 "basic", /* title */
809 NULL, /* alt_registrar */
810 1, /* contact cnt */
811 { "<sip:user@127.0.0.1:5060;transport=udp;x-param=1234>" }, /* contacts[] */
812 600, /* expires */
813
814 /* registrar config: */
815 /* respond code auth contact exp_prm expires more_contacts */
816 { PJ_TRUE, 200, PJ_FALSE, EXACT, 75, 65, {NULL, 0}},
817
818 /* client expected results: */
819 /* error code have_reg expiration contact_cnt auth?*/
820 { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_FALSE}
821 },
822
823 /* Basic successful registration scenario with authentication
824 */
825 {
826 ON_OFF, /* check_contact */
827 ON_OFF, /* add_xuid_param */
828 "authentication", /* title */
829 NULL, /* alt_registrar */
830 1, /* contact cnt */
831 { "<sip:user@127.0.0.1:5060;transport=udp;x-param=1234>" }, /* contacts[] */
832 600, /* expires */
833
834 /* registrar config: */
835 /* respond code auth contact exp_prm expires more_contacts */
836 { PJ_TRUE, 200, PJ_TRUE, EXACT, 75, 65, {NULL, 0}},
837
838 /* client expected results: */
839 /* error code have_reg expiration contact_cnt auth?*/
840 { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_TRUE}
841 },
842
843 /* a good registrar returns the Contact header as is and
844 * add expires parameter. Also it adds bindings from other
845 * clients in this test.
846 */
847 {
848 ON_OFF, /* check_contact */
849 ON, /* add_xuid_param */
850 "more bindings in response", /* title */
851 NULL, /* alt_registrar */
852 1, /* contact cnt */
853 { "<sip:user@127.0.0.1:5060;transport=udp>" }, /* contacts[] */
854 600, /* expires */
855
856 /* registrar config: */
857 /* respond code auth contact exp_prm expires more_contacts */
858 { PJ_TRUE, 200, PJ_FALSE, EXACT, 75, 65, {"<sip:a@a>;expires=70", 0}},
859
860 /* client expected results: */
861 /* error code have_reg expiration contact_cnt auth?*/
862 { PJ_FALSE, 200, PJ_TRUE, 75, 2, PJ_FALSE}
863 },
864
865
866 /* a bad registrar returns modified Contact header, but it
867 * still returns all parameters intact. In this case
868 * the expiration is taken from the expires param because
869 * of matching xuid param or because the number of
870 * Contact header matches.
871 */
872 {
873 ON_OFF, /* check_contact */
874 ON_OFF, /* add_xuid_param */
875 "registrar modifies Contact header", /* title */
876 NULL, /* alt_registrar */
877 1, /* contact cnt */
878 { "<sip:user@127.0.0.1:5060>" }, /* contacts[] */
879 600, /* expires */
880
881 /* registrar config: */
882 /* respond code auth contact exp_prm expires more_contacts */
883 { PJ_TRUE, 200, PJ_FALSE, MODIFIED, 75, 65, {NULL, 0}},
884
885 /* client expected results: */
886 /* error code have_reg expiration contact_cnt auth?*/
887 { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_FALSE}
888 },
889
890
891 /* a bad registrar returns modified Contact header, but it
892 * still returns all parameters intact. In addition it returns
893 * bindings from other clients.
894 *
895 * In this case the expiration is taken from the expires param
896 * because add_xuid_param is enabled.
897 */
898 {
899 ON_OFF, /* check_contact */
900 ON, /* add_xuid_param */
901 "registrar modifies Contact header and add bindings", /* title */
902 NULL, /* alt_registrar */
903 1, /* contact cnt */
904 { "<sip:user@127.0.0.1:5060>" }, /* contacts[] */
905 600, /* expires */
906
907 /* registrar config: */
908 /* respond code auth contact exp_prm expires more_contacts */
909 { PJ_TRUE, 200, PJ_FALSE, MODIFIED, 75, 65, {"<sip:a@a>;expires=70", 0}},
910
911 /* client expected results: */
912 /* error code have_reg expiration contact_cnt auth?*/
913 { PJ_FALSE, 200, PJ_TRUE, 75, 2, PJ_FALSE}
914 },
915
916
917 /* a bad registrar returns completely different Contact and
918 * all parameters are gone. In this case the expiration is
919 * also taken from the expires param since the number of
920 * header matches.
921 */
922 {
923 ON_OFF, /* check_contact */
924 ON_OFF, /* add_xuid_param */
925 "registrar replaces Contact header", /* title */
926 NULL, /* alt_registrar */
927 1, /* contact cnt */
928 { "<sip:user@127.0.0.1:5060>" }, /* contacts[] */
929 600, /* expires */
930
931 /* registrar config: */
932 /* respond code auth contact exp_prm expires more_contacts */
933 { PJ_TRUE, 202, PJ_FALSE, NONE, 0, 65, {"<sip:a@A>;expires=75", 0}},
934
935 /* client expected results: */
936 /* error code have_reg expiration contact_cnt auth?*/
937 { PJ_FALSE, 202, PJ_TRUE, 75, 1, PJ_FALSE}
938 },
939
940
941 /* a bad registrar returns completely different Contact (and
942 * all parameters are gone) and it also includes bindings from
943 * other clients.
944 * In this case the expiration is taken from the Expires header.
945 */
946 {
947 ON_OFF, /* check_contact */
948 ON_OFF, /* add_xuid_param */
949 " as above with additional bindings", /* title */
950 NULL, /* alt_registrar */
951 1, /* contact cnt */
952 { "<sip:user@127.0.0.1:5060>" }, /* contacts[] */
953 600, /* expires */
954
955 /* registrar config: */
956 /* respond code auth contact exp_prm expires more_contacts */
957 { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 65, {"<sip:a@A>;expires=75, <sip:b@B;expires=70>", 0}},
958
959 /* client expected results: */
960 /* error code have_reg expiration contact_cnt auth?*/
961 { PJ_FALSE, 200, PJ_TRUE, 65, 2, PJ_FALSE}
962 },
963
964 /* the registrar doesn't return any bindings, but for some
965 * reason it includes an Expires header.
966 * In this case the expiration is taken from the Expires header.
967 */
968 {
969 ON_OFF, /* check_contact */
970 ON_OFF, /* add_xuid_param */
971 "no Contact but with Expires", /* title */
972 NULL, /* alt_registrar */
973 1, /* contact cnt */
974 { "<sip:user@127.0.0.1:5060>" }, /* contacts[] */
975 600, /* expires */
976
977 /* registrar config: */
978 /* respond code auth contact exp_prm expires more_contacts */
979 { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 65, {NULL, 0}},
980
981 /* client expected results: */
982 /* error code have_reg expiration contact_cnt auth?*/
983 { PJ_FALSE, 200, PJ_TRUE, 65, 0, PJ_FALSE}
984 },
985
986 /* Neither Contact header nor Expires header are present.
987 * In this case the expiration is taken from the request.
988 */
989 {
990 ON_OFF, /* check_contact */
991 ON_OFF, /* add_xuid_param */
992 "no Contact and no Expires", /* title */
993 NULL, /* alt_registrar */
994 1, /* contact cnt */
995 { "<sip:user@127.0.0.1:5060>" },/* contacts[] */
996 600, /* expires */
997
998 /* registrar config: */
999 /* respond code auth contact exp_prm expires more_contacts */
1000 { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}},
1001
1002 /* client expected results: */
1003 /* error code have_reg expiration contact_cnt auth?*/
1004 { PJ_FALSE, 200, PJ_TRUE, 600, 0, PJ_FALSE}
1005 },
1006 };
1007
1008 unsigned i;
1009 pj_sockaddr_in addr;
1010 pjsip_transport *udp = NULL;
1011 pj_uint16_t port;
1012 char registrar_uri_buf[80];
1013 pj_str_t registrar_uri;
1014 int rc = 0;
1015
1016 pj_sockaddr_in_init(&addr, 0, 0);
1017
1018 /* Acquire existing transport, if any */
1019 rc = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, &addr, sizeof(addr), NULL, &udp);
1020 if (rc == PJ_SUCCESS) {
1021 port = pj_sockaddr_get_port(&udp->local_addr);
1022 pjsip_transport_dec_ref(udp);
1023 udp = NULL;
1024 } else {
1025 rc = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &udp);
1026 if (rc != PJ_SUCCESS) {
1027 app_perror(" error creating UDP transport", rc);
1028 rc = -2;
1029 goto on_return;
1030 }
1031
1032 port = pj_sockaddr_get_port(&udp->local_addr);
1033 }
1034
1035 /* Register registrar module */
1036 rc = pjsip_endpt_register_module(endpt, &registrar.mod);
1037 if (rc != PJ_SUCCESS) {
1038 app_perror(" error registering module", rc);
1039 rc = -3;
1040 goto on_return;
1041 }
1042
1043 /* Register send module */
1044 rc = pjsip_endpt_register_module(endpt, &send_mod.mod);
1045 if (rc != PJ_SUCCESS) {
1046 app_perror(" error registering module", rc);
1047 rc = -3;
1048 goto on_return;
1049 }
1050
1051 pj_ansi_snprintf(registrar_uri_buf, sizeof(registrar_uri_buf),
1052 "sip:127.0.0.1:%d", (int)port);
1053 registrar_uri = pj_str(registrar_uri_buf);
1054
1055 for (i=0; i<PJ_ARRAY_SIZE(test_rec); ++i) {
1056 struct test_rec *t = &test_rec[i];
1057 unsigned j, x;
1058 pj_str_t reg_uri;
1059 pj_str_t contacts[8];
1060
1061 /* Fill in the registrar address if it's not specified */
1062 if (t->alt_registrar == NULL) {
1063 reg_uri = registrar_uri;
1064 } else {
1065 reg_uri = pj_str(t->alt_registrar);
1066 }
1067
1068 /* Build contact pj_str_t's */
1069 for (j=0; j<t->contact_cnt; ++j) {
1070 contacts[j] = pj_str(t->contacts[j]);
1071 }
1072
1073 /* Normalize more_contacts field */
1074 if (t->server_cfg.more_contacts.ptr)
1075 t->server_cfg.more_contacts.slen = strlen(t->server_cfg.more_contacts.ptr);
1076
1077 /* Do tests with three combinations:
1078 * - check_contact on/off
1079 * - add_xuid_param on/off
1080 * - destroy_on_callback on/off
1081 */
1082 for (x=1; x<=2; ++x) {
1083 unsigned y;
1084
1085 if ((t->check_contact & x) == 0)
1086 continue;
1087
1088 pjsip_cfg()->regc.check_contact = (x-1);
1089
1090 for (y=1; y<=2; ++y) {
1091 unsigned z;
1092
1093 if ((t->add_xuid_param & y) == 0)
1094 continue;
1095
1096 pjsip_cfg()->regc.add_xuid_param = (y-1);
1097
1098 for (z=0; z<=1; ++z) {
1099 char new_title[200];
1100
1101 t->client_cfg.destroy_on_cb = z;
1102
1103 sprintf(new_title, "%s [check=%d, xuid=%d, destroy=%d]",
1104 t->title, pjsip_cfg()->regc.check_contact,
1105 pjsip_cfg()->regc.add_xuid_param, z);
1106 rc = do_test(new_title, &t->server_cfg, &t->client_cfg,
1107 &reg_uri, t->contact_cnt, contacts,
1108 t->expires, PJ_FALSE, NULL);
1109 if (rc != 0)
1110 goto on_return;
1111 }
1112
1113 }
1114 }
1115
1116 /* Sleep between test groups to avoid using up too many
1117 * active transactions.
1118 */
1119 pj_thread_sleep(1000);
1120 }
1121
1122 /* keep-alive test */
1123 rc = keep_alive_test(&registrar_uri);
1124 if (rc != 0)
1125 goto on_return;
1126
1127 /* Send error on refresh without destroy on callback */
1128 rc = refresh_error(&registrar_uri, PJ_FALSE);
1129 if (rc != 0)
1130 goto on_return;
1131
1132 /* Send error on refresh, destroy on callback */
1133 rc = refresh_error(&registrar_uri, PJ_TRUE);
1134 if (rc != 0)
1135 goto on_return;
1136
1137 /* Updating contact */
1138 rc = update_test(&registrar_uri);
1139 if (rc != 0)
1140 goto on_return;
1141
1142 /* Send error during auth, don't destroy on callback */
1143 rc = auth_send_error(&registrar_uri, PJ_FALSE);
1144 if (rc != 0)
1145 goto on_return;
1146
1147 /* Send error during auth, destroy on callback */
1148 rc = auth_send_error(&registrar_uri, PJ_FALSE);
1149 if (rc != 0)
1150 goto on_return;
1151
1152on_return:
1153 if (registrar.mod.id != -1) {
1154 pjsip_endpt_unregister_module(endpt, &registrar.mod);
1155 }
1156 if (send_mod.mod.id != -1) {
1157 pjsip_endpt_unregister_module(endpt, &send_mod.mod);
1158 }
1159 if (udp) {
1160 pjsip_transport_dec_ref(udp);
1161 }
1162 return rc;
1163}
1164
1165