Wed Jan 8 2020 09:49:46

Asterisk developer's documentation


config_parser.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16 
17 /*!
18  * \file
19  * \brief sip config parsing functions and unit tests
20  */
21 
22 /*** MODULEINFO
23  <support_level>core</support_level>
24  ***/
25 
26 #include "asterisk.h"
27 
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
29 
30 #include "include/sip.h"
31 #include "include/config_parser.h"
32 #include "include/sip_utils.h"
33 
34 /*! \brief Parse register=> line in sip.conf
35  *
36  * \retval 0 on success
37  * \retval -1 on failure
38  */
39 int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno)
40 {
41  int portnum = 0;
42  int domainport = 0;
43  enum sip_transport transport = SIP_TRANSPORT_UDP;
44  char buf[256] = "";
45  char *userpart = NULL, *hostpart = NULL;
46  /* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] */
48  AST_APP_ARG(peer);
49  AST_APP_ARG(userpart);
50  );
52  AST_APP_ARG(transport);
53  AST_APP_ARG(blank);
54  AST_APP_ARG(userpart);
55  );
57  AST_APP_ARG(userpart);
59  AST_APP_ARG(authuser);
60  );
63  AST_APP_ARG(domain);
64  );
66  AST_APP_ARG(authuser);
67  AST_APP_ARG(domainport);
68  );
70  AST_APP_ARG(hostpart);
71  AST_APP_ARG(expiry);
72  );
74  AST_APP_ARG(hostpart);
76  );
78  AST_APP_ARG(host);
79  AST_APP_ARG(port);
80  );
81 
82  if (!value) {
83  return -1;
84  }
85 
86  if (!reg) {
87  return -1;
88  }
89  ast_copy_string(buf, value, sizeof(buf));
90 
91  /*! register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
92  * becomes
93  * userpart => [peer?][transport://]user[@domain][:secret[:authuser]]
94  * hostpart => host[:port][/extension][~expiry]
95  */
96  if ((hostpart = strrchr(buf, '@'))) {
97  *hostpart++ = '\0';
98  userpart = buf;
99  }
100 
101  if (ast_strlen_zero(userpart) || ast_strlen_zero(hostpart)) {
102  ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
103  return -1;
104  }
105 
106  /*!
107  * pre1.peer => peer
108  * pre1.userpart => [transport://]user[@domain][:secret[:authuser]]
109  * hostpart => host[:port][/extension][~expiry]
110  */
111  AST_NONSTANDARD_RAW_ARGS(pre1, userpart, '?');
112  if (ast_strlen_zero(pre1.userpart)) {
113  pre1.userpart = pre1.peer;
114  pre1.peer = NULL;
115  }
116 
117  /*!
118  * pre1.peer => peer
119  * pre2.transport = transport
120  * pre2.userpart => user[@domain][:secret[:authuser]]
121  * hostpart => host[:port][/extension][~expiry]
122  */
123  AST_NONSTANDARD_RAW_ARGS(pre2, pre1.userpart, '/');
124  if (ast_strlen_zero(pre2.userpart)) {
125  pre2.userpart = pre2.transport;
126  pre2.transport = NULL;
127  } else {
128  pre2.transport[strlen(pre2.transport) - 1] = '\0'; /* Remove trailing : */
129  }
130 
131  if (!ast_strlen_zero(pre2.blank)) {
132  ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
133  return -1;
134  }
135 
136  /*!
137  * pre1.peer => peer
138  * pre2.transport = transport
139  * user1.userpart => user[@domain]
140  * user1.secret => secret
141  * user1.authuser => authuser
142  * hostpart => host[:port][/extension][~expiry]
143  */
144  AST_NONSTANDARD_RAW_ARGS(user1, pre2.userpart, ':');
145 
146  /*!
147  * pre1.peer => peer
148  * pre2.transport = transport
149  * user1.userpart => user[@domain]
150  * user1.secret => secret
151  * user1.authuser => authuser
152  * host1.hostpart => host[:port][/extension]
153  * host1.expiry => [expiry]
154  */
155  AST_NONSTANDARD_RAW_ARGS(host1, hostpart, '~');
156 
157  /*!
158  * pre1.peer => peer
159  * pre2.transport = transport
160  * user1.userpart => user[@domain]
161  * user1.secret => secret
162  * user1.authuser => authuser
163  * host2.hostpart => host[:port]
164  * host2.extension => [extension]
165  * host1.expiry => [expiry]
166  */
167  AST_NONSTANDARD_RAW_ARGS(host2, host1.hostpart, '/');
168 
169  /*!
170  * pre1.peer => peer
171  * pre2.transport = transport
172  * user1.userpart => user[@domain]
173  * user1.secret => secret
174  * user1.authuser => authuser
175  * host3.host => host
176  * host3.port => port
177  * host2.extension => extension
178  * host1.expiry => expiry
179  */
180  AST_NONSTANDARD_RAW_ARGS(host3, host2.hostpart, ':');
181 
182  /*!
183  * pre1.peer => peer
184  * pre2.transport = transport
185  * user2.user => user
186  * user2.domain => domain
187  * user1.secret => secret
188  * user1.authuser => authuser
189  * host3.host => host
190  * host3.port => port
191  * host2.extension => extension
192  * host1.expiry => expiry
193  */
194  AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@');
195 
196  /*!
197  * pre1.peer => peer
198  * pre2.transport = transport
199  * user2.user => user
200  * user2.domain => domain
201  * user1.secret => secret
202  * user3.authuser => authuser
203  * user3.domainport => domainport
204  * host3.host => host
205  * host3.port => port
206  * host2.extension => extension
207  * host1.expiry => expiry
208  */
209  AST_NONSTANDARD_RAW_ARGS(user3, user1.authuser, ':');
210 
211  /* Reordering needed due to fields being [(:secret[:username])|(:regdomainport:secret:username)]
212  but parsing being [secret[:username[:regdomainport]]] */
213  if (user3.argc == 2) {
214  char *reorder = user3.domainport;
215  user3.domainport = user1.secret;
216  user1.secret = user3.authuser;
217  user3.authuser = reorder;
218  }
219 
220  if (host3.port) {
221  if (!(portnum = port_str2int(host3.port, 0))) {
222  ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", host3.port, lineno);
223  }
224  }
225  if (user3.domainport) {
226  if (!(domainport = port_str2int(user3.domainport, 0))) {
227  ast_log(LOG_NOTICE, "'%s' is not a valid domain port number on line %d of sip.conf. using default.\n", user3.domainport, lineno);
228  }
229  }
230 
231  /* set transport type */
232  if (!pre2.transport) {
233  transport = SIP_TRANSPORT_UDP;
234  } else if (!strncasecmp(pre2.transport, "tcp", 3)) {
235  transport = SIP_TRANSPORT_TCP;
236  } else if (!strncasecmp(pre2.transport, "tls", 3)) {
237  transport = SIP_TRANSPORT_TLS;
238  } else if (!strncasecmp(pre2.transport, "udp", 3)) {
239  transport = SIP_TRANSPORT_UDP;
240  } else {
241  transport = SIP_TRANSPORT_UDP;
242  ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", pre2.transport, lineno);
243  }
244 
245  /* if no portnum specified, set default for transport */
246  if (!portnum) {
247  if (transport == SIP_TRANSPORT_TLS) {
248  portnum = STANDARD_TLS_PORT;
249  } else {
250  portnum = STANDARD_SIP_PORT;
251  }
252  }
253 
254  /* copy into sip_registry object */
255  ast_string_field_set(reg, callback, ast_strip_quoted(S_OR(host2.extension, "s"), "\"", "\""));
256  ast_string_field_set(reg, username, ast_strip_quoted(S_OR(user2.user, ""), "\"", "\""));
257  ast_string_field_set(reg, hostname, ast_strip_quoted(S_OR(host3.host, ""), "\"", "\""));
258  ast_string_field_set(reg, authuser, ast_strip_quoted(S_OR(user3.authuser, ""), "\"", "\""));
259  ast_string_field_set(reg, secret, ast_strip_quoted(S_OR(user1.secret, ""), "\"", "\""));
260  ast_string_field_set(reg, peername, ast_strip_quoted(S_OR(pre1.peer, ""), "\"", "\""));
261  ast_string_field_set(reg, regdomain, ast_strip_quoted(S_OR(user2.domain, ""), "\"", "\""));
262 
263  reg->transport = transport;
264  reg->timeout = reg->expire = -1;
265  reg->portno = portnum;
266  reg->regdomainport = domainport;
267  reg->callid_valid = FALSE;
268  reg->ocseq = INITIAL_CSEQ;
269  reg->refresh = reg->expiry = reg->configured_expiry = (host1.expiry ? atoi(ast_strip_quoted(host1.expiry, "\"", "\"")) : default_expiry);
270 
271  return 0;
272 }
273 
274 AST_TEST_DEFINE(sip_parse_register_line_test)
275 {
276  int res = AST_TEST_PASS;
277  struct sip_registry *reg;
278  int default_expiry = 120;
279  const char *reg1 = "name@domain";
280  const char *reg2 = "name:pass@domain";
281  const char *reg3 = "name@namedomain:pass:authuser@domain";
282  const char *reg4 = "name@namedomain:pass:authuser@domain/extension";
283  const char *reg5 = "tcp://name@namedomain:pass:authuser@domain/extension";
284  const char *reg6 = "tls://name@namedomain:pass:authuser@domain/extension~111";
285  const char *reg7 = "peer?tcp://name@namedomain:pass:authuser@domain:1234/extension~111";
286  const char *reg8 = "peer?name@namedomain:pass:authuser@domain:1234/extension~111";
287  const char *reg9 = "peer?name:pass:authuser:1234/extension~111";
288  const char *reg10 = "@domin:1234";
289  const char *reg12 = "name@namedomain:4321:pass:authuser@domain";
290  const char *reg13 = "name@namedomain:4321::@domain";
291 
292  switch (cmd) {
293  case TEST_INIT:
294  info->name = "sip_parse_register_line_test";
295  info->category = "/channels/chan_sip/";
296  info->summary = "tests sip register line parsing";
297  info->description =
298  "Tests parsing of various register line configurations. "
299  "Verifies output matches expected behavior.";
300  return AST_TEST_NOT_RUN;
301  case TEST_EXECUTE:
302  break;
303  }
304 
305  /* ---Test reg 1, simple config --- */
306  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
307  goto alloc_fail;
308  } else if (
309  sip_parse_register_line(reg, default_expiry, reg1, 1) ||
310  strcmp(reg->callback, "s") ||
311  strcmp(reg->username, "name") ||
312  strcmp(reg->regdomain, "") ||
313  strcmp(reg->hostname, "domain") ||
314  strcmp(reg->authuser, "") ||
315  strcmp(reg->secret, "") ||
316  strcmp(reg->peername, "") ||
317  reg->transport != SIP_TRANSPORT_UDP ||
318  reg->timeout != -1 ||
319  reg->expire != -1 ||
320  reg->refresh != default_expiry ||
321  reg->expiry != default_expiry ||
322  reg->configured_expiry != default_expiry ||
323  reg->portno != STANDARD_SIP_PORT ||
324  (reg->regdomainport) ||
325  reg->callid_valid != FALSE ||
326  reg->ocseq != INITIAL_CSEQ) {
327 
328  ast_test_status_update(test, "Test 1: simple config failed\n");
329  res = AST_TEST_FAIL;
330  }
332  ast_free(reg);
333 
334  /* ---Test reg 2, add secret --- */
335  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
336  goto alloc_fail;
337  } else if (
338  sip_parse_register_line(reg, default_expiry, reg2, 1) ||
339  strcmp(reg->callback, "s") ||
340  strcmp(reg->username, "name") ||
341  strcmp(reg->regdomain, "") ||
342  strcmp(reg->hostname, "domain") ||
343  strcmp(reg->authuser, "") ||
344  strcmp(reg->secret, "pass") ||
345  strcmp(reg->peername, "") ||
346  reg->transport != SIP_TRANSPORT_UDP ||
347  reg->timeout != -1 ||
348  reg->expire != -1 ||
349  reg->refresh != default_expiry ||
350  reg->expiry != default_expiry ||
351  reg->configured_expiry != default_expiry ||
352  reg->portno != STANDARD_SIP_PORT ||
353  (reg->regdomainport) ||
354  reg->callid_valid != FALSE ||
355  reg->ocseq != INITIAL_CSEQ) {
356 
357  ast_test_status_update(test, "Test 2: add secret failed\n");
358  res = AST_TEST_FAIL;
359  }
361  ast_free(reg);
362 
363  /* ---Test reg 3, add userdomain and authuser --- */
364  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
365  goto alloc_fail;
366  } else if (
367  sip_parse_register_line(reg, default_expiry, reg3, 1) ||
368  strcmp(reg->callback, "s") ||
369  strcmp(reg->username, "name") ||
370  strcmp(reg->regdomain, "namedomain") ||
371  strcmp(reg->hostname, "domain") ||
372  strcmp(reg->authuser, "authuser") ||
373  strcmp(reg->secret, "pass") ||
374  strcmp(reg->peername, "") ||
375  reg->transport != SIP_TRANSPORT_UDP ||
376  reg->timeout != -1 ||
377  reg->expire != -1 ||
378  reg->refresh != default_expiry ||
379  reg->expiry != default_expiry ||
380  reg->configured_expiry != default_expiry ||
381  reg->portno != STANDARD_SIP_PORT ||
382  (reg->regdomainport) ||
383  reg->callid_valid != FALSE ||
384  reg->ocseq != INITIAL_CSEQ) {
385 
386  ast_test_status_update(test, "Test 3: add userdomain and authuser failed\n");
387  res = AST_TEST_FAIL;
388  }
390  ast_free(reg);
391 
392  /* ---Test reg 4, add callback extension --- */
393  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
394  goto alloc_fail;
395  } else if (
396  sip_parse_register_line(reg, default_expiry, reg4, 1) ||
397  strcmp(reg->callback, "extension") ||
398  strcmp(reg->username, "name") ||
399  strcmp(reg->regdomain, "namedomain") ||
400  strcmp(reg->hostname, "domain") ||
401  strcmp(reg->authuser, "authuser") ||
402  strcmp(reg->secret, "pass") ||
403  strcmp(reg->peername, "") ||
404  reg->transport != SIP_TRANSPORT_UDP ||
405  reg->timeout != -1 ||
406  reg->expire != -1 ||
407  reg->refresh != default_expiry ||
408  reg->expiry != default_expiry ||
409  reg->configured_expiry != default_expiry ||
410  reg->portno != STANDARD_SIP_PORT ||
411  (reg->regdomainport) ||
412  reg->callid_valid != FALSE ||
413  reg->ocseq != INITIAL_CSEQ) {
414 
415  ast_test_status_update(test, "Test 4: add callback extension failed\n");
416  res = AST_TEST_FAIL;
417  }
419  ast_free(reg);
420 
421  /* ---Test reg 5, add transport --- */
422  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
423  goto alloc_fail;
424  } else if (
425  sip_parse_register_line(reg, default_expiry, reg5, 1) ||
426  strcmp(reg->callback, "extension") ||
427  strcmp(reg->username, "name") ||
428  strcmp(reg->regdomain, "namedomain") ||
429  strcmp(reg->hostname, "domain") ||
430  strcmp(reg->authuser, "authuser") ||
431  strcmp(reg->secret, "pass") ||
432  strcmp(reg->peername, "") ||
433  reg->transport != SIP_TRANSPORT_TCP ||
434  reg->timeout != -1 ||
435  reg->expire != -1 ||
436  reg->refresh != default_expiry ||
437  reg->expiry != default_expiry ||
438  reg->configured_expiry != default_expiry ||
439  reg->portno != STANDARD_SIP_PORT ||
440  (reg->regdomainport) ||
441  reg->callid_valid != FALSE ||
442  reg->ocseq != INITIAL_CSEQ) {
443 
444  ast_test_status_update(test, "Test 5: add transport failed\n");
445  res = AST_TEST_FAIL;
446  }
448  ast_free(reg);
449 
450  /* ---Test reg 6, change to tls transport, add expiry --- */
451  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
452  goto alloc_fail;
453  } else if (
454  sip_parse_register_line(reg, default_expiry, reg6, 1) ||
455  strcmp(reg->callback, "extension") ||
456  strcmp(reg->username, "name") ||
457  strcmp(reg->regdomain, "namedomain") ||
458  strcmp(reg->hostname, "domain") ||
459  strcmp(reg->authuser, "authuser") ||
460  strcmp(reg->secret, "pass") ||
461  strcmp(reg->peername, "") ||
462  reg->transport != SIP_TRANSPORT_TLS ||
463  reg->timeout != -1 ||
464  reg->expire != -1 ||
465  reg->refresh != 111 ||
466  reg->expiry != 111 ||
467  reg->configured_expiry != 111 ||
468  reg->portno != STANDARD_TLS_PORT ||
469  (reg->regdomainport) ||
470  reg->callid_valid != FALSE ||
471  reg->ocseq != INITIAL_CSEQ) {
472 
473  ast_test_status_update(test, "Test 6: change to tls transport and add expiry failed\n");
474  res = AST_TEST_FAIL;
475  }
477  ast_free(reg);
478 
479  /* ---Test reg 7, change transport to tcp, add custom port, and add peer --- */
480  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
481  goto alloc_fail;
482  } else if (
483  sip_parse_register_line(reg, default_expiry, reg7, 1) ||
484  strcmp(reg->callback, "extension") ||
485  strcmp(reg->username, "name") ||
486  strcmp(reg->regdomain, "namedomain") ||
487  strcmp(reg->hostname, "domain") ||
488  strcmp(reg->authuser, "authuser") ||
489  strcmp(reg->secret, "pass") ||
490  strcmp(reg->peername, "peer") ||
491  reg->transport != SIP_TRANSPORT_TCP ||
492  reg->timeout != -1 ||
493  reg->expire != -1 ||
494  reg->refresh != 111 ||
495  reg->expiry != 111 ||
496  reg->configured_expiry != 111 ||
497  reg->portno != 1234 ||
498  (reg->regdomainport) ||
499  reg->callid_valid != FALSE ||
500  reg->ocseq != INITIAL_CSEQ) {
501 
502  ast_test_status_update(test, "Test 7, change transport to tcp, add custom port, and add peer failed.\n");
503  res = AST_TEST_FAIL;
504  }
506  ast_free(reg);
507 
508  /* ---Test reg 8, remove transport --- */
509  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
510  goto alloc_fail;
511  } else if (
512  sip_parse_register_line(reg, default_expiry, reg8, 1) ||
513  strcmp(reg->callback, "extension") ||
514  strcmp(reg->username, "name") ||
515  strcmp(reg->regdomain, "namedomain") ||
516  strcmp(reg->hostname, "domain") ||
517  strcmp(reg->authuser, "authuser") ||
518  strcmp(reg->secret, "pass") ||
519  strcmp(reg->peername, "peer") ||
520  reg->transport != SIP_TRANSPORT_UDP ||
521  reg->timeout != -1 ||
522  reg->expire != -1 ||
523  reg->refresh != 111 ||
524  reg->expiry != 111 ||
525  reg->configured_expiry != 111 ||
526  reg->portno != 1234 ||
527  (reg->regdomainport) ||
528  reg->callid_valid != FALSE ||
529  reg->ocseq != INITIAL_CSEQ) {
530 
531  ast_test_status_update(test, "Test 8, remove transport failed.\n");
532  res = AST_TEST_FAIL;
533  }
535  ast_free(reg);
536 
537  /* ---Test reg 9, missing domain, expected to fail --- */
538  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
539  goto alloc_fail;
540  } else if (!sip_parse_register_line(reg, default_expiry, reg9, 1)) {
542  "Test 9, missing domain, expected to fail but did not.\n");
543  res = AST_TEST_FAIL;
544  }
546  ast_free(reg);
547 
548  /* ---Test reg 10, missing user, expected to fail --- */
549  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
550  goto alloc_fail;
551  } else if (!sip_parse_register_line(reg, default_expiry, reg10, 1)) {
553  "Test 10, missing user expected to fail but did not\n");
554  res = AST_TEST_FAIL;
555  }
557  ast_free(reg);
558 
559  /* ---Test reg 11, no registry object, expected to fail--- */
560  if (!sip_parse_register_line(NULL, default_expiry, reg1, 1)) {
562  "Test 11, no registry object, expected to fail but did not.\n");
563  res = AST_TEST_FAIL;
564  }
565 
566  /* ---Test reg 12, no registry line, expected to fail --- */
567  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
568  goto alloc_fail;
569  } else if (!sip_parse_register_line(reg, default_expiry, NULL, 1)) {
570 
572  "Test 12, NULL register line expected to fail but did not.\n");
573  res = AST_TEST_FAIL;
574  }
576  ast_free(reg);
577 
578  /* ---Test reg13, add domain port --- */
579  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
580  goto alloc_fail;
581  } else if (
582  sip_parse_register_line(reg, default_expiry, reg12, 1) ||
583  strcmp(reg->callback, "s") ||
584  strcmp(reg->username, "name") ||
585  strcmp(reg->regdomain, "namedomain") ||
586  strcmp(reg->hostname, "domain") ||
587  strcmp(reg->authuser, "authuser") ||
588  strcmp(reg->secret, "pass") ||
589  strcmp(reg->peername, "") ||
590  reg->transport != SIP_TRANSPORT_UDP ||
591  reg->timeout != -1 ||
592  reg->expire != -1 ||
593  reg->refresh != default_expiry ||
594  reg->expiry != default_expiry ||
595  reg->configured_expiry != default_expiry ||
596  reg->portno != STANDARD_SIP_PORT ||
597  reg->regdomainport != 4321 ||
598  reg->callid_valid != FALSE ||
599  reg->ocseq != INITIAL_CSEQ) {
600 
601  ast_test_status_update(test, "Test 13, add domain port failed.\n");
602  res = AST_TEST_FAIL;
603  }
605  ast_free(reg);
606 
607  /* ---Test reg14, domain port without secret --- */
608  if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
609  goto alloc_fail;
610  } else if (
611  sip_parse_register_line(reg, default_expiry, reg13, 1) ||
612  strcmp(reg->callback, "s") ||
613  strcmp(reg->username, "name") ||
614  strcmp(reg->regdomain, "namedomain") ||
615  strcmp(reg->hostname, "domain") ||
616  strcmp(reg->authuser, "") ||
617  strcmp(reg->secret, "") ||
618  strcmp(reg->peername, "") ||
619  reg->transport != SIP_TRANSPORT_UDP ||
620  reg->timeout != -1 ||
621  reg->expire != -1 ||
622  reg->refresh != default_expiry ||
623  reg->expiry != default_expiry ||
624  reg->configured_expiry != default_expiry ||
625  reg->portno != STANDARD_SIP_PORT ||
626  reg->regdomainport != 4321 ||
627  reg->callid_valid != FALSE ||
628  reg->ocseq != INITIAL_CSEQ) {
629 
630  ast_test_status_update(test, "Test 14, domain port without secret failed.\n");
631  res = AST_TEST_FAIL;
632  }
634  ast_free(reg);
635 
636 
637  return res;
638 
639 alloc_fail:
640  ast_test_status_update(test, "Out of memory. \n");
641  return res;
642 }
643 
644 int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport)
645 {
646  char *port;
647 
648  if (ast_strlen_zero(line)) {
649  *hostname = NULL;
650  return -1;
651  }
652  if ((*hostname = strstr(line, "://"))) {
653  *hostname += 3;
654 
655  if (!strncasecmp(line, "tcp", 3)) {
656  *transport = SIP_TRANSPORT_TCP;
657  } else if (!strncasecmp(line, "tls", 3)) {
658  *transport = SIP_TRANSPORT_TLS;
659  } else if (!strncasecmp(line, "udp", 3)) {
660  *transport = SIP_TRANSPORT_UDP;
661  } else if (lineno) {
662  ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", line, lineno);
663  } else {
664  ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type in sip config. defaulting to udp.\n", line);
665  }
666  } else {
667  *hostname = line;
668  *transport = SIP_TRANSPORT_UDP;
669  }
670 
671  if ((line = strrchr(*hostname, '@')))
672  line++;
673  else
674  line = *hostname;
675 
676  if (ast_sockaddr_split_hostport(line, hostname, &port, 0) == 0) {
677  if (lineno) {
678  ast_log(LOG_WARNING, "Cannot parse host '%s' on line %d of sip.conf.\n",
679  line, lineno);
680  } else {
681  ast_log(LOG_WARNING, "Cannot parse host '%s' in sip config.\n", line);
682  }
683  return -1;
684  }
685 
686  if (port) {
687  if (!sscanf(port, "%5d", portnum)) {
688  if (lineno) {
689  ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", port, lineno);
690  } else {
691  ast_log(LOG_NOTICE, "'%s' is not a valid port number in sip config. using default.\n", port);
692  }
693  port = NULL;
694  }
695  }
696 
697  if (!port) {
698  if (*transport & SIP_TRANSPORT_TLS) {
699  *portnum = STANDARD_TLS_PORT;
700  } else {
701  *portnum = STANDARD_SIP_PORT;
702  }
703  }
704 
705  return 0;
706 }
707 
708 AST_TEST_DEFINE(sip_parse_host_line_test)
709 {
710  int res = AST_TEST_PASS;
711  char *host;
712  int port;
713  enum sip_transport transport;
714  char host1[] = "www.blah.com";
715  char host2[] = "tcp://www.blah.com";
716  char host3[] = "tls://10.10.10.10";
717  char host4[] = "tls://10.10.10.10:1234";
718  char host5[] = "10.10.10.10:1234";
719 
720  switch (cmd) {
721  case TEST_INIT:
722  info->name = "sip_parse_host_line_test";
723  info->category = "/channels/chan_sip/";
724  info->summary = "tests sip.conf host line parsing";
725  info->description =
726  "Tests parsing of various host line configurations. "
727  "Verifies output matches expected behavior.";
728  return AST_TEST_NOT_RUN;
729  case TEST_EXECUTE:
730  break;
731  }
732 
733  /* test 1, simple host */
734  sip_parse_host(host1, 1, &host, &port, &transport);
735  if (port != STANDARD_SIP_PORT ||
736  ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
737  transport != SIP_TRANSPORT_UDP) {
738  ast_test_status_update(test, "Test 1: simple host failed.\n");
739  res = AST_TEST_FAIL;
740  }
741 
742  /* test 2, add tcp transport */
743  sip_parse_host(host2, 1, &host, &port, &transport);
744  if (port != STANDARD_SIP_PORT ||
745  ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
746  transport != SIP_TRANSPORT_TCP) {
747  ast_test_status_update(test, "Test 2: tcp host failed.\n");
748  res = AST_TEST_FAIL;
749  }
750 
751  /* test 3, add tls transport */
752  sip_parse_host(host3, 1, &host, &port, &transport);
753  if (port != STANDARD_TLS_PORT ||
754  ast_strlen_zero(host) || strcmp(host, "10.10.10.10") ||
755  transport != SIP_TRANSPORT_TLS) {
756  ast_test_status_update(test, "Test 3: tls host failed. \n");
757  res = AST_TEST_FAIL;
758  }
759 
760  /* test 4, add custom port with tls */
761  sip_parse_host(host4, 1, &host, &port, &transport);
762  if (port != 1234 || ast_strlen_zero(host) ||
763  strcmp(host, "10.10.10.10") ||
764  transport != SIP_TRANSPORT_TLS) {
765  ast_test_status_update(test, "Test 4: tls host with custom port failed.\n");
766  res = AST_TEST_FAIL;
767  }
768 
769  /* test 5, simple host with custom port */
770  sip_parse_host(host5, 1, &host, &port, &transport);
771  if (port != 1234 || ast_strlen_zero(host) ||
772  strcmp(host, "10.10.10.10") ||
773  transport != SIP_TRANSPORT_UDP) {
774  ast_test_status_update(test, "Test 5: simple host with custom port failed.\n");
775  res = AST_TEST_FAIL;
776  }
777 
778  /* test 6, expected failure with NULL input */
779  if (!sip_parse_host(NULL, 1, &host, &port, &transport)) {
780  ast_test_status_update(test, "Test 6: expected error on NULL input did not occur.\n");
781  res = AST_TEST_FAIL;
782  }
783 
784  return res;
785 
786 }
787 
788 /*! \brief SIP test registration */
790 {
791  AST_TEST_REGISTER(sip_parse_register_line_test);
792  AST_TEST_REGISTER(sip_parse_host_line_test);
793 }
794 
795 /*! \brief SIP test registration */
797 {
798  AST_TEST_UNREGISTER(sip_parse_register_line_test);
799  AST_TEST_UNREGISTER(sip_parse_host_line_test);
800 }
801 
Asterisk main include file. File version handling, generic pbx functions.
#define FALSE
Definition: app_minivm.c:506
int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno)
Parse register=&gt; line in sip.conf.
Definition: config_parser.c:39
#define LOG_WARNING
Definition: logger.h:144
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:275
void sip_config_parser_register_tests(void)
SIP test registration.
int value
Definition: syslog.c:39
void sip_config_parser_unregister_tests(void)
SIP test registration.
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: utils.c:1431
int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
Splits a string into its host and port components.
Definition: netsock2.c:132
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static int default_expiry
Definition: chan_sip.c:548
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
#define ast_free(a)
Definition: astmm.h:97
structure to hold users read from users.conf
static char secret[50]
Definition: chan_h323.c:148
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
unsigned int port_str2int(const char *pt, unsigned int standard)
converts ascii port to int representation. If no pt buffer is provided or the pt has errors when bein...
Definition: chan_sip.c:3291
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
#define AST_NONSTANDARD_RAW_ARGS(args, parse, sep)
Definition: app.h:621
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
static char hostname[MAXHOSTNAMELEN]
Definition: logger.c:91
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344