dom mar 16 23:37:23 CET 2003
[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 void internaloutput(const char *str)
27 {
28         printf(str);
29 }
30
31 static void internalerror(const char *str)
32 {
33         fprintf(stderr, "WARNING: %s", str);
34 }
35
36 static void (*outputf)(const char *str) = internaloutput;
37 static void (*errorf)(const char *str) = internalerror;
38
39 static void dump_addr(char *output, int maxlen, void *value, int len)
40 {
41         struct sockaddr_in sin;
42         if (len == sizeof(sin)) {
43                 memcpy(&sin, value, len);
44                 snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
45         } else {
46                 snprintf(output, maxlen, "Invalid Address");
47         }
48 }
49
50 static void dump_string(char *output, int maxlen, void *value, int len)
51 {
52         maxlen--;
53         if (maxlen > len)
54                 maxlen = len;
55         strncpy(output,value, maxlen);
56         output[maxlen] = '\0';
57 }
58
59 static void dump_int(char *output, int maxlen, void *value, int len)
60 {
61         if (len == sizeof(unsigned int))
62                 snprintf(output, maxlen, "%d", ntohl(*((unsigned int *)value)));
63         else
64                 snprintf(output, maxlen, "Invalid INT");
65 }
66
67 static void dump_short(char *output, int maxlen, void *value, int len)
68 {
69         if (len == sizeof(unsigned short))
70                 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
71         else
72                 snprintf(output, maxlen, "Invalid SHORT");
73 }
74
75 static void dump_byte(char *output, int maxlen, void *value, int len)
76 {
77         if (len == sizeof(unsigned char))
78                 snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
79         else
80                 snprintf(output, maxlen, "Invalid BYTE");
81 }
82
83 static struct iax2_ie {
84         int ie;
85         char *name;
86         void (*dump)(char *output, int maxlen, void *value, int len);
87 } ies[] = {
88         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
89         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
90         { IAX_IE_CALLING_NUMBER, "ANI", dump_string },
91         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
92         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
93         { IAX_IE_USERNAME, "USERNAME", dump_string },
94         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
95         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
96         { IAX_IE_FORMAT, "FORMAT", dump_int },
97         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
98         { IAX_IE_VERSION, "VERSION", dump_short },
99         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
100         { IAX_IE_DNID, "DNID", dump_string },
101         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
102         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
103         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
104         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
105         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
106         { IAX_IE_REFRESH, "REFRESH", dump_short },
107         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
108         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
109         { IAX_IE_CAUSE, "CAUSE", dump_string },
110         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
111         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
112         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
113 };
114
115 const char *iax_ie2str(int ie)
116 {
117         int x;
118         for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
119                 if (ies[x].ie == ie)
120                         return ies[x].name;
121         }
122         return "Unknown IE";
123 }
124
125 static void dump_ies(unsigned char *iedata, int len)
126 {
127         int ielen;
128         int ie;
129         int x;
130         int found;
131         char interp[80];
132         char tmp[256];
133         if (len < 2)
134                 return;
135         while(len > 2) {
136                 ie = iedata[0];
137                 ielen = iedata[1];
138                 if (ielen + 2> len) {
139                         snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
140                         outputf(tmp);
141                         return;
142                 }
143                 found = 0;
144                 for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
145                         if (ies[x].ie == ie) {
146                                 if (ies[x].dump) {
147                                         ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
148                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
149                                         outputf(tmp);
150                                 } else {
151                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : Present\n", ies[x].name);
152                                         outputf(tmp);
153                                 }
154                                 found++;
155                         }
156                 }
157                 if (!found) {
158                         snprintf(tmp, sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
159                         outputf(tmp);
160                 }
161                 iedata += (2 + ielen);
162                 len -= (2 + ielen);
163         }
164         outputf("\n");
165 }
166
167 void iax_showframe(struct ast_iax2_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
168 {
169         char *frames[] = {
170                 "(0?)",
171                 "DTMF   ",
172                 "VOICE  ",
173                 "VIDEO  ",
174                 "CONTROL",
175                 "NULL   ",
176                 "IAX    ",
177                 "TEXT   ",
178                 "IMAGE  " };
179         char *iaxs[] = {
180                 "(0?)",
181                 "NEW    ",
182                 "PING   ",
183                 "PONG   ",
184                 "ACK    ",
185                 "HANGUP ",
186                 "REJECT ",
187                 "ACCEPT ",
188                 "AUTHREQ",
189                 "AUTHREP",
190                 "INVAL  ",
191                 "LAGRQ  ",
192                 "LAGRP  ",
193                 "REGREQ ",
194                 "REGAUTH",
195                 "REGACK ",
196                 "REGREJ ",
197                 "REGREL ",
198                 "VNAK   ",
199                 "DPREQ  ",
200                 "DPREP  ",
201                 "DIAL   ",
202                 "TXREQ  ",
203                 "TXCNT  ",
204                 "TXACC  ",
205                 "TXREADY",
206                 "TXREL  ",
207                 "TXREJ  ",
208                 "QUELCH ",
209                 "UNQULCH",
210                 "POKE",
211                 "PAGE",
212                 "MWI",
213                 "UNSUPPORTED",
214         };
215         char *cmds[] = {
216                 "(0?)",
217                 "HANGUP ",
218                 "RING   ",
219                 "RINGING",
220                 "ANSWER ",
221                 "BUSY   ",
222                 "TKOFFHK ",
223                 "OFFHOOK" };
224         struct ast_iax2_full_hdr *fh;
225         char retries[20];
226         char class2[20];
227         char subclass2[20];
228         char *class;
229         char *subclass;
230         char tmp[256];
231         if (f) {
232                 fh = f->data;
233                 snprintf(retries, sizeof(retries), "%03d", f->retries);
234         } else {
235                 fh = fhi;
236                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
237                         strcpy(retries, "Yes");
238                 else
239                         strcpy(retries, "No");
240         }
241         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
242                 /* Don't mess with mini-frames */
243                 return;
244         }
245         if (fh->type > sizeof(frames)/sizeof(char *)) {
246                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
247                 class = class2;
248         } else {
249                 class = frames[(int)fh->type];
250         }
251         if (fh->type == AST_FRAME_DTMF) {
252                 sprintf(subclass2, "%c", fh->csub);
253                 subclass = subclass2;
254         } else if (fh->type == AST_FRAME_IAX) {
255                 if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
256                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
257                         subclass = subclass2;
258                 } else {
259                         subclass = iaxs[(int)fh->csub];
260                 }
261         } else if (fh->type == AST_FRAME_CONTROL) {
262                 if (fh->csub > sizeof(cmds)/sizeof(char *)) {
263                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
264                         subclass = subclass2;
265                 } else {
266                         subclass = cmds[(int)fh->csub];
267                 }
268         } else {
269                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
270                 subclass = subclass2;
271         }
272 snprintf(tmp, sizeof(tmp), 
273 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
274         (rx ? "Rx" : "Tx"),
275         retries, fh->oseqno, fh->iseqno, class, subclass);
276         outputf(tmp);
277 snprintf(tmp, sizeof(tmp), 
278 "   Timestamp: %05dms  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
279         ntohl(fh->ts),
280         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
281                 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
282         outputf(tmp);
283         if (fh->type == AST_FRAME_IAX)
284                 dump_ies(fh->iedata, datalen);
285 }
286
287 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
288 {
289         char tmp[256];
290         if (datalen > (sizeof(ied->buf) - ied->pos)) {
291                 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);
292                 errorf(tmp);
293                 return -1;
294         }
295         ied->buf[ied->pos++] = ie;
296         ied->buf[ied->pos++] = datalen;
297         memcpy(ied->buf + ied->pos, data, datalen);
298         ied->pos += datalen;
299         return 0;
300 }
301
302 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
303 {
304         return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
305 }
306
307 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
308 {
309         unsigned int newval;
310         newval = htonl(value);
311         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
312 }
313
314 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
315 {
316         unsigned short newval;
317         newval = htons(value);
318         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
319 }
320
321 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
322 {
323         return iax_ie_append_raw(ied, ie, str, strlen(str));
324 }
325
326 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
327 {
328         return iax_ie_append_raw(ied, ie, &dat, 1);
329 }
330
331 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
332 {
333         return iax_ie_append_raw(ied, ie, NULL, 0);
334 }
335
336 void iax_set_output(void (*func)(const char *))
337 {
338         outputf = func;
339 }
340
341 void iax_set_error(void (*func)(const char *))
342 {
343         errorf = func;
344 }