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