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