Merge in ast_strftime branch, which changes timestamps to be accurate to the microsec...
[asterisk/asterisk.git] / channels / iax2-parser.c
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 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <string.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38
39 #include "asterisk/frame.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/unaligned.h"
42 #include "asterisk/config.h"
43 #include "asterisk/lock.h"
44 #include "asterisk/threadstorage.h"
45
46 #include "iax2.h"
47 #include "iax2-parser.h"
48 #include "iax2-provision.h"
49
50 static int frames = 0;
51 static int iframes = 0;
52 static int oframes = 0;
53
54 #if !defined(LOW_MEMORY)
55 static void frame_cache_cleanup(void *data);
56
57 /*! \brief A per-thread cache of iax_frame structures */
58 AST_THREADSTORAGE_CUSTOM(frame_cache, NULL, frame_cache_cleanup);
59
60 /*! \brief This is just so iax_frames, a list head struct for holding a list of
61  *  iax_frame structures, is defined. */
62 AST_LIST_HEAD_NOLOCK(iax_frames, iax_frame);
63 #endif
64
65 static void internaloutput(const char *str)
66 {
67         fputs(str, stdout);
68 }
69
70 static void internalerror(const char *str)
71 {
72         fprintf(stderr, "WARNING: %s", str);
73 }
74
75 static void (*outputf)(const char *str) = internaloutput;
76 static void (*errorf)(const char *str) = internalerror;
77
78 static void dump_addr(char *output, int maxlen, void *value, int len)
79 {
80         struct sockaddr_in sin;
81         if (len == (int)sizeof(sin)) {
82                 memcpy(&sin, value, len);
83                 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
84         } else {
85                 snprintf(output, maxlen, "Invalid Address");
86         }
87 }
88
89 static void dump_string(char *output, int maxlen, void *value, int len)
90 {
91         maxlen--;
92         if (maxlen > len)
93                 maxlen = len;
94         strncpy(output, value, maxlen);
95         output[maxlen] = '\0';
96 }
97
98 static void dump_prefs(char *output, int maxlen, void *value, int len)
99 {
100         struct ast_codec_pref pref;
101         int total_len = 0;
102
103         maxlen--;
104         total_len = maxlen;
105
106         if (maxlen > len)
107                 maxlen = len;
108
109         strncpy(output, value, maxlen);
110         output[maxlen] = '\0';
111         
112         ast_codec_pref_convert(&pref, output, total_len, 0);
113         memset(output,0,total_len);
114         ast_codec_pref_string(&pref, output, total_len);
115 }
116
117 static void dump_int(char *output, int maxlen, void *value, int len)
118 {
119         if (len == (int)sizeof(unsigned int))
120                 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
121         else
122                 ast_copy_string(output, "Invalid INT", maxlen); 
123 }
124
125 static void dump_short(char *output, int maxlen, void *value, int len)
126 {
127         if (len == (int)sizeof(unsigned short))
128                 snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
129         else
130                 ast_copy_string(output, "Invalid SHORT", maxlen);
131 }
132
133 static void dump_byte(char *output, int maxlen, void *value, int len)
134 {
135         if (len == (int)sizeof(unsigned char))
136                 snprintf(output, maxlen, "%d", *((unsigned char *)value));
137         else
138                 ast_copy_string(output, "Invalid BYTE", maxlen);
139 }
140
141 static void dump_datetime(char *output, int maxlen, void *value, int len)
142 {
143         struct ast_tm tm;
144         unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
145         if (len == (int)sizeof(unsigned int)) {
146                 tm.tm_sec  = (val & 0x1f) << 1;
147                 tm.tm_min  = (val >> 5) & 0x3f;
148                 tm.tm_hour = (val >> 11) & 0x1f;
149                 tm.tm_mday = (val >> 16) & 0x1f;
150                 tm.tm_mon  = ((val >> 21) & 0x0f) - 1;
151                 tm.tm_year = ((val >> 25) & 0x7f) + 100;
152                 ast_strftime(output, maxlen, "%Y-%m-%d  %T", &tm); 
153         } else
154                 ast_copy_string(output, "Invalid DATETIME format!", maxlen);
155 }
156
157 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
158 {
159         struct sockaddr_in sin;
160         if (len == (int)sizeof(unsigned int)) {
161                 memcpy(&sin.sin_addr, value, len);
162                 snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
163         } else
164                 ast_copy_string(output, "Invalid IPADDR", maxlen);
165 }
166
167
168 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
169 {
170         char buf[256] = "";
171         if (len == (int)sizeof(unsigned int))
172                 snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
173                         iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
174         else
175                 ast_copy_string(output, "Invalid INT", maxlen);
176 }
177
178 static void dump_samprate(char *output, int maxlen, void *value, int len)
179 {
180         char tmp[256]="";
181         int sr;
182         if (len == (int)sizeof(unsigned short)) {
183                 sr = ntohs(*((unsigned short *)value));
184                 if (sr & IAX_RATE_8KHZ)
185                         strcat(tmp, ",8khz");
186                 if (sr & IAX_RATE_11KHZ)
187                         strcat(tmp, ",11.025khz");
188                 if (sr & IAX_RATE_16KHZ)
189                         strcat(tmp, ",16khz");
190                 if (sr & IAX_RATE_22KHZ)
191                         strcat(tmp, ",22.05khz");
192                 if (sr & IAX_RATE_44KHZ)
193                         strcat(tmp, ",44.1khz");
194                 if (sr & IAX_RATE_48KHZ)
195                         strcat(tmp, ",48khz");
196                 if (strlen(tmp))
197                         ast_copy_string(output, &tmp[1], maxlen);
198                 else
199                         ast_copy_string(output, "None Specified!\n", maxlen);
200         } else
201                 ast_copy_string(output, "Invalid SHORT", maxlen);
202
203 }
204
205 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
206 static void dump_prov(char *output, int maxlen, void *value, int len)
207 {
208         dump_prov_ies(output, maxlen, value, len);
209 }
210
211 static struct iax2_ie {
212         int ie;
213         char *name;
214         void (*dump)(char *output, int maxlen, void *value, int len);
215 } ies[] = {
216         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
217         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
218         { IAX_IE_CALLING_ANI, "ANI", dump_string },
219         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
220         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
221         { IAX_IE_USERNAME, "USERNAME", dump_string },
222         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
223         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
224         { IAX_IE_FORMAT, "FORMAT", dump_int },
225         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
226         { IAX_IE_VERSION, "VERSION", dump_short },
227         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
228         { IAX_IE_DNID, "DNID", dump_string },
229         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
230         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
231         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
232         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
233         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
234         { IAX_IE_REFRESH, "REFRESH", dump_short },
235         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
236         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
237         { IAX_IE_CAUSE, "CAUSE", dump_string },
238         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
239         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
240         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
241         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
242         { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
243         { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
244         { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
245         { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
246         { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
247         { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
248         { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
249         { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
250         { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
251         { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
252         { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
253         { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
254         { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
255         { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
256         { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
257         { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
258         { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
259         { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
260         { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
261         { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
262         { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
263         { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
264         { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
265         { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
266         { IAX_IE_VARIABLE, "VARIABLE", dump_string },
267         { IAX_IE_OSPTOKEN, "OSPTOKEN" },
268 };
269
270 static struct iax2_ie prov_ies[] = {
271         { PROV_IE_USEDHCP, "USEDHCP" },
272         { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
273         { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
274         { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
275         { PROV_IE_PORTNO, "BINDPORT", dump_short },
276         { PROV_IE_USER, "USERNAME", dump_string },
277         { PROV_IE_PASS, "PASSWORD", dump_string },
278         { PROV_IE_LANG, "LANGUAGE", dump_string },
279         { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
280         { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
281         { PROV_IE_FORMAT, "FORMAT", dump_int },
282         { PROV_IE_AESKEY, "AESKEY" },
283         { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
284         { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
285         { PROV_IE_NEWAESKEY, "NEWAESKEY" },
286         { PROV_IE_PROVVER, "PROV VERSION", dump_int },
287         { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
288 };
289
290 const char *iax_ie2str(int ie)
291 {
292         int x;
293         for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
294                 if (ies[x].ie == ie)
295                         return ies[x].name;
296         }
297         return "Unknown IE";
298 }
299
300
301 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
302 {
303         int ielen;
304         int ie;
305         int x;
306         int found;
307         char interp[80];
308         char tmp[256];
309         if (len < 2)
310                 return;
311         strcpy(output, "\n"); 
312         maxlen -= strlen(output); output += strlen(output);
313         while(len > 2) {
314                 ie = iedata[0];
315                 ielen = iedata[1];
316                 if (ielen + 2> len) {
317                         snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
318                         ast_copy_string(output, tmp, maxlen);
319                         maxlen -= strlen(output);
320                         output += strlen(output);
321                         return;
322                 }
323                 found = 0;
324                 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
325                         if (prov_ies[x].ie == ie) {
326                                 if (prov_ies[x].dump) {
327                                         prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
328                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
329                                         ast_copy_string(output, tmp, maxlen);
330                                         maxlen -= strlen(output); output += strlen(output);
331                                 } else {
332                                         if (ielen)
333                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
334                                         else
335                                                 strcpy(interp, "Present");
336                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
337                                         ast_copy_string(output, tmp, maxlen);
338                                         maxlen -= strlen(output); output += strlen(output);
339                                 }
340                                 found++;
341                         }
342                 }
343                 if (!found) {
344                         snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
345                         ast_copy_string(output, tmp, maxlen);
346                         maxlen -= strlen(output); output += strlen(output);
347                 }
348                 iedata += (2 + ielen);
349                 len -= (2 + ielen);
350         }
351 }
352
353 static void dump_ies(unsigned char *iedata, int len)
354 {
355         int ielen;
356         int ie;
357         int x;
358         int found;
359         char interp[1024];
360         char tmp[1024];
361         if (len < 2)
362                 return;
363         while(len > 2) {
364                 ie = iedata[0];
365                 ielen = iedata[1];
366                 if (ielen + 2> len) {
367                         snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
368                         outputf(tmp);
369                         return;
370                 }
371                 found = 0;
372                 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
373                         if (ies[x].ie == ie) {
374                                 if (ies[x].dump) {
375                                         ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
376                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
377                                         outputf(tmp);
378                                 } else {
379                                         if (ielen)
380                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
381                                         else
382                                                 strcpy(interp, "Present");
383                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
384                                         outputf(tmp);
385                                 }
386                                 found++;
387                         }
388                 }
389                 if (!found) {
390                         snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
391                         outputf(tmp);
392                 }
393                 iedata += (2 + ielen);
394                 len -= (2 + ielen);
395         }
396         outputf("\n");
397 }
398
399 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
400 {
401         const char *frames[] = {
402                 "(0?)",
403                 "DTMF_E ",
404                 "VOICE  ",
405                 "VIDEO  ",
406                 "CONTROL",
407                 "NULL   ",
408                 "IAX    ",
409                 "TEXT   ",
410                 "IMAGE  ",
411                 "HTML   ",
412                 "CNG    ",
413                 "MODEM  ",
414                 "DTMF_B ",
415         };
416         const char *iaxs[] = {
417                 "(0?)",
418                 "NEW    ",
419                 "PING   ",
420                 "PONG   ",
421                 "ACK    ",
422                 "HANGUP ",
423                 "REJECT ",
424                 "ACCEPT ",
425                 "AUTHREQ",
426                 "AUTHREP",
427                 "INVAL  ",
428                 "LAGRQ  ",
429                 "LAGRP  ",
430                 "REGREQ ",
431                 "REGAUTH",
432                 "REGACK ",
433                 "REGREJ ",
434                 "REGREL ",
435                 "VNAK   ",
436                 "DPREQ  ",
437                 "DPREP  ",
438                 "DIAL   ",
439                 "TXREQ  ",
440                 "TXCNT  ",
441                 "TXACC  ",
442                 "TXREADY",
443                 "TXREL  ",
444                 "TXREJ  ",
445                 "QUELCH ",
446                 "UNQULCH",
447                 "POKE   ",
448                 "PAGE   ",
449                 "MWI    ",
450                 "UNSPRTD",
451                 "TRANSFR",
452                 "PROVISN",
453                 "FWDWNLD",
454                 "FWDATA ",
455                 "TXMEDIA"
456         };
457         const char *cmds[] = {
458                 "(0?)",
459                 "HANGUP ",
460                 "RING   ",
461                 "RINGING",
462                 "ANSWER ",
463                 "BUSY   ",
464                 "TKOFFHK",
465                 "OFFHOOK",
466                 "CONGSTN",
467                 "FLASH  ",
468                 "WINK   ",
469                 "OPTION ",
470                 "RDKEY  ",
471                 "RDUNKEY",
472                 "PROGRES",
473                 "PROCDNG",
474                 "HOLD   ",
475                 "UNHOLD ",
476                 "VIDUPDT", };
477         struct ast_iax2_full_hdr *fh;
478         char retries[20];
479         char class2[20];
480         char subclass2[20];
481         const char *class;
482         const char *subclass;
483         char *dir;
484         char tmp[512];
485
486         switch(rx) {
487         case 0:
488                 dir = "Tx";
489                 break;
490         case 2:
491                 dir = "TE";
492                 break;
493         case 3:
494                 dir = "RD";
495                 break;
496         default:
497                 dir = "Rx";
498                 break;
499         }
500         if (f) {
501                 fh = f->data;
502                 snprintf(retries, sizeof(retries), "%03d", f->retries);
503         } else {
504                 fh = fhi;
505                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
506                         strcpy(retries, "Yes");
507                 else
508                         strcpy(retries, " No");
509         }
510         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
511                 /* Don't mess with mini-frames */
512                 return;
513         }
514         if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
515                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
516                 class = class2;
517         } else {
518                 class = frames[(int)fh->type];
519         }
520         if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
521                 sprintf(subclass2, "%c", fh->csub);
522                 subclass = subclass2;
523         } else if (fh->type == AST_FRAME_IAX) {
524                 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
525                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
526                         subclass = subclass2;
527                 } else {
528                         subclass = iaxs[(int)fh->csub];
529                 }
530         } else if (fh->type == AST_FRAME_CONTROL) {
531                 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
532                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
533                         subclass = subclass2;
534                 } else {
535                         subclass = cmds[(int)fh->csub];
536                 }
537         } else {
538                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
539                 subclass = subclass2;
540         }
541         snprintf(tmp, sizeof(tmp), 
542                  "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
543                  dir,
544                  retries, fh->oseqno, fh->iseqno, class, subclass);
545         outputf(tmp);
546         snprintf(tmp, sizeof(tmp), 
547                  "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
548                  (unsigned long)ntohl(fh->ts),
549                  ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
550                  ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
551         outputf(tmp);
552         if (fh->type == AST_FRAME_IAX)
553                 dump_ies(fh->iedata, datalen);
554 }
555
556 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
557 {
558         char tmp[256];
559         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
560                 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);
561                 errorf(tmp);
562                 return -1;
563         }
564         ied->buf[ied->pos++] = ie;
565         ied->buf[ied->pos++] = datalen;
566         memcpy(ied->buf + ied->pos, data, datalen);
567         ied->pos += datalen;
568         return 0;
569 }
570
571 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
572 {
573         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
574 }
575
576 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
577 {
578         unsigned int newval;
579         newval = htonl(value);
580         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
581 }
582
583 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
584 {
585         unsigned short newval;
586         newval = htons(value);
587         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
588 }
589
590 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
591 {
592         return iax_ie_append_raw(ied, ie, str, strlen(str));
593 }
594
595 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
596 {
597         return iax_ie_append_raw(ied, ie, &dat, 1);
598 }
599
600 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
601 {
602         return iax_ie_append_raw(ied, ie, NULL, 0);
603 }
604
605 void iax_set_output(void (*func)(const char *))
606 {
607         outputf = func;
608 }
609
610 void iax_set_error(void (*func)(const char *))
611 {
612         errorf = func;
613 }
614
615 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
616 {
617         /* Parse data into information elements */
618         int len;
619         int ie;
620         char tmp[256], *tmp2;
621         struct ast_variable *var, *var2, *prev;
622         unsigned int count;
623         memset(ies, 0, (int)sizeof(struct iax_ies));
624         ies->msgcount = -1;
625         ies->firmwarever = -1;
626         ies->calling_ton = -1;
627         ies->calling_tns = -1;
628         ies->calling_pres = -1;
629         ies->samprate = IAX_RATE_8KHZ;
630         while(datalen >= 2) {
631                 ie = data[0];
632                 len = data[1];
633                 if (len > datalen - 2) {
634                         errorf("Information element length exceeds message size\n");
635                         return -1;
636                 }
637                 switch(ie) {
638                 case IAX_IE_CALLED_NUMBER:
639                         ies->called_number = (char *)data + 2;
640                         break;
641                 case IAX_IE_CALLING_NUMBER:
642                         ies->calling_number = (char *)data + 2;
643                         break;
644                 case IAX_IE_CALLING_ANI:
645                         ies->calling_ani = (char *)data + 2;
646                         break;
647                 case IAX_IE_CALLING_NAME:
648                         ies->calling_name = (char *)data + 2;
649                         break;
650                 case IAX_IE_CALLED_CONTEXT:
651                         ies->called_context = (char *)data + 2;
652                         break;
653                 case IAX_IE_USERNAME:
654                         ies->username = (char *)data + 2;
655                         break;
656                 case IAX_IE_PASSWORD:
657                         ies->password = (char *)data + 2;
658                         break;
659                 case IAX_IE_CODEC_PREFS:
660                         ies->codec_prefs = (char *)data + 2;
661                         break;
662                 case IAX_IE_CAPABILITY:
663                         if (len != (int)sizeof(unsigned int)) {
664                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
665                                 errorf(tmp);
666                         } else
667                                 ies->capability = ntohl(get_unaligned_uint32(data + 2));
668                         break;
669                 case IAX_IE_FORMAT:
670                         if (len != (int)sizeof(unsigned int)) {
671                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
672                                 errorf(tmp);
673                         } else
674                                 ies->format = ntohl(get_unaligned_uint32(data + 2));
675                         break;
676                 case IAX_IE_LANGUAGE:
677                         ies->language = (char *)data + 2;
678                         break;
679                 case IAX_IE_VERSION:
680                         if (len != (int)sizeof(unsigned short)) {
681                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
682                                 errorf(tmp);
683                         } else
684                                 ies->version = ntohs(get_unaligned_uint16(data + 2));
685                         break;
686                 case IAX_IE_ADSICPE:
687                         if (len != (int)sizeof(unsigned short)) {
688                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
689                                 errorf(tmp);
690                         } else
691                                 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
692                         break;
693                 case IAX_IE_SAMPLINGRATE:
694                         if (len != (int)sizeof(unsigned short)) {
695                                 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
696                                 errorf(tmp);
697                         } else
698                                 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
699                         break;
700                 case IAX_IE_DNID:
701                         ies->dnid = (char *)data + 2;
702                         break;
703                 case IAX_IE_RDNIS:
704                         ies->rdnis = (char *)data + 2;
705                         break;
706                 case IAX_IE_AUTHMETHODS:
707                         if (len != (int)sizeof(unsigned short))  {
708                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
709                                 errorf(tmp);
710                         } else
711                                 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
712                         break;
713                 case IAX_IE_ENCRYPTION:
714                         if (len != (int)sizeof(unsigned short))  {
715                                 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
716                                 errorf(tmp);
717                         } else
718                                 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
719                         break;
720                 case IAX_IE_CHALLENGE:
721                         ies->challenge = (char *)data + 2;
722                         break;
723                 case IAX_IE_MD5_RESULT:
724                         ies->md5_result = (char *)data + 2;
725                         break;
726                 case IAX_IE_RSA_RESULT:
727                         ies->rsa_result = (char *)data + 2;
728                         break;
729                 case IAX_IE_APPARENT_ADDR:
730                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
731                         break;
732                 case IAX_IE_REFRESH:
733                         if (len != (int)sizeof(unsigned short)) {
734                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
735                                 errorf(tmp);
736                         } else
737                                 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
738                         break;
739                 case IAX_IE_DPSTATUS:
740                         if (len != (int)sizeof(unsigned short)) {
741                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
742                                 errorf(tmp);
743                         } else
744                                 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
745                         break;
746                 case IAX_IE_CALLNO:
747                         if (len != (int)sizeof(unsigned short)) {
748                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
749                                 errorf(tmp);
750                         } else
751                                 ies->callno = ntohs(get_unaligned_uint16(data + 2));
752                         break;
753                 case IAX_IE_CAUSE:
754                         ies->cause = (char *)data + 2;
755                         break;
756                 case IAX_IE_CAUSECODE:
757                         if (len != 1) {
758                                 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
759                                 errorf(tmp);
760                         } else {
761                                 ies->causecode = data[2];
762                         }
763                         break;
764                 case IAX_IE_IAX_UNKNOWN:
765                         if (len == 1)
766                                 ies->iax_unknown = data[2];
767                         else {
768                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
769                                 errorf(tmp);
770                         }
771                         break;
772                 case IAX_IE_MSGCOUNT:
773                         if (len != (int)sizeof(unsigned short)) {
774                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
775                                 errorf(tmp);
776                         } else
777                                 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));  
778                         break;
779                 case IAX_IE_AUTOANSWER:
780                         ies->autoanswer = 1;
781                         break;
782                 case IAX_IE_MUSICONHOLD:
783                         ies->musiconhold = 1;
784                         break;
785                 case IAX_IE_TRANSFERID:
786                         if (len != (int)sizeof(unsigned int)) {
787                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
788                                 errorf(tmp);
789                         } else
790                                 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
791                         break;
792                 case IAX_IE_DATETIME:
793                         if (len != (int)sizeof(unsigned int)) {
794                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
795                                 errorf(tmp);
796                         } else
797                                 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
798                         break;
799                 case IAX_IE_FIRMWAREVER:
800                         if (len != (int)sizeof(unsigned short)) {
801                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
802                                 errorf(tmp);
803                         } else
804                                 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));       
805                         break;
806                 case IAX_IE_DEVICETYPE:
807                         ies->devicetype = (char *)data + 2;
808                         break;
809                 case IAX_IE_SERVICEIDENT:
810                         ies->serviceident = (char *)data + 2;
811                         break;
812                 case IAX_IE_FWBLOCKDESC:
813                         if (len != (int)sizeof(unsigned int)) {
814                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
815                                 errorf(tmp);
816                         } else
817                                 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
818                         break;
819                 case IAX_IE_FWBLOCKDATA:
820                         ies->fwdata = data + 2;
821                         ies->fwdatalen = len;
822                         break;
823                 case IAX_IE_ENCKEY:
824                         ies->enckey = data + 2;
825                         ies->enckeylen = len;
826                         break;
827                 case IAX_IE_PROVVER:
828                         if (len != (int)sizeof(unsigned int)) {
829                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
830                                 errorf(tmp);
831                         } else {
832                                 ies->provverpres = 1;
833                                 ies->provver = ntohl(get_unaligned_uint32(data + 2));
834                         }
835                         break;
836                 case IAX_IE_CALLINGPRES:
837                         if (len == 1)
838                                 ies->calling_pres = data[2];
839                         else {
840                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
841                                 errorf(tmp);
842                         }
843                         break;
844                 case IAX_IE_CALLINGTON:
845                         if (len == 1)
846                                 ies->calling_ton = data[2];
847                         else {
848                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
849                                 errorf(tmp);
850                         }
851                         break;
852                 case IAX_IE_CALLINGTNS:
853                         if (len != (int)sizeof(unsigned short)) {
854                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
855                                 errorf(tmp);
856                         } else
857                                 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));       
858                         break;
859                case IAX_IE_RR_JITTER:
860                        if (len != (int)sizeof(unsigned int)) {
861                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
862                                errorf(tmp);
863                        } else {
864                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
865                        }
866                        break;
867                case IAX_IE_RR_LOSS:
868                        if (len != (int)sizeof(unsigned int)) {
869                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
870                                errorf(tmp);
871                        } else {
872                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
873                        }
874                        break;
875                case IAX_IE_RR_PKTS:
876                        if (len != (int)sizeof(unsigned int)) {
877                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
878                                errorf(tmp);
879                        } else {
880                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
881                        }
882                        break;
883                case IAX_IE_RR_DELAY:
884                        if (len != (int)sizeof(unsigned short)) {
885                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
886                         errorf(tmp);
887                        } else {
888                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
889                        }
890                        break;
891                 case IAX_IE_RR_DROPPED:
892                         if (len != (int)sizeof(unsigned int)) {
893                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
894                                 errorf(tmp);
895                         } else {
896                                 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
897                         }
898                         break;
899                 case IAX_IE_RR_OOO:
900                         if (len != (int)sizeof(unsigned int)) {
901                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
902                                 errorf(tmp);
903                         } else {
904                                 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
905                         }
906                         break;
907                 case IAX_IE_VARIABLE:
908                         ast_copy_string(tmp, (char *)data + 2, len + 1);
909                         tmp2 = strchr(tmp, '=');
910                         if (tmp2)
911                                 *tmp2++ = '\0';
912                         else
913                                 tmp2 = "";
914                         /* Existing variable or new variable? */
915                         for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
916                                 if (strcmp(tmp, var2->name) == 0) {
917                                         int len = strlen(var2->value) + strlen(tmp2) + 1;
918                                         char *tmp3 = alloca(len);
919                                         snprintf(tmp3, len, "%s%s", var2->value, tmp2);
920                                         var = ast_variable_new(tmp, tmp3);
921                                         var->next = var2->next;
922                                         if (prev)
923                                                 prev->next = var;
924                                         else
925                                                 ies->vars = var;
926                                         ast_free(var2);
927                                         break;
928                                 }
929                         }
930                         if (!var2) {
931                                 var = ast_variable_new(tmp, tmp2);
932                                 var->next = ies->vars;
933                                 ies->vars = var;
934                         }
935                         break;
936                 case IAX_IE_OSPTOKEN:
937                         if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
938                                 ies->osptokenblock[count] = (char *)data + 2 + 1;
939                                 ies->ospblocklength[count] = len - 1;
940                         } else {
941                                 snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
942                                 errorf(tmp);
943                         }
944                         break;
945                 default:
946                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
947                         outputf(tmp);
948                 }
949                 /* Overwrite information element with 0, to null terminate previous portion */
950                 data[0] = 0;
951                 datalen -= (len + 2);
952                 data += (len + 2);
953         }
954         /* Null-terminate last field */
955         *data = '\0';
956         if (datalen) {
957                 errorf("Invalid information element contents, strange boundary\n");
958                 return -1;
959         }
960         return 0;
961 }
962
963 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
964 {
965         fr->af.frametype = f->frametype;
966         fr->af.subclass = f->subclass;
967         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
968         fr->af.datalen = f->datalen;
969         fr->af.samples = f->samples;
970         fr->af.offset = AST_FRIENDLY_OFFSET;
971         fr->af.src = f->src;
972         fr->af.delivery.tv_sec = 0;
973         fr->af.delivery.tv_usec = 0;
974         fr->af.data = fr->afdata;
975         fr->af.len = f->len;
976         if (fr->af.datalen) {
977                 size_t copy_len = fr->af.datalen;
978                 if (copy_len > fr->afdatalen) {
979                         ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
980                                 (int) fr->afdatalen, (int) fr->af.datalen);
981                         copy_len = fr->afdatalen;
982                 }
983 #if __BYTE_ORDER == __LITTLE_ENDIAN
984                 /* We need to byte-swap slinear samples from network byte order */
985                 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
986                         /* 2 bytes / sample for SLINEAR */
987                         ast_swapcopy_samples(fr->af.data, f->data, copy_len / 2);
988                 } else
989 #endif
990                         memcpy(fr->af.data, f->data, copy_len);
991         }
992 }
993
994 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
995 {
996         struct iax_frame *fr = NULL;
997
998 #if !defined(LOW_MEMORY)
999         struct iax_frames *iax_frames;
1000
1001         /* Attempt to get a frame from this thread's cache */
1002         if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1003                 AST_LIST_TRAVERSE_SAFE_BEGIN(iax_frames, fr, list) {
1004                         if (fr->afdatalen >= datalen) {
1005                                 size_t afdatalen = fr->afdatalen;
1006                                 AST_LIST_REMOVE_CURRENT(iax_frames, list);
1007                                 memset(fr, 0, sizeof(*fr));
1008                                 fr->afdatalen = afdatalen;
1009                                 break;
1010                         }
1011                 }
1012                 AST_LIST_TRAVERSE_SAFE_END
1013         }
1014         if (!fr) {
1015                 if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
1016                         return NULL;
1017                 fr->afdatalen = datalen;
1018         }
1019 #else
1020         if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
1021                 return NULL;
1022         fr->afdatalen = datalen;
1023 #endif
1024
1025
1026         fr->direction = direction;
1027         fr->retrans = -1;
1028         fr->cacheable = cacheable;
1029         
1030         if (fr->direction == DIRECTION_INGRESS)
1031                 ast_atomic_fetchadd_int(&iframes, 1);
1032         else
1033                 ast_atomic_fetchadd_int(&oframes, 1);
1034         
1035         ast_atomic_fetchadd_int(&frames, 1);
1036
1037         return fr;
1038 }
1039
1040 void iax_frame_free(struct iax_frame *fr)
1041 {
1042 #if !defined(LOW_MEMORY)
1043         struct iax_frames *iax_frames;
1044 #endif
1045
1046         /* Note: does not remove from scheduler! */
1047         if (fr->direction == DIRECTION_INGRESS)
1048                 ast_atomic_fetchadd_int(&iframes, -1);
1049         else if (fr->direction == DIRECTION_OUTGRESS)
1050                 ast_atomic_fetchadd_int(&oframes, -1);
1051         else {
1052                 errorf("Attempt to double free frame detected\n");
1053                 return;
1054         }
1055         ast_atomic_fetchadd_int(&frames, -1);
1056
1057 #if !defined(LOW_MEMORY)
1058         if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1059                 ast_free(fr);
1060                 return;
1061         }
1062
1063         fr->direction = 0;
1064         AST_LIST_INSERT_HEAD(iax_frames, fr, list);
1065 #else
1066         ast_free(fr);
1067 #endif
1068 }
1069
1070 #if !defined(LOW_MEMORY)
1071 static void frame_cache_cleanup(void *data)
1072 {
1073         struct iax_frames *frames = data;
1074         struct iax_frame *cur;
1075
1076         while ((cur = AST_LIST_REMOVE_HEAD(frames, list)))
1077                 ast_free(cur);
1078
1079         ast_free(frames);
1080 }
1081 #endif
1082
1083 int iax_get_frames(void) { return frames; }
1084 int iax_get_iframes(void) { return iframes; }
1085 int iax_get_oframes(void) { return oframes; }