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