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