Wed Jan 8 2020 09:49:48

Asterisk developer's documentation


iax2-parser.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Implementation of Inter-Asterisk eXchange Protocol, v 2
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
33 
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 
38 #include "asterisk/frame.h"
39 #include "asterisk/utils.h"
40 #include "asterisk/unaligned.h"
41 #include "asterisk/config.h"
42 #include "asterisk/lock.h"
43 #include "asterisk/threadstorage.h"
44 
45 #include "iax2.h"
46 #include "iax2-parser.h"
47 #include "iax2-provision.h"
48 
49 static int frames = 0;
50 static int iframes = 0;
51 static int oframes = 0;
52 
53 #if !defined(LOW_MEMORY)
54 static void frame_cache_cleanup(void *data);
55 
56 /*! \brief A per-thread cache of iax_frame structures */
58 
59 /*! \brief This is just so iax_frames, a list head struct for holding a list of
60  * iax_frame structures, is defined. */
62 
63 struct iax_frames {
65  size_t size;
66 };
67 
68 #define FRAME_CACHE_MAX_SIZE 20
69 #endif
70 
71 static void internaloutput(const char *str)
72 {
73  fputs(str, stdout);
74 }
75 
76 static void internalerror(const char *str)
77 {
78  fprintf(stderr, "WARNING: %s", str);
79 }
80 
81 static void (*outputf)(const char *str) = internaloutput;
82 static void (*errorf)(const char *str) = internalerror;
83 
84 static void dump_addr(char *output, int maxlen, void *value, int len)
85 {
86  struct sockaddr_in sin;
87  if (len == (int)sizeof(sin)) {
88  memcpy(&sin, value, len);
89  snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
90  } else {
91  ast_copy_string(output, "Invalid Address", maxlen);
92  }
93 }
94 
95 static void dump_string_hex(char *output, int maxlen, void *value, int len)
96 {
97  int i = 0;
98 
99  while (len-- && (i + 1) * 4 < maxlen) {
100  sprintf(output + (4 * i), "\\x%2.2x", (unsigned)*((unsigned char *)value + i));
101  i++;
102  }
103 }
104 
105 static void dump_string(char *output, int maxlen, void *value, int len)
106 {
107  maxlen--;
108  if (maxlen > len)
109  maxlen = len;
110  strncpy(output, value, maxlen);
111  output[maxlen] = '\0';
112 }
113 
114 static void dump_prefs(char *output, int maxlen, void *value, int len)
115 {
116  struct ast_codec_pref pref;
117  int total_len = 0;
118 
119  maxlen--;
120  total_len = maxlen;
121 
122  if (maxlen > len)
123  maxlen = len;
124 
125  strncpy(output, value, maxlen);
126  output[maxlen] = '\0';
127 
128  ast_codec_pref_convert(&pref, output, total_len, 0);
129  memset(output,0,total_len);
130  ast_codec_pref_string(&pref, output, total_len);
131 }
132 
133 static void dump_int(char *output, int maxlen, void *value, int len)
134 {
135  if (len == (int)sizeof(unsigned int))
136  snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
137  else
138  ast_copy_string(output, "Invalid INT", maxlen);
139 }
140 
141 static void dump_short(char *output, int maxlen, void *value, int len)
142 {
143  if (len == (int)sizeof(unsigned short))
144  snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
145  else
146  ast_copy_string(output, "Invalid SHORT", maxlen);
147 }
148 
149 static void dump_byte(char *output, int maxlen, void *value, int len)
150 {
151  if (len == (int)sizeof(unsigned char))
152  snprintf(output, maxlen, "%d", *((unsigned char *)value));
153  else
154  ast_copy_string(output, "Invalid BYTE", maxlen);
155 }
156 
157 static void dump_datetime(char *output, int maxlen, void *value, int len)
158 {
159  struct ast_tm tm;
160  unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
161  if (len == (int)sizeof(unsigned int)) {
162  tm.tm_sec = (val & 0x1f) << 1;
163  tm.tm_min = (val >> 5) & 0x3f;
164  tm.tm_hour = (val >> 11) & 0x1f;
165  tm.tm_mday = (val >> 16) & 0x1f;
166  tm.tm_mon = ((val >> 21) & 0x0f) - 1;
167  tm.tm_year = ((val >> 25) & 0x7f) + 100;
168  ast_strftime(output, maxlen, "%Y-%m-%d %T", &tm);
169  } else
170  ast_copy_string(output, "Invalid DATETIME format!", maxlen);
171 }
172 
173 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
174 {
175  struct sockaddr_in sin;
176  if (len == (int)sizeof(unsigned int)) {
177  memcpy(&sin.sin_addr, value, len);
178  snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
179  } else
180  ast_copy_string(output, "Invalid IPADDR", maxlen);
181 }
182 
183 
184 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
185 {
186  char buf[256] = "";
187  if (len == (int)sizeof(unsigned int))
188  snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
189  iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
190  else
191  ast_copy_string(output, "Invalid INT", maxlen);
192 }
193 
194 static void dump_samprate(char *output, int maxlen, void *value, int len)
195 {
196  char tmp[256]="";
197  int sr;
198  if (len == (int)sizeof(unsigned short)) {
199  sr = ntohs(*((unsigned short *)value));
200  if (sr & IAX_RATE_8KHZ)
201  strcat(tmp, ",8khz");
202  if (sr & IAX_RATE_11KHZ)
203  strcat(tmp, ",11.025khz");
204  if (sr & IAX_RATE_16KHZ)
205  strcat(tmp, ",16khz");
206  if (sr & IAX_RATE_22KHZ)
207  strcat(tmp, ",22.05khz");
208  if (sr & IAX_RATE_44KHZ)
209  strcat(tmp, ",44.1khz");
210  if (sr & IAX_RATE_48KHZ)
211  strcat(tmp, ",48khz");
212  if (strlen(tmp))
213  ast_copy_string(output, &tmp[1], maxlen);
214  else
215  ast_copy_string(output, "None Specified!\n", maxlen);
216  } else
217  ast_copy_string(output, "Invalid SHORT", maxlen);
218 
219 }
220 
221 static void dump_versioned_codec(char *output, int maxlen, void *value, int len)
222 {
223  char *version = (char *) value;
224  if (version[0] == 0) {
225  if (len == (int) (sizeof(format_t) + sizeof(char))) {
226  format_t codec = ntohll(get_unaligned_uint64(value + 1));
227  ast_copy_string(output, ast_getformatname(codec), maxlen);
228  } else {
229  ast_copy_string(output, "Invalid length!", maxlen);
230  }
231  } else {
232  ast_copy_string(output, "Unknown version!", maxlen);
233  }
234 }
235 
236 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
237 static void dump_prov(char *output, int maxlen, void *value, int len)
238 {
239  dump_prov_ies(output, maxlen, value, len);
240 }
241 
242 struct iax2_ie {
243  int ie;
244  char *name;
245  void (*dump)(char *output, int maxlen, void *value, int len);
246 };
247 static struct iax2_ie infoelts[] = {
248  { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
249  { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
250  { IAX_IE_CALLING_ANI, "ANI", dump_string },
251  { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
252  { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
253  { IAX_IE_USERNAME, "USERNAME", dump_string },
254  { IAX_IE_PASSWORD, "PASSWORD", dump_string },
255  { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
256  { IAX_IE_CAPABILITY2, "CAPABILITY2", dump_versioned_codec },
257  { IAX_IE_FORMAT, "FORMAT", dump_int },
258  { IAX_IE_FORMAT2, "FORMAT2", dump_versioned_codec },
259  { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
260  { IAX_IE_VERSION, "VERSION", dump_short },
261  { IAX_IE_ADSICPE, "ADSICPE", dump_short },
262  { IAX_IE_DNID, "DNID", dump_string },
263  { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
264  { IAX_IE_CHALLENGE, "CHALLENGE", dump_string_hex },
265  { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
266  { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
267  { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
268  { IAX_IE_REFRESH, "REFRESH", dump_short },
269  { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
270  { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
271  { IAX_IE_CAUSE, "CAUSE", dump_string },
272  { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
273  { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
274  { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
275  { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
276  { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
277  { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
278  { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
279  { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
280  { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
281  { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
282  { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
283  { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
284  { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
285  { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
286  { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
287  { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
288  { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
289  { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
290  { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
291  { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
292  { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
293  { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
294  { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
295  { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
296  { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
297  { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
298  { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
299  { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
300  { IAX_IE_VARIABLE, "VARIABLE", dump_string },
301  { IAX_IE_OSPTOKEN, "OSPTOKEN" },
302  { IAX_IE_CALLTOKEN, "CALLTOKEN" },
303 };
304 
305 static const struct iax2_ie prov_ies[] = {
306  { PROV_IE_USEDHCP, "USEDHCP" },
307  { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
308  { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
309  { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
310  { PROV_IE_PORTNO, "BINDPORT", dump_short },
311  { PROV_IE_USER, "USERNAME", dump_string },
312  { PROV_IE_PASS, "PASSWORD", dump_string },
313  { PROV_IE_LANG, "LANGUAGE", dump_string },
314  { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
315  { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
316  { PROV_IE_FORMAT, "FORMAT", dump_int },
317  { PROV_IE_AESKEY, "AESKEY" },
318  { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
319  { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
320  { PROV_IE_NEWAESKEY, "NEWAESKEY" },
321  { PROV_IE_PROVVER, "PROV VERSION", dump_int },
322  { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
323 };
324 
325 const char *iax_ie2str(int ie)
326 {
327  int x;
328  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
329  if (infoelts[x].ie == ie)
330  return infoelts[x].name;
331  }
332  return "Unknown IE";
333 }
334 
335 
336 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
337 {
338  int ielen;
339  int ie;
340  int x;
341  int found;
342  char interp[80];
343  char tmp[256];
344  if (len < 2)
345  return;
346  strcpy(output, "\n");
347  maxlen -= strlen(output); output += strlen(output);
348  while(len > 2) {
349  ie = iedata[0];
350  ielen = iedata[1];
351  if (ielen + 2> len) {
352  snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
353  ast_copy_string(output, tmp, maxlen);
354  maxlen -= strlen(output);
355  output += strlen(output);
356  return;
357  }
358  found = 0;
359  for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
360  if (prov_ies[x].ie == ie) {
361  if (prov_ies[x].dump) {
362  prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
363  snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
364  ast_copy_string(output, tmp, maxlen);
365  maxlen -= strlen(output); output += strlen(output);
366  } else {
367  if (ielen)
368  snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
369  else
370  strcpy(interp, "Present");
371  snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
372  ast_copy_string(output, tmp, maxlen);
373  maxlen -= strlen(output); output += strlen(output);
374  }
375  found++;
376  }
377  }
378  if (!found) {
379  snprintf(tmp, (int)sizeof(tmp), " Unknown Prov IE %03d : Present\n", ie);
380  ast_copy_string(output, tmp, maxlen);
381  maxlen -= strlen(output); output += strlen(output);
382  }
383  iedata += (2 + ielen);
384  len -= (2 + ielen);
385  }
386 }
387 
388 static void dump_ies(unsigned char *iedata, int len)
389 {
390  int ielen;
391  int ie;
392  int x;
393  int found;
394  char interp[1024];
395  char tmp[1024];
396 
397  if (len < 2)
398  return;
399  while(len > 2) {
400  ie = iedata[0];
401  ielen = iedata[1];
402  if (ielen + 2> len) {
403  snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
404  outputf(tmp);
405  return;
406  }
407  found = 0;
408  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
409  if (infoelts[x].ie == ie) {
410  if (infoelts[x].dump) {
411  infoelts[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
412  snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", infoelts[x].name, interp);
413  outputf(tmp);
414  } else {
415  if (ielen)
416  snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
417  else
418  strcpy(interp, "Present");
419  snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", infoelts[x].name, interp);
420  outputf(tmp);
421  }
422  found++;
423  }
424  }
425  if (!found) {
426  snprintf(tmp, (int)sizeof(tmp), " Unknown IE %03d : Present\n", ie);
427  outputf(tmp);
428  }
429  iedata += (2 + ielen);
430  len -= (2 + ielen);
431  }
432  outputf("\n");
433 }
434 
435 void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len)
436 {
437  const char *cmd = "Unknown";
438 
439  /* if an error occurs here during compile, that means a new iax frame subclass
440  * has been added to the iax_frame_subclass enum. Add the new subclass to the
441  * switch case and make sure to update it with a new string representation. */
442  switch (subclass) {
443  case IAX_COMMAND_NEW:
444  cmd = "NEW ";
445  break;
446  case IAX_COMMAND_PING:
447  cmd = "PING ";
448  break;
449  case IAX_COMMAND_PONG:
450  cmd = "PONG ";
451  break;
452  case IAX_COMMAND_ACK:
453  cmd = "ACK ";
454  break;
455  case IAX_COMMAND_HANGUP:
456  cmd = "HANGUP ";
457  break;
458  case IAX_COMMAND_REJECT:
459  cmd = "REJECT ";
460  break;
461  case IAX_COMMAND_ACCEPT:
462  cmd = "ACCEPT ";
463  break;
464  case IAX_COMMAND_AUTHREQ:
465  cmd = "AUTHREQ";
466  break;
467  case IAX_COMMAND_AUTHREP:
468  cmd = "AUTHREP";
469  break;
470  case IAX_COMMAND_INVAL:
471  cmd = "INVAL ";
472  break;
473  case IAX_COMMAND_LAGRQ:
474  cmd = "LAGRQ ";
475  break;
476  case IAX_COMMAND_LAGRP:
477  cmd = "LAGRP ";
478  break;
479  case IAX_COMMAND_REGREQ:
480  cmd = "REGREQ ";
481  break;
482  case IAX_COMMAND_REGAUTH:
483  cmd = "REGAUTH";
484  break;
485  case IAX_COMMAND_REGACK:
486  cmd = "REGACK ";
487  break;
488  case IAX_COMMAND_REGREJ:
489  cmd = "REGREJ ";
490  break;
491  case IAX_COMMAND_REGREL:
492  cmd = "REGREL ";
493  break;
494  case IAX_COMMAND_VNAK:
495  cmd = "VNAK ";
496  break;
497  case IAX_COMMAND_DPREQ:
498  cmd = "DPREQ ";
499  break;
500  case IAX_COMMAND_DPREP:
501  cmd = "DPREP ";
502  break;
503  case IAX_COMMAND_DIAL:
504  cmd = "DIAL ";
505  break;
506  case IAX_COMMAND_TXREQ:
507  cmd = "TXREQ ";
508  break;
509  case IAX_COMMAND_TXCNT:
510  cmd = "TXCNT ";
511  break;
512  case IAX_COMMAND_TXACC:
513  cmd = "TXACC ";
514  break;
515  case IAX_COMMAND_TXREADY:
516  cmd = "TXREADY";
517  break;
518  case IAX_COMMAND_TXREL:
519  cmd = "TXREL ";
520  break;
521  case IAX_COMMAND_TXREJ:
522  cmd = "TXREJ ";
523  break;
524  case IAX_COMMAND_QUELCH:
525  cmd = "QUELCH ";
526  break;
528  cmd = "UNQULCH";
529  break;
530  case IAX_COMMAND_POKE:
531  cmd = "POKE ";
532  break;
533  case IAX_COMMAND_PAGE:
534  cmd = "PAGE ";
535  break;
536  case IAX_COMMAND_MWI:
537  cmd = "MWI ";
538  break;
540  cmd = "UNSPRTD";
541  break;
543  cmd = "TRANSFR";
544  break;
546  cmd = "PROVISN";
547  break;
548  case IAX_COMMAND_FWDOWNL:
549  cmd = "FWDWNLD";
550  break;
551  case IAX_COMMAND_FWDATA:
552  cmd = "FWDATA ";
553  break;
554  case IAX_COMMAND_TXMEDIA:
555  cmd = "TXMEDIA";
556  break;
557  case IAX_COMMAND_RTKEY:
558  cmd = "RTKEY ";
559  break;
561  cmd = "CTOKEN ";
562  break;
563  }
564  ast_copy_string(str, cmd, len);
565 }
566 
567 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
568 {
569  const char *framelist[] = {
570  "(0?)",
571  "DTMF_E ",
572  "VOICE ",
573  "VIDEO ",
574  "CONTROL",
575  "NULL ",
576  "IAX ",
577  "TEXT ",
578  "IMAGE ",
579  "HTML ",
580  "CNG ",
581  "MODEM ",
582  "DTMF_B ",
583  };
584  const char *cmds[] = {
585  "(0?)",
586  "HANGUP ",
587  "RING ",
588  "RINGING",
589  "ANSWER ",
590  "BUSY ",
591  "TKOFFHK",
592  "OFFHOOK",
593  "CONGSTN",
594  "FLASH ",
595  "WINK ",
596  "OPTION ",
597  "RDKEY ",
598  "RDUNKEY",
599  "PROGRES",
600  "PROCDNG",
601  "HOLD ",
602  "UNHOLD ",
603  "VIDUPDT",
604  "T38 ",
605  "SRCUPDT",
606  "TXFER ",
607  "CNLINE ",
608  "REDIR ",
609  "T38PARM",
610  "CC ERR!",/* This must never go across an IAX link. */
611  "SRCCHG ",
612  "READACT",
613  "AOC ",
614  "ENDOFQ ",
615  "INCOMPL",
616  "UPDRTPP",
617  };
618  struct ast_iax2_full_hdr *fh;
619  char retries[20];
620  char class2[20];
621  char subclass2[20];
622  const char *class;
623  const char *subclass;
624  char *dir;
625  char tmp[512];
626 
627  switch(rx) {
628  case 0:
629  dir = "Tx";
630  break;
631  case 2:
632  dir = "TE";
633  break;
634  case 3:
635  dir = "RD";
636  break;
637  default:
638  dir = "Rx";
639  break;
640  }
641  if (f) {
642  fh = f->data;
643  snprintf(retries, sizeof(retries), "%03d", f->retries);
644  } else {
645  fh = fhi;
646  if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
647  strcpy(retries, "Yes");
648  else
649  strcpy(retries, " No");
650  }
651  if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
652  /* Don't mess with mini-frames */
653  return;
654  }
655  if (fh->type >= ARRAY_LEN(framelist)) {
656  snprintf(class2, sizeof(class2), "(%d?)", fh->type);
657  class = class2;
658  } else {
659  class = framelist[(int)fh->type];
660  }
661  if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
662  sprintf(subclass2, "%c", fh->csub);
663  subclass = subclass2;
664  } else if (fh->type == AST_FRAME_IAX) {
665  iax_frame_subclass2str((int)fh->csub, subclass2, sizeof(subclass2));
666  subclass = subclass2;
667  } else if (fh->type == AST_FRAME_CONTROL) {
668  if (fh->csub >= ARRAY_LEN(cmds)) {
669  snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
670  subclass = subclass2;
671  } else {
672  subclass = cmds[(int)fh->csub];
673  }
674  } else {
675  snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
676  subclass = subclass2;
677  }
678  snprintf(tmp, sizeof(tmp),
679  "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
680  dir,
681  retries, fh->oseqno, fh->iseqno, class, subclass);
682  outputf(tmp);
683  snprintf(tmp, sizeof(tmp),
684  " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
685  (unsigned long)ntohl(fh->ts),
686  ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
687  ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
688  outputf(tmp);
689  if (fh->type == AST_FRAME_IAX)
690  dump_ies(fh->iedata, datalen);
691 }
692 
693 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
694 {
695  char tmp[256];
696  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
697  snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
698  errorf(tmp);
699  return -1;
700  }
701  ied->buf[ied->pos++] = ie;
702  ied->buf[ied->pos++] = datalen;
703  memcpy(ied->buf + ied->pos, data, datalen);
704  ied->pos += datalen;
705  return 0;
706 }
707 
708 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
709 {
710  return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
711 }
712 
713 int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value)
714 {
715  struct _local {
716  unsigned char version;
717  uint64_t value;
718  } __attribute__((packed)) newval = { version, };
719  put_unaligned_uint64(&newval.value, htonll(value));
720  return iax_ie_append_raw(ied, ie, &newval, (int) sizeof(newval));
721 }
722 
723 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
724 {
725  unsigned int newval;
726  newval = htonl(value);
727  return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
728 }
729 
730 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
731 {
732  unsigned short newval;
733  newval = htons(value);
734  return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
735 }
736 
737 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
738 {
739  return iax_ie_append_raw(ied, ie, str, strlen(str));
740 }
741 
742 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
743 {
744  return iax_ie_append_raw(ied, ie, &dat, 1);
745 }
746 
747 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
748 {
749  return iax_ie_append_raw(ied, ie, NULL, 0);
750 }
751 
752 void iax_set_output(void (*func)(const char *))
753 {
754  outputf = func;
755 }
756 
757 void iax_set_error(void (*func)(const char *))
758 {
759  errorf = func;
760 }
761 
762 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
763 {
764  /* Parse data into information elements */
765  int len;
766  int ie;
767  char tmp[256], *tmp2;
768  struct ast_variable *var, *var2, *prev;
769  unsigned int count;
770  memset(ies, 0, (int)sizeof(struct iax_ies));
771  ies->msgcount = -1;
772  ies->firmwarever = -1;
773  ies->calling_ton = -1;
774  ies->calling_tns = -1;
775  ies->calling_pres = -1;
776  ies->samprate = IAX_RATE_8KHZ;
777  while(datalen >= 2) {
778  ie = data[0];
779  len = data[1];
780  if (len > datalen - 2) {
781  errorf("Information element length exceeds message size\n");
782  return -1;
783  }
784  switch(ie) {
786  ies->called_number = (char *)data + 2;
787  break;
789  ies->calling_number = (char *)data + 2;
790  break;
791  case IAX_IE_CALLING_ANI:
792  ies->calling_ani = (char *)data + 2;
793  break;
794  case IAX_IE_CALLING_NAME:
795  ies->calling_name = (char *)data + 2;
796  break;
798  ies->called_context = (char *)data + 2;
799  break;
800  case IAX_IE_USERNAME:
801  ies->username = (char *)data + 2;
802  break;
803  case IAX_IE_PASSWORD:
804  ies->password = (char *)data + 2;
805  break;
806  case IAX_IE_CODEC_PREFS:
807  ies->codec_prefs = (char *)data + 2;
808  break;
809  case IAX_IE_CAPABILITY:
810  if (len != (int)sizeof(unsigned int)) {
811  snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
812  errorf(tmp);
813  } else if (ies->capability == 0) { /* Don't overwrite capability2, if specified */
814  ies->capability = ntohl(get_unaligned_uint32(data + 2));
815  }
816  break;
817  case IAX_IE_CAPABILITY2:
818  {
819  int version = data[2];
820  if (version == 0) {
821  if (len != (int)sizeof(char) + sizeof(format_t)) {
822  snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int) (sizeof(format_t) + sizeof(char)), len);
823  errorf(tmp);
824  } else {
825  ies->capability = (format_t) ntohll(get_unaligned_uint64(data + 3));
826  }
827  } /* else unknown version */
828  }
829  break;
830  case IAX_IE_FORMAT:
831  if (len != (int)sizeof(unsigned int)) {
832  snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
833  errorf(tmp);
834  } else if (ies->format == 0) { /* Don't overwrite format2, if specified */
835  ies->format = ntohl(get_unaligned_uint32(data + 2));
836  }
837  break;
838  case IAX_IE_FORMAT2:
839  {
840  int version = data[2];
841  if (version == 0) {
842  if (len != (int)sizeof(char) + sizeof(format_t)) {
843  snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int) (sizeof(format_t) + sizeof(char)), len);
844  errorf(tmp);
845  } else {
846  ies->format = (format_t) ntohll(get_unaligned_uint64(data + 3));
847  }
848  } /* else unknown version */
849  }
850  break;
851  case IAX_IE_LANGUAGE:
852  ies->language = (char *)data + 2;
853  break;
854  case IAX_IE_VERSION:
855  if (len != (int)sizeof(unsigned short)) {
856  snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
857  errorf(tmp);
858  } else
859  ies->version = ntohs(get_unaligned_uint16(data + 2));
860  break;
861  case IAX_IE_ADSICPE:
862  if (len != (int)sizeof(unsigned short)) {
863  snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
864  errorf(tmp);
865  } else
866  ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
867  break;
868  case IAX_IE_SAMPLINGRATE:
869  if (len != (int)sizeof(unsigned short)) {
870  snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
871  errorf(tmp);
872  } else
873  ies->samprate = ntohs(get_unaligned_uint16(data + 2));
874  break;
875  case IAX_IE_DNID:
876  ies->dnid = (char *)data + 2;
877  break;
878  case IAX_IE_RDNIS:
879  ies->rdnis = (char *)data + 2;
880  break;
881  case IAX_IE_AUTHMETHODS:
882  if (len != (int)sizeof(unsigned short)) {
883  snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
884  errorf(tmp);
885  } else
886  ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
887  break;
888  case IAX_IE_ENCRYPTION:
889  if (len != (int)sizeof(unsigned short)) {
890  snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
891  errorf(tmp);
892  } else
893  ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
894  break;
895  case IAX_IE_CHALLENGE:
896  ies->challenge = (char *)data + 2;
897  break;
898  case IAX_IE_MD5_RESULT:
899  ies->md5_result = (char *)data + 2;
900  break;
901  case IAX_IE_RSA_RESULT:
902  ies->rsa_result = (char *)data + 2;
903  break;
905  ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
906  break;
907  case IAX_IE_REFRESH:
908  if (len != (int)sizeof(unsigned short)) {
909  snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
910  errorf(tmp);
911  } else
912  ies->refresh = ntohs(get_unaligned_uint16(data + 2));
913  break;
914  case IAX_IE_DPSTATUS:
915  if (len != (int)sizeof(unsigned short)) {
916  snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
917  errorf(tmp);
918  } else
919  ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
920  break;
921  case IAX_IE_CALLNO:
922  if (len != (int)sizeof(unsigned short)) {
923  snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
924  errorf(tmp);
925  } else
926  ies->callno = ntohs(get_unaligned_uint16(data + 2));
927  break;
928  case IAX_IE_CAUSE:
929  ies->cause = (char *)data + 2;
930  break;
931  case IAX_IE_CAUSECODE:
932  if (len != 1) {
933  snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
934  errorf(tmp);
935  } else {
936  ies->causecode = data[2];
937  }
938  break;
939  case IAX_IE_IAX_UNKNOWN:
940  if (len == 1)
941  ies->iax_unknown = data[2];
942  else {
943  snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
944  errorf(tmp);
945  }
946  break;
947  case IAX_IE_MSGCOUNT:
948  if (len != (int)sizeof(unsigned short)) {
949  snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
950  errorf(tmp);
951  } else
952  ies->msgcount = ntohs(get_unaligned_uint16(data + 2));
953  break;
954  case IAX_IE_AUTOANSWER:
955  ies->autoanswer = 1;
956  break;
957  case IAX_IE_MUSICONHOLD:
958  ies->musiconhold = 1;
959  break;
960  case IAX_IE_TRANSFERID:
961  if (len != (int)sizeof(unsigned int)) {
962  snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
963  errorf(tmp);
964  } else
965  ies->transferid = ntohl(get_unaligned_uint32(data + 2));
966  break;
967  case IAX_IE_DATETIME:
968  if (len != (int)sizeof(unsigned int)) {
969  snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
970  errorf(tmp);
971  } else
972  ies->datetime = ntohl(get_unaligned_uint32(data + 2));
973  break;
974  case IAX_IE_FIRMWAREVER:
975  if (len != (int)sizeof(unsigned short)) {
976  snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
977  errorf(tmp);
978  } else
979  ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));
980  break;
981  case IAX_IE_DEVICETYPE:
982  ies->devicetype = (char *)data + 2;
983  break;
984  case IAX_IE_SERVICEIDENT:
985  ies->serviceident = (char *)data + 2;
986  break;
987  case IAX_IE_FWBLOCKDESC:
988  if (len != (int)sizeof(unsigned int)) {
989  snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
990  errorf(tmp);
991  } else
992  ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
993  break;
994  case IAX_IE_FWBLOCKDATA:
995  ies->fwdata = data + 2;
996  ies->fwdatalen = len;
997  break;
998  case IAX_IE_ENCKEY:
999  ies->enckey = data + 2;
1000  ies->enckeylen = len;
1001  break;
1002  case IAX_IE_PROVVER:
1003  if (len != (int)sizeof(unsigned int)) {
1004  snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
1005  errorf(tmp);
1006  } else {
1007  ies->provverpres = 1;
1008  ies->provver = ntohl(get_unaligned_uint32(data + 2));
1009  }
1010  break;
1011  case IAX_IE_CALLINGPRES:
1012  if (len == 1)
1013  ies->calling_pres = data[2];
1014  else {
1015  snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
1016  errorf(tmp);
1017  }
1018  break;
1019  case IAX_IE_CALLINGTON:
1020  if (len == 1)
1021  ies->calling_ton = data[2];
1022  else {
1023  snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
1024  errorf(tmp);
1025  }
1026  break;
1027  case IAX_IE_CALLINGTNS:
1028  if (len != (int)sizeof(unsigned short)) {
1029  snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
1030  errorf(tmp);
1031  } else
1032  ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));
1033  break;
1034  case IAX_IE_RR_JITTER:
1035  if (len != (int)sizeof(unsigned int)) {
1036  snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
1037  errorf(tmp);
1038  } else {
1039  ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
1040  }
1041  break;
1042  case IAX_IE_RR_LOSS:
1043  if (len != (int)sizeof(unsigned int)) {
1044  snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
1045  errorf(tmp);
1046  } else {
1047  ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
1048  }
1049  break;
1050  case IAX_IE_RR_PKTS:
1051  if (len != (int)sizeof(unsigned int)) {
1052  snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
1053  errorf(tmp);
1054  } else {
1055  ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
1056  }
1057  break;
1058  case IAX_IE_RR_DELAY:
1059  if (len != (int)sizeof(unsigned short)) {
1060  snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
1061  errorf(tmp);
1062  } else {
1063  ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
1064  }
1065  break;
1066  case IAX_IE_RR_DROPPED:
1067  if (len != (int)sizeof(unsigned int)) {
1068  snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
1069  errorf(tmp);
1070  } else {
1071  ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
1072  }
1073  break;
1074  case IAX_IE_RR_OOO:
1075  if (len != (int)sizeof(unsigned int)) {
1076  snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
1077  errorf(tmp);
1078  } else {
1079  ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
1080  }
1081  break;
1082  case IAX_IE_VARIABLE:
1083  ast_copy_string(tmp, (char *)data + 2, len + 1);
1084  tmp2 = strchr(tmp, '=');
1085  if (tmp2)
1086  *tmp2++ = '\0';
1087  else
1088  tmp2 = "";
1089  {
1090  struct ast_str *str = ast_str_create(16);
1091  /* Existing variable or new variable? */
1092  for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
1093  if (strcmp(tmp, var2->name) == 0) {
1094  ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
1095  var = ast_variable_new(tmp, ast_str_buffer(str), var2->file);
1096  var->next = var2->next;
1097  if (prev) {
1098  prev->next = var;
1099  } else {
1100  ies->vars = var;
1101  }
1102  snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
1103  outputf(tmp);
1104  ast_free(var2);
1105  break;
1106  }
1107  }
1108  ast_free(str);
1109  }
1110 
1111  if (!var2) {
1112  var = ast_variable_new(tmp, tmp2, "");
1113  snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
1114  outputf(tmp);
1115  var->next = ies->vars;
1116  ies->vars = var;
1117  }
1118  break;
1119  case IAX_IE_OSPTOKEN:
1120  if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
1121  ies->osptokenblock[count] = (char *)data + 2 + 1;
1122  ies->ospblocklength[count] = len - 1;
1123  } else {
1124  snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %u\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
1125  errorf(tmp);
1126  }
1127  break;
1128  case IAX_IE_CALLTOKEN:
1129  if (len) {
1130  ies->calltokendata = (unsigned char *) data + 2;
1131  }
1132  ies->calltoken = 1;
1133  break;
1134  default:
1135  snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
1136  outputf(tmp);
1137  }
1138  /* Overwrite information element with 0, to null terminate previous portion */
1139  data[0] = 0;
1140  datalen -= (len + 2);
1141  data += (len + 2);
1142  }
1143  /* Null-terminate last field */
1144  *data = '\0';
1145  if (datalen) {
1146  errorf("Invalid information element contents, strange boundary\n");
1147  return -1;
1148  }
1149  return 0;
1150 }
1151 
1152 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
1153 {
1154  fr->af.frametype = f->frametype;
1155  fr->af.subclass.codec = f->subclass.codec;
1156  fr->af.mallocd = 0; /* Our frame is static relative to the container */
1157  fr->af.datalen = f->datalen;
1158  fr->af.samples = f->samples;
1160  fr->af.src = f->src;
1161  fr->af.delivery.tv_sec = 0;
1162  fr->af.delivery.tv_usec = 0;
1163  fr->af.data.ptr = fr->afdata;
1164  fr->af.len = f->len;
1165  if (fr->af.datalen) {
1166  size_t copy_len = fr->af.datalen;
1167  if (copy_len > fr->afdatalen) {
1168  ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
1169  (int) fr->afdatalen, (int) fr->af.datalen);
1170  copy_len = fr->afdatalen;
1171  }
1172 #if __BYTE_ORDER == __LITTLE_ENDIAN
1173  /* We need to byte-swap slinear samples from network byte order */
1174  if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass.codec == AST_FORMAT_SLINEAR)) {
1175  /* 2 bytes / sample for SLINEAR */
1176  ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
1177  } else
1178 #endif
1179  memcpy(fr->af.data.ptr, f->data.ptr, copy_len);
1180  }
1181 }
1182 
1183 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
1184 {
1185  struct iax_frame *fr = NULL;
1186 
1187 #if !defined(LOW_MEMORY)
1188  struct iax_frames *iax_frames = NULL;
1189  struct iax_frame *smallest = NULL;
1190 
1191  /* Attempt to get a frame from this thread's cache */
1192  if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1193  smallest = AST_LIST_FIRST(&iax_frames->list);
1194  AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
1195  if (fr->afdatalen >= datalen) {
1196  size_t afdatalen = fr->afdatalen;
1198  iax_frames->size--;
1199  memset(fr, 0, sizeof(*fr));
1200  fr->afdatalen = afdatalen;
1201  break;
1202  } else if (smallest->afdatalen > fr->afdatalen) {
1203  smallest = fr;
1204  }
1205  }
1207  }
1208  if (!fr) {
1209  if (iax_frames && iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) {
1210  /* Make useless cache into something more useful */
1211  AST_LIST_REMOVE(&iax_frames->list, smallest, list);
1212  if (!(fr = ast_realloc(smallest, sizeof(*fr) + datalen))) {
1213  AST_LIST_INSERT_TAIL(&iax_frames->list, smallest, list);
1214  return NULL;
1215  }
1216  } else if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
1217  return NULL;
1218  fr->afdatalen = datalen;
1219  }
1220 #else
1221  if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
1222  return NULL;
1223  fr->afdatalen = datalen;
1224 #endif
1225 
1226 
1227  fr->direction = direction;
1228  fr->retrans = -1;
1229  fr->cacheable = cacheable;
1230 
1231  if (fr->direction == DIRECTION_INGRESS)
1232  ast_atomic_fetchadd_int(&iframes, 1);
1233  else
1234  ast_atomic_fetchadd_int(&oframes, 1);
1235 
1236  ast_atomic_fetchadd_int(&frames, 1);
1237 
1238  return fr;
1239 }
1240 
1241 void iax_frame_free(struct iax_frame *fr)
1242 {
1243 #if !defined(LOW_MEMORY)
1244  struct iax_frames *iax_frames = NULL;
1245 #endif
1246 
1247  /* Note: does not remove from scheduler! */
1248  if (fr->direction == DIRECTION_INGRESS)
1249  ast_atomic_fetchadd_int(&iframes, -1);
1250  else if (fr->direction == DIRECTION_OUTGRESS)
1251  ast_atomic_fetchadd_int(&oframes, -1);
1252  else {
1253  errorf("Attempt to double free frame detected\n");
1254  return;
1255  }
1256  ast_atomic_fetchadd_int(&frames, -1);
1257 
1258 #if !defined(LOW_MEMORY)
1259  if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1260  ast_free(fr);
1261  return;
1262  }
1263 
1264  if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
1265  fr->direction = 0;
1266  /* Pseudo-sort: keep smaller frames at the top of the list. This should
1267  * increase the chance that we pick the smallest applicable frame for use. */
1268  if (AST_LIST_FIRST(&iax_frames->list) && AST_LIST_FIRST(&iax_frames->list)->afdatalen < fr->afdatalen) {
1269  AST_LIST_INSERT_TAIL(&iax_frames->list, fr, list);
1270  } else {
1271  AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
1272  }
1273  iax_frames->size++;
1274  return;
1275  }
1276 #endif
1277  ast_free(fr);
1278 }
1279 
1280 #if !defined(LOW_MEMORY)
1281 static void frame_cache_cleanup(void *data)
1282 {
1283  struct iax_frames *framelist = data;
1284  struct iax_frame *current;
1285 
1286  while ((current = AST_LIST_REMOVE_HEAD(&framelist->list, list)))
1287  ast_free(current);
1288 
1289  ast_free(framelist);
1290 }
1291 #endif
1292 
1293 int iax_get_frames(void) { return frames; }
1294 int iax_get_iframes(void) { return iframes; }
1295 int iax_get_oframes(void) { return oframes; }
static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
Definition: iax2-parser.c:336
union ast_frame_subclass subclass
Definition: frame.h:146
struct ast_frame af
Definition: iax2-parser.h:139
unsigned int fwdesc
Definition: iax2-parser.h:64
#define IAX_IE_IAX_UNKNOWN
Definition: iax2.h:153
void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len)
Definition: iax2-parser.c:435
#define DIRECTION_INGRESS
Definition: iax2-parser.h:85
#define IAX_RATE_22KHZ
Definition: iax2.h:211
#define PROV_IE_FORMAT
#define IAX_IE_CAPABILITY2
Definition: iax2.h:187
unsigned char csub
Definition: iax2.h:229
uint32_t version
int calling_tns
Definition: iax2-parser.h:31
Asterisk locking-related definitions:
int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
Definition: iax2-parser.c:762
#define IAX_IE_CALLINGTNS
Definition: iax2.h:170
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
Definition: iax2-parser.c:567
#define PROV_IE_USEDHCP
#define PROV_IE_PASS
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int offset
Definition: frame.h:156
char * serviceident
Definition: iax2-parser.h:62
void iax_set_output(void(*func)(const char *))
Definition: iax2-parser.c:752
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
static void dump_string_hex(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:95
#define IAX_IE_PROVVER
Definition: iax2.h:167
char * rsa_result
Definition: iax2-parser.h:48
This is just so iax_frames, a list head struct for holding a list of iax_frame structures, is defined.
Definition: iax2-parser.c:61
char * md5_result
Definition: iax2-parser.h:47
#define IAX_RATE_44KHZ
Definition: iax2.h:212
#define DIRECTION_OUTGRESS
Definition: iax2-parser.h:86
int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
Dump audio codec preference list into a string.
Definition: frame.c:1025
Definition: ast_expr2.c:325
void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
Definition: iax2-parser.c:1152
unsigned short scallno
Definition: iax2.h:223
uint64_t ntohll(uint64_t net64)
Definition: strcompat.c:361
size_t afdatalen
Definition: iax2-parser.h:141
iax_frame_subclass
Definition: iax2.h:51
void * ptr
Definition: frame.h:160
unsigned int transferid
Definition: iax2-parser.h:59
#define IAX_IE_VARIABLE
Definition: iax2.h:183
#define IAX_IE_RR_LOSS
Definition: iax2.h:178
struct iax_frame * iax_frame_new(int direction, int datalen, unsigned int cacheable)
Definition: iax2-parser.c:1183
static struct iax2_ie prov_ies[]
Definition: iax2-parser.c:305
struct sockaddr_in * apparent_addr
Definition: iax2-parser.h:49
unsigned char * fwdata
Definition: iax2-parser.h:65
#define IAX_IE_DATETIME
Definition: iax2.h:161
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
char * username
Definition: iax2-parser.h:34
unsigned char oseqno
Definition: iax2.h:226
unsigned int rr_dropped
Definition: iax2-parser.h:76
int calling_ton
Definition: iax2-parser.h:30
#define IAX_IE_CALLNO
Definition: iax2.h:151
uint64_t htonll(uint64_t host64)
Definition: strcompat.c:387
#define IAX_RATE_48KHZ
Definition: iax2.h:213
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define IAX_IE_MD5_RESULT
Definition: iax2.h:146
unsigned char * enckey
Definition: iax2-parser.h:67
static void(* errorf)(const char *str)
Definition: iax2-parser.c:82
#define var
Definition: ast_expr2f.c:606
#define IAX_IE_FIRMWAREVER
Definition: iax2.h:164
format_t capability
Definition: iax2-parser.h:36
int firmwarever
Definition: iax2-parser.h:63
static void dump_short(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:141
unsigned char afdata[0]
Definition: iax2-parser.h:143
#define IAX_IE_RR_DELAY
Definition: iax2.h:180
Configuration File Parser.
static void dump_ipaddr(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:173
static void internaloutput(const char *str)
Definition: iax2-parser.c:71
#define PROV_IE_SUBNET
#define IAX_IE_AUTOANSWER
Definition: iax2.h:155
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
#define PROV_IE_IPADDR
#define IAX_IE_SAMPLINGRATE
Definition: iax2.h:171
unsigned int rr_loss
Definition: iax2-parser.h:73
unsigned int datetime
Definition: iax2-parser.h:60
const char * str
Definition: app_jack.c:144
format_t codec
Definition: frame.h:137
int iax_get_iframes(void)
Definition: iax2-parser.c:1294
#define IAX_IE_CHALLENGE
Definition: iax2.h:145
unsigned int provver
Definition: iax2-parser.h:69
unsigned short dpstatus
Definition: iax2-parser.h:51
Definitions to aid in the use of thread local storage.
unsigned char fwdatalen
Definition: iax2-parser.h:66
int value
Definition: syslog.c:39
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
#define IAX_IE_DPSTATUS
Definition: iax2.h:150
char * devicetype
Definition: iax2-parser.h:61
#define IAX_IE_LANGUAGE
Definition: iax2.h:140
char * calling_number
Definition: iax2-parser.h:27
int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value)
Definition: iax2-parser.c:713
format_t format
Definition: iax2-parser.h:37
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
int tm_year
Definition: localtime.h:41
#define IAX_IE_RR_JITTER
Definition: iax2.h:177
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
#define IAX_IE_CALLING_NUMBER
Definition: iax2.h:132
#define PROV_IE_GATEWAY
#define IAX_IE_CALLING_ANI
Definition: iax2.h:133
static int frames
Definition: iax2-parser.c:49
Utility functions.
#define PROV_IE_PROVVER
unsigned char type
Definition: iax2.h:228
#define IAX_IE_DEVICETYPE
Definition: iax2.h:162
static void dump_datetime(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:157
#define IAX_IE_ENCRYPTION
Definition: iax2.h:173
int iax_get_oframes(void)
Definition: iax2-parser.c:1295
#define IAX_IE_ENCKEY
Definition: iax2.h:174
int msgcount
Definition: iax2-parser.h:56
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
unsigned short dcallno
Definition: iax2.h:224
static void frame_cache_cleanup(void *data)
Definition: iax2-parser.c:1281
char * called_context
Definition: iax2-parser.h:33
char * codec_prefs
Definition: iax2-parser.h:38
char * challenge
Definition: iax2-parser.h:46
Handle unaligned data access.
#define IAX_MAX_OSPBLOCK_NUM
Definition: iax2.h:191
unsigned int encmethods
Definition: iax2-parser.h:45
const char * value
Definition: config.h:79
unsigned short callno
Definition: iax2-parser.h:52
int provverpres
Definition: iax2-parser.h:71
int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
Definition: iax2-parser.c:708
unsigned char * calltokendata
Definition: iax2-parser.h:82
#define IAX_IE_FORMAT2
Definition: iax2.h:188
unsigned char causecode
Definition: iax2-parser.h:54
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Definition: frame.h:204
const char * src
Definition: frame.h:158
unsigned int cacheable
Definition: iax2-parser.h:121
#define IAX_IE_CAUSECODE
Definition: iax2.h:172
unsigned int rr_jitter
Definition: iax2-parser.h:72
static int iframes
Definition: iax2-parser.c:50
#define IAX_IE_VERSION
Definition: iax2.h:141
#define PROV_IE_FLAGS
unsigned char iax_unknown
Definition: iax2-parser.h:55
Asterisk internal frame definitions.
int datalen
Definition: frame.h:148
char * osptokenblock[IAX_MAX_OSPBLOCK_NUM]
Definition: iax2-parser.h:79
#define IAX_IE_SERVICEIDENT
Definition: iax2.h:163
int tm_mon
Definition: localtime.h:40
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
Definition: iax2-parser.c:730
#define IAX_IE_CALLING_NAME
Definition: iax2.h:134
size_t size
Definition: iax2-parser.c:65
#define IAX_IE_PROVISIONING
Definition: iax2.h:159
#define IAX_IE_AESPROVISIONING
Definition: iax2.h:160
const char * name
Definition: config.h:77
#define FRAME_CACHE_MAX_SIZE
Definition: iax2-parser.c:68
unsigned short adsicpe
Definition: iax2-parser.h:41
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
int tm_mday
Definition: localtime.h:39
#define PROV_IE_SERVERPORT
int iax_get_frames(void)
Definition: iax2-parser.c:1293
#define IAX_IE_DNID
Definition: iax2.h:143
static unsigned int get_unaligned_uint32(const void *p)
Definition: unaligned.h:38
#define PROV_IE_SERVERIP
int version
Definition: iax2-parser.h:40
static unsigned short get_unaligned_uint16(const void *p)
Definition: unaligned.h:44
unsigned int direction
Definition: iax2-parser.h:119
#define IAX_IE_CALLTOKEN
Definition: iax2.h:185
unsigned int rr_ooo
Definition: iax2-parser.h:77
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
#define IAX_IE_CALLED_NUMBER
Definition: iax2.h:131
#define IAX_IE_ADSICPE
Definition: iax2.h:142
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
Implementation of Inter-Asterisk eXchange, version 2 iax2-parser.c iax2-parser.h chan_iax2.c.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
int64_t format_t
Definition: frame_defs.h:32
const char * file
Definition: config.h:85
void * data
Definition: iax2-parser.h:101
int calling_pres
Definition: iax2-parser.h:32
#define IAX_IE_AUTHMETHODS
Definition: iax2.h:144
#define PROV_IE_NEWAESKEY
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * language
Definition: iax2-parser.h:39
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 IAX_IE_PASSWORD
Definition: iax2.h:137
static void dump_prefs(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:114
char * rdnis
Definition: iax2-parser.h:43
static void dump_ies(unsigned char *iedata, int len)
Definition: iax2-parser.c:388
#define IAX_IE_MSGCOUNT
Definition: iax2.h:154
void iax_set_error(void(*func)(const char *))
Definition: iax2-parser.c:757
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
#define IAX_IE_FWBLOCKDESC
Definition: iax2.h:165
#define PROV_IE_LANG
char * calling_name
Definition: iax2-parser.h:29
static const char name[]
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: utils.c:564
unsigned int authmethods
Definition: iax2-parser.h:44
#define IAX_IE_RR_OOO
Definition: iax2.h:182
#define ast_free(a)
Definition: astmm.h:97
unsigned char calltoken
Definition: iax2-parser.h:81
static void put_unaligned_uint64(void *p, uint64_t datum)
Definition: unaligned.h:51
#define PROV_IE_ALTSERVER
unsigned char iedata[0]
Definition: iax2.h:230
int autoanswer
Definition: iax2-parser.h:57
unsigned char iseqno
Definition: iax2.h:227
#define PROV_IE_AESKEY
#define IAX_IE_CODEC_PREFS
Definition: iax2.h:175
static void dump_samprate(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:194
static struct ast_format f[]
Definition: format_g726.c:181
char * called_number
Definition: iax2-parser.h:26
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2351
static void dump_prov(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:237
int tm_hour
Definition: localtime.h:38
static void dump_versioned_codec(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:221
int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
Definition: iax2-parser.c:693
unsigned char buf[1024]
Definition: iax2-parser.h:147
#define IAX_IE_OSPTOKEN
Definition: iax2.h:184
unsigned char enckeylen
Definition: iax2-parser.h:68
struct timeval delivery
Definition: frame.h:162
int mallocd
Definition: frame.h:152
unsigned short rr_delay
Definition: iax2-parser.h:75
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
static void internalerror(const char *str)
Definition: iax2-parser.c:76
static struct iax2_ie infoelts[]
Definition: iax2-parser.c:247
int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
Definition: iax2-parser.c:747
#define IAX_IE_CALLINGTON
Definition: iax2.h:169
int tm_sec
Definition: localtime.h:36
#define IAX_IE_REFRESH
Definition: iax2.h:149
static void(* outputf)(const char *str)
Definition: iax2-parser.c:81
struct ast_variable * vars
Definition: iax2-parser.h:78
#define IAX_IE_CALLINGPRES
Definition: iax2.h:168
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
#define IAX_IE_RDNIS
Definition: iax2.h:158
int musiconhold
Definition: iax2-parser.h:58
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define IAX_IE_USERNAME
Definition: iax2.h:136
static void dump_string(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:105
Implementation of the IAX2 protocol.
#define IAX_IE_RR_DROPPED
Definition: iax2.h:181
#define ast_realloc(a, b)
Definition: astmm.h:103
int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
Definition: iax2-parser.c:723
unsigned int rr_pkts
Definition: iax2-parser.h:74
#define IAX_IE_MUSICONHOLD
Definition: iax2.h:156
void(* dump)(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:245
static void dump_int(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:133
#define IAX_IE_RR_PKTS
Definition: iax2.h:179
Data structure associated with a single frame of data.
Definition: frame.h:142
#define IAX_FLAG_FULL
Definition: iax2.h:40
#define IAX_IE_CAUSE
Definition: iax2.h:152
#define IAX_IE_RSA_RESULT
Definition: iax2.h:147
void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
Shift an audio codec preference list up or down 65 bytes so that it becomes an ASCII string...
Definition: frame.c:1002
unsigned int ospblocklength[IAX_MAX_OSPBLOCK_NUM]
Definition: iax2-parser.h:80
char * password
Definition: iax2-parser.h:35
IAX2 Provisioning protocol.
char * name
Definition: iax2-parser.c:244
#define IAX_IE_FWBLOCKDATA
Definition: iax2.h:166
char * calling_ani
Definition: iax2-parser.h:28
#define IAX_IE_CALLED_CONTEXT
Definition: iax2.h:135
#define IAX_RATE_16KHZ
Definition: iax2.h:210
void iax_frame_free(struct iax_frame *fr)
Definition: iax2-parser.c:1241
struct iax_frame::@116 list
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
enum ast_frame_type frametype
Definition: frame.h:144
struct ast_variable * next
Definition: config.h:82
static int oframes
Definition: iax2-parser.c:51
#define IAX_IE_APPARENT_ADDR
Definition: iax2.h:148
struct iax_frame_list list
Definition: iax2-parser.c:64
static void dump_addr(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:84
char * iax_provflags2str(char *buf, int buflen, unsigned int flags)
int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
Definition: iax2-parser.c:742
static void dump_prov_flags(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:184
unsigned short refresh
Definition: iax2-parser.h:50
#define PROV_IE_PORTNO
#define IAX_IE_TRANSFERID
Definition: iax2.h:157
char * cause
Definition: iax2-parser.h:53
const char * iax_ie2str(int ie)
Definition: iax2-parser.c:325
void ast_swapcopy_samples(void *dst, const void *src, int samples)
Definition: frame.c:556
#define IAX_IE_FORMAT
Definition: iax2.h:139
#define IAX_FLAG_RETRANS
Definition: iax2.h:42
int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
Definition: iax2-parser.c:737
#define IAX_RATE_11KHZ
Definition: iax2.h:209
union ast_frame::@172 data
long len
Definition: frame.h:170
static void dump_byte(char *output, int maxlen, void *value, int len)
Definition: iax2-parser.c:149
static struct ast_threadstorage frame_cache
Definition: iax2-parser.c:57
#define IAX_IE_CAPABILITY
Definition: iax2.h:138
#define IAX_RATE_8KHZ
Definition: iax2.h:208
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
static uint64_t get_unaligned_uint64(const void *p)
Definition: unaligned.h:32
int tm_min
Definition: localtime.h:37
char * dnid
Definition: iax2-parser.h:42
unsigned short samprate
Definition: iax2-parser.h:70
#define PROV_IE_USER
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int samples
Definition: frame.h:150
#define ast_calloc_cache(a, b)
Definition: astmm.h:85
#define PROV_IE_TOS
unsigned int ts
Definition: iax2.h:225