Add commonly used include headers
[asterisk/asterisk.git] / channels / iax2-parser.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of Inter-Asterisk eXchange
5  * 
6  * Copyright (C) 2003, Digium
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <string.h>
17 #include <netinet/in.h>
18 #include <asterisk/frame.h>
19 #include <arpa/inet.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "iax2.h"
24 #include "iax2-parser.h"
25
26
27 static int frames = 0;
28 static int iframes = 0;
29 static int oframes = 0;
30
31 static void internaloutput(const char *str)
32 {
33         printf(str);
34 }
35
36 static void internalerror(const char *str)
37 {
38         fprintf(stderr, "WARNING: %s", str);
39 }
40
41 static void (*outputf)(const char *str) = internaloutput;
42 static void (*errorf)(const char *str) = internalerror;
43
44 static void dump_addr(char *output, int maxlen, void *value, int len)
45 {
46         struct sockaddr_in sin;
47         if (len == sizeof(sin)) {
48                 memcpy(&sin, value, len);
49                 snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
50         } else {
51                 snprintf(output, maxlen, "Invalid Address");
52         }
53 }
54
55 static void dump_string(char *output, int maxlen, void *value, int len)
56 {
57         maxlen--;
58         if (maxlen > len)
59                 maxlen = len;
60         strncpy(output,value, maxlen);
61         output[maxlen] = '\0';
62 }
63
64 static void dump_int(char *output, int maxlen, void *value, int len)
65 {
66         if (len == sizeof(unsigned int))
67                 snprintf(output, maxlen, "%d", ntohl(*((unsigned int *)value)));
68         else
69                 snprintf(output, maxlen, "Invalid INT");
70 }
71
72 static void dump_short(char *output, int maxlen, void *value, int len)
73 {
74         if (len == sizeof(unsigned short))
75                 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
76         else
77                 snprintf(output, maxlen, "Invalid SHORT");
78 }
79
80 static void dump_byte(char *output, int maxlen, void *value, int len)
81 {
82         if (len == sizeof(unsigned char))
83                 snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
84         else
85                 snprintf(output, maxlen, "Invalid BYTE");
86 }
87
88 static struct iax2_ie {
89         int ie;
90         char *name;
91         void (*dump)(char *output, int maxlen, void *value, int len);
92 } ies[] = {
93         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
94         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
95         { IAX_IE_CALLING_NUMBER, "ANI", dump_string },
96         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
97         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
98         { IAX_IE_USERNAME, "USERNAME", dump_string },
99         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
100         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
101         { IAX_IE_FORMAT, "FORMAT", dump_int },
102         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
103         { IAX_IE_VERSION, "VERSION", dump_short },
104         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
105         { IAX_IE_DNID, "DNID", dump_string },
106         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
107         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
108         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
109         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
110         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
111         { IAX_IE_REFRESH, "REFRESH", dump_short },
112         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
113         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
114         { IAX_IE_CAUSE, "CAUSE", dump_string },
115         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
116         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
117         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
118         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
119 };
120
121 const char *iax_ie2str(int ie)
122 {
123         int x;
124         for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
125                 if (ies[x].ie == ie)
126                         return ies[x].name;
127         }
128         return "Unknown IE";
129 }
130
131 static void dump_ies(unsigned char *iedata, int len)
132 {
133         int ielen;
134         int ie;
135         int x;
136         int found;
137         char interp[80];
138         char tmp[256];
139         if (len < 2)
140                 return;
141         while(len > 2) {
142                 ie = iedata[0];
143                 ielen = iedata[1];
144                 if (ielen + 2> len) {
145                         snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
146                         outputf(tmp);
147                         return;
148                 }
149                 found = 0;
150                 for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
151                         if (ies[x].ie == ie) {
152                                 if (ies[x].dump) {
153                                         ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
154                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
155                                         outputf(tmp);
156                                 } else {
157                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : Present\n", ies[x].name);
158                                         outputf(tmp);
159                                 }
160                                 found++;
161                         }
162                 }
163                 if (!found) {
164                         snprintf(tmp, sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
165                         outputf(tmp);
166                 }
167                 iedata += (2 + ielen);
168                 len -= (2 + ielen);
169         }
170         outputf("\n");
171 }
172
173 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
174 {
175         char *frames[] = {
176                 "(0?)",
177                 "DTMF   ",
178                 "VOICE  ",
179                 "VIDEO  ",
180                 "CONTROL",
181                 "NULL   ",
182                 "IAX    ",
183                 "TEXT   ",
184                 "IMAGE  " };
185         char *iaxs[] = {
186                 "(0?)",
187                 "NEW    ",
188                 "PING   ",
189                 "PONG   ",
190                 "ACK    ",
191                 "HANGUP ",
192                 "REJECT ",
193                 "ACCEPT ",
194                 "AUTHREQ",
195                 "AUTHREP",
196                 "INVAL  ",
197                 "LAGRQ  ",
198                 "LAGRP  ",
199                 "REGREQ ",
200                 "REGAUTH",
201                 "REGACK ",
202                 "REGREJ ",
203                 "REGREL ",
204                 "VNAK   ",
205                 "DPREQ  ",
206                 "DPREP  ",
207                 "DIAL   ",
208                 "TXREQ  ",
209                 "TXCNT  ",
210                 "TXACC  ",
211                 "TXREADY",
212                 "TXREL  ",
213                 "TXREJ  ",
214                 "QUELCH ",
215                 "UNQULCH",
216                 "POKE",
217                 "PAGE",
218                 "MWI",
219                 "UNSUPPORTED",
220         };
221         char *cmds[] = {
222                 "(0?)",
223                 "HANGUP ",
224                 "RING   ",
225                 "RINGING",
226                 "ANSWER ",
227                 "BUSY   ",
228                 "TKOFFHK ",
229                 "OFFHOOK" };
230         struct ast_iax2_full_hdr *fh;
231         char retries[20];
232         char class2[20];
233         char subclass2[20];
234         char *class;
235         char *subclass;
236         char tmp[256];
237         if (f) {
238                 fh = f->data;
239                 snprintf(retries, sizeof(retries), "%03d", f->retries);
240         } else {
241                 fh = fhi;
242                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
243                         strcpy(retries, "Yes");
244                 else
245                         strcpy(retries, "No");
246         }
247         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
248                 /* Don't mess with mini-frames */
249                 return;
250         }
251         if (fh->type > sizeof(frames)/sizeof(char *)) {
252                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
253                 class = class2;
254         } else {
255                 class = frames[(int)fh->type];
256         }
257         if (fh->type == AST_FRAME_DTMF) {
258                 sprintf(subclass2, "%c", fh->csub);
259                 subclass = subclass2;
260         } else if (fh->type == AST_FRAME_IAX) {
261                 if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
262                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
263                         subclass = subclass2;
264                 } else {
265                         subclass = iaxs[(int)fh->csub];
266                 }
267         } else if (fh->type == AST_FRAME_CONTROL) {
268                 if (fh->csub > sizeof(cmds)/sizeof(char *)) {
269                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
270                         subclass = subclass2;
271                 } else {
272                         subclass = cmds[(int)fh->csub];
273                 }
274         } else {
275                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
276                 subclass = subclass2;
277         }
278 snprintf(tmp, sizeof(tmp), 
279 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
280         (rx ? "Rx" : "Tx"),
281         retries, fh->oseqno, fh->iseqno, class, subclass);
282         outputf(tmp);
283 snprintf(tmp, sizeof(tmp), 
284 "   Timestamp: %05dms  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
285         ntohl(fh->ts),
286         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
287                 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
288         outputf(tmp);
289         if (fh->type == AST_FRAME_IAX)
290                 dump_ies(fh->iedata, datalen);
291 }
292
293 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
294 {
295         char tmp[256];
296         if (datalen > (sizeof(ied->buf) - ied->pos)) {
297                 snprintf(tmp, sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, sizeof(ied->buf) - ied->pos);
298                 errorf(tmp);
299                 return -1;
300         }
301         ied->buf[ied->pos++] = ie;
302         ied->buf[ied->pos++] = datalen;
303         memcpy(ied->buf + ied->pos, data, datalen);
304         ied->pos += datalen;
305         return 0;
306 }
307
308 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
309 {
310         return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
311 }
312
313 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
314 {
315         unsigned int newval;
316         newval = htonl(value);
317         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
318 }
319
320 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
321 {
322         unsigned short newval;
323         newval = htons(value);
324         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
325 }
326
327 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
328 {
329         return iax_ie_append_raw(ied, ie, str, strlen(str));
330 }
331
332 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
333 {
334         return iax_ie_append_raw(ied, ie, &dat, 1);
335 }
336
337 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
338 {
339         return iax_ie_append_raw(ied, ie, NULL, 0);
340 }
341
342 void iax_set_output(void (*func)(const char *))
343 {
344         outputf = func;
345 }
346
347 void iax_set_error(void (*func)(const char *))
348 {
349         errorf = func;
350 }
351
352 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
353 {
354         /* Parse data into information elements */
355         int len;
356         int ie;
357         char tmp[256];
358         memset(ies, 0, sizeof(struct iax_ies));
359         ies->msgcount = -1;
360         while(datalen >= 2) {
361                 ie = data[0];
362                 len = data[1];
363                 if (len > datalen - 2) {
364                         errorf("Information element length exceeds message size\n");
365                         return -1;
366                 }
367                 switch(ie) {
368                 case IAX_IE_CALLED_NUMBER:
369                         ies->called_number = data + 2;
370                         break;
371                 case IAX_IE_CALLING_NUMBER:
372                         ies->calling_number = data + 2;
373                         break;
374                 case IAX_IE_CALLING_ANI:
375                         ies->calling_ani = data + 2;
376                         break;
377                 case IAX_IE_CALLING_NAME:
378                         ies->calling_name = data + 2;
379                         break;
380                 case IAX_IE_CALLED_CONTEXT:
381                         ies->called_context = data + 2;
382                         break;
383                 case IAX_IE_USERNAME:
384                         ies->username = data + 2;
385                         break;
386                 case IAX_IE_PASSWORD:
387                         ies->password = data + 2;
388                         break;
389                 case IAX_IE_CAPABILITY:
390                         if (len != sizeof(unsigned int)) {
391                                 snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
392                                 errorf(tmp);
393                         } else
394                                 ies->capability = ntohl(*((unsigned int *)(data + 2)));
395                         break;
396                 case IAX_IE_FORMAT:
397                         if (len != sizeof(unsigned int)) {
398                                 snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
399                                 errorf(tmp);
400                         } else
401                                 ies->format = ntohl(*((unsigned int *)(data + 2)));
402                         break;
403                 case IAX_IE_LANGUAGE:
404                         ies->language = data + 2;
405                         break;
406                 case IAX_IE_VERSION:
407                         if (len != sizeof(unsigned short)) {
408                                 snprintf(tmp, sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
409                                 errorf(tmp);
410                         } else
411                                 ies->version = ntohs(*((unsigned short *)(data + 2)));
412                         break;
413                 case IAX_IE_ADSICPE:
414                         if (len != sizeof(unsigned short)) {
415                                 snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
416                                 errorf(tmp);
417                         } else
418                                 ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
419                         break;
420                 case IAX_IE_DNID:
421                         ies->dnid = data + 2;
422                         break;
423                 case IAX_IE_AUTHMETHODS:
424                         if (len != sizeof(unsigned short))  {
425                                 snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
426                                 errorf(tmp);
427                         } else
428                                 ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
429                         break;
430                 case IAX_IE_CHALLENGE:
431                         ies->challenge = data + 2;
432                         break;
433                 case IAX_IE_MD5_RESULT:
434                         ies->md5_result = data + 2;
435                         break;
436                 case IAX_IE_RSA_RESULT:
437                         ies->rsa_result = data + 2;
438                         break;
439                 case IAX_IE_APPARENT_ADDR:
440                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
441                         break;
442                 case IAX_IE_REFRESH:
443                         if (len != sizeof(unsigned short)) {
444                                 snprintf(tmp, sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
445                                 errorf(tmp);
446                         } else
447                                 ies->refresh = ntohs(*((unsigned short *)(data + 2)));
448                         break;
449                 case IAX_IE_DPSTATUS:
450                         if (len != sizeof(unsigned short)) {
451                                 snprintf(tmp, sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
452                                 errorf(tmp);
453                         } else
454                                 ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
455                         break;
456                 case IAX_IE_CALLNO:
457                         if (len != sizeof(unsigned short)) {
458                                 snprintf(tmp, sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
459                                 errorf(tmp);
460                         } else
461                                 ies->callno = ntohs(*((unsigned short *)(data + 2)));
462                         break;
463                 case IAX_IE_CAUSE:
464                         ies->cause = data + 2;
465                         break;
466                 case IAX_IE_IAX_UNKNOWN:
467                         if (len == 1)
468                                 ies->iax_unknown = data[2];
469                         else {
470                                 snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
471                                 errorf(tmp);
472                         }
473                         break;
474                 case IAX_IE_MSGCOUNT:
475                         if (len != sizeof(unsigned short)) {
476                                 snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
477                                 errorf(tmp);
478                         } else
479                                 ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
480                         break;
481                 case IAX_IE_AUTOANSWER:
482                         ies->autoanswer = 1;
483                         break;
484                 case IAX_IE_MUSICONHOLD:
485                         ies->musiconhold = 1;
486                         break;
487                 case IAX_IE_TRANSFERID:
488                         if (len != sizeof(unsigned int)) {
489                                 snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
490                                 errorf(tmp);
491                         } else
492                                 ies->transferid = ntohl(*((unsigned int *)(data + 2)));
493                         break;
494                 default:
495                         snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
496                         errorf(tmp);
497                 }
498                 /* Overwrite information element with 0, to null terminate previous portion */
499                 data[0] = 0;
500                 datalen -= (len + 2);
501                 data += (len + 2);
502         }
503         /* Null-terminate last field */
504         *data = '\0';
505         if (datalen) {
506                 errorf("Invalid information element contents, strange boundary\n");
507                 return -1;
508         }
509         return 0;
510 }
511
512 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
513 {
514         fr->af.frametype = f->frametype;
515         fr->af.subclass = f->subclass;
516         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
517         fr->af.datalen = f->datalen;
518         fr->af.samples = f->samples;
519         fr->af.offset = AST_FRIENDLY_OFFSET;
520         fr->af.src = f->src;
521         fr->af.data = fr->afdata;
522         if (fr->af.datalen) 
523                 memcpy(fr->af.data, f->data, fr->af.datalen);
524 }
525
526 struct iax_frame *iax_frame_new(int direction, int datalen)
527 {
528         struct iax_frame *fr;
529         fr = malloc(sizeof(struct iax_frame) + datalen);
530         if (fr) {
531                 fr->direction = direction;
532                 fr->retrans = -1;
533                 frames++;
534                 if (fr->direction == DIRECTION_INGRESS)
535                         iframes++;
536                 else
537                         oframes++;
538         }
539         return fr;
540 }
541
542 void iax_frame_free(struct iax_frame *fr)
543 {
544         /* Note: does not remove from scheduler! */
545         if (fr->direction == DIRECTION_INGRESS)
546                 iframes--;
547         else if (fr->direction == DIRECTION_OUTGRESS)
548                 oframes--;
549         else {
550                 errorf("Attempt to double free frame detected\n");
551                 return;
552         }
553         fr->direction = 0;
554         free(fr);
555         frames--;
556 }
557
558 int iax_get_frames(void) { return frames; }
559 int iax_get_iframes(void) { return iframes; }
560 int iax_get_oframes(void) { return oframes; }