Sat Mar 24 23:26:05 2007

Asterisk developer's documentation


iax2-parser.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Implementation of Inter-Asterisk eXchange Protocol, v 2
00022  * 
00023  */
00024 
00025 #include <sys/types.h>
00026 #include <sys/socket.h>
00027 #include <string.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <unistd.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00037 
00038 #include "asterisk/frame.h"
00039 #include "asterisk/utils.h"
00040 #include "asterisk/unaligned.h"
00041 #include "iax2.h"
00042 #include "iax2-parser.h"
00043 #include "iax2-provision.h"
00044 
00045 static int frames = 0;
00046 static int iframes = 0;
00047 static int oframes = 0;
00048 
00049 static void internaloutput(const char *str)
00050 {
00051    fputs(str, stdout);
00052 }
00053 
00054 static void internalerror(const char *str)
00055 {
00056    fprintf(stderr, "WARNING: %s", str);
00057 }
00058 
00059 static void (*outputf)(const char *str) = internaloutput;
00060 static void (*errorf)(const char *str) = internalerror;
00061 
00062 static void dump_addr(char *output, int maxlen, void *value, int len)
00063 {
00064    struct sockaddr_in sin;
00065    char iabuf[INET_ADDRSTRLEN];
00066    if (len == (int)sizeof(sin)) {
00067       memcpy(&sin, value, len);
00068       snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
00069    } else {
00070       snprintf(output, maxlen, "Invalid Address");
00071    }
00072 }
00073 
00074 static void dump_string(char *output, int maxlen, void *value, int len)
00075 {
00076    maxlen--;
00077    if (maxlen > len)
00078       maxlen = len;
00079    strncpy(output, value, maxlen);
00080    output[maxlen] = '\0';
00081 }
00082 
00083 static void dump_prefs(char *output, int maxlen, void *value, int len)
00084 {
00085    struct ast_codec_pref pref;
00086    int total_len = 0;
00087 
00088    maxlen--;
00089    total_len = maxlen;
00090 
00091    if (maxlen > len)
00092       maxlen = len;
00093 
00094    strncpy(output, value, maxlen);
00095    output[maxlen] = '\0';
00096    
00097    ast_codec_pref_convert(&pref, output, total_len, 0);
00098    memset(output,0,total_len);
00099    ast_codec_pref_string(&pref, output, total_len);
00100 }
00101 
00102 static void dump_int(char *output, int maxlen, void *value, int len)
00103 {
00104    if (len == (int)sizeof(unsigned int))
00105       snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
00106    else
00107       ast_copy_string(output, "Invalid INT", maxlen); 
00108 }
00109 
00110 static void dump_short(char *output, int maxlen, void *value, int len)
00111 {
00112    if (len == (int)sizeof(unsigned short))
00113       snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
00114    else
00115       ast_copy_string(output, "Invalid SHORT", maxlen);
00116 }
00117 
00118 static void dump_byte(char *output, int maxlen, void *value, int len)
00119 {
00120    if (len == (int)sizeof(unsigned char))
00121       snprintf(output, maxlen, "%d", *((unsigned char *)value));
00122    else
00123       ast_copy_string(output, "Invalid BYTE", maxlen);
00124 }
00125 
00126 static void dump_datetime(char *output, int maxlen, void *value, int len)
00127 {
00128    struct tm tm;
00129    unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
00130    if (len == (int)sizeof(unsigned int)) {
00131       tm.tm_sec  = (val & 0x1f) << 1;
00132       tm.tm_min  = (val >> 5) & 0x3f;
00133       tm.tm_hour = (val >> 11) & 0x1f;
00134       tm.tm_mday = (val >> 16) & 0x1f;
00135       tm.tm_mon  = ((val >> 21) & 0x0f) - 1;
00136       tm.tm_year = ((val >> 25) & 0x7f) + 100;
00137       strftime(output, maxlen, "%Y-%m-%d  %T", &tm); 
00138    } else
00139       ast_copy_string(output, "Invalid DATETIME format!", maxlen);
00140 }
00141 
00142 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
00143 {
00144    struct sockaddr_in sin;
00145    char iabuf[INET_ADDRSTRLEN];
00146    if (len == (int)sizeof(unsigned int)) {
00147       memcpy(&sin.sin_addr, value, len);
00148       ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr);
00149       snprintf(output, maxlen, "%s", iabuf);
00150    } else
00151       ast_copy_string(output, "Invalid IPADDR", maxlen);
00152 }
00153 
00154 
00155 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
00156 {
00157    char buf[256] = "";
00158    if (len == (int)sizeof(unsigned int))
00159       snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
00160          iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
00161    else
00162       ast_copy_string(output, "Invalid INT", maxlen);
00163 }
00164 
00165 static void dump_samprate(char *output, int maxlen, void *value, int len)
00166 {
00167    char tmp[256]="";
00168    int sr;
00169    if (len == (int)sizeof(unsigned short)) {
00170       sr = ntohs(*((unsigned short *)value));
00171       if (sr & IAX_RATE_8KHZ)
00172          strcat(tmp, ",8khz");
00173       if (sr & IAX_RATE_11KHZ)
00174          strcat(tmp, ",11.025khz");
00175       if (sr & IAX_RATE_16KHZ)
00176          strcat(tmp, ",16khz");
00177       if (sr & IAX_RATE_22KHZ)
00178          strcat(tmp, ",22.05khz");
00179       if (sr & IAX_RATE_44KHZ)
00180          strcat(tmp, ",44.1khz");
00181       if (sr & IAX_RATE_48KHZ)
00182          strcat(tmp, ",48khz");
00183       if (strlen(tmp))
00184          ast_copy_string(output, &tmp[1], maxlen);
00185       else
00186          ast_copy_string(output, "None Specified!\n", maxlen);
00187    } else
00188       ast_copy_string(output, "Invalid SHORT", maxlen);
00189 
00190 }
00191 
00192 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
00193 static void dump_prov(char *output, int maxlen, void *value, int len)
00194 {
00195    dump_prov_ies(output, maxlen, value, len);
00196 }
00197 
00198 static struct iax2_ie {
00199    int ie;
00200    char *name;
00201    void (*dump)(char *output, int maxlen, void *value, int len);
00202 } ies[] = {
00203    { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
00204    { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
00205    { IAX_IE_CALLING_ANI, "ANI", dump_string },
00206    { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
00207    { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
00208    { IAX_IE_USERNAME, "USERNAME", dump_string },
00209    { IAX_IE_PASSWORD, "PASSWORD", dump_string },
00210    { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
00211    { IAX_IE_FORMAT, "FORMAT", dump_int },
00212    { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
00213    { IAX_IE_VERSION, "VERSION", dump_short },
00214    { IAX_IE_ADSICPE, "ADSICPE", dump_short },
00215    { IAX_IE_DNID, "DNID", dump_string },
00216    { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
00217    { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
00218    { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
00219    { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
00220    { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
00221    { IAX_IE_REFRESH, "REFRESH", dump_short },
00222    { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
00223    { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
00224    { IAX_IE_CAUSE, "CAUSE", dump_string },
00225    { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
00226    { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
00227    { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
00228    { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
00229    { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
00230    { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
00231    { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
00232    { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
00233    { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
00234    { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
00235    { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
00236    { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
00237    { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
00238    { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
00239    { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
00240    { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
00241    { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
00242    { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
00243    { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
00244    { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
00245    { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
00246    { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
00247    { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
00248    { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
00249    { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
00250    { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
00251    { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
00252    { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
00253 };
00254 
00255 static struct iax2_ie prov_ies[] = {
00256    { PROV_IE_USEDHCP, "USEDHCP" },
00257    { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
00258    { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
00259    { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
00260    { PROV_IE_PORTNO, "BINDPORT", dump_short },
00261    { PROV_IE_USER, "USERNAME", dump_string },
00262    { PROV_IE_PASS, "PASSWORD", dump_string },
00263    { PROV_IE_LANG, "LANGUAGE", dump_string },
00264    { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
00265    { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
00266    { PROV_IE_FORMAT, "FORMAT", dump_int },
00267    { PROV_IE_AESKEY, "AESKEY" },
00268    { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
00269    { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
00270    { PROV_IE_NEWAESKEY, "NEWAESKEY" },
00271    { PROV_IE_PROVVER, "PROV VERSION", dump_int },
00272    { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
00273 };
00274 
00275 const char *iax_ie2str(int ie)
00276 {
00277    int x;
00278    for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00279       if (ies[x].ie == ie)
00280          return ies[x].name;
00281    }
00282    return "Unknown IE";
00283 }
00284 
00285 
00286 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
00287 {
00288    int ielen;
00289    int ie;
00290    int x;
00291    int found;
00292    char interp[80];
00293    char tmp[256];
00294    if (len < 2)
00295       return;
00296    strcpy(output, "\n"); 
00297    maxlen -= strlen(output); output += strlen(output);
00298    while(len > 2) {
00299       ie = iedata[0];
00300       ielen = iedata[1];
00301       if (ielen + 2> len) {
00302          snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
00303          ast_copy_string(output, tmp, maxlen);
00304          maxlen -= strlen(output);
00305          output += strlen(output);
00306          return;
00307       }
00308       found = 0;
00309       for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
00310          if (prov_ies[x].ie == ie) {
00311             if (prov_ies[x].dump) {
00312                prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00313                snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
00314                ast_copy_string(output, tmp, maxlen);
00315                maxlen -= strlen(output); output += strlen(output);
00316             } else {
00317                if (ielen)
00318                   snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00319                else
00320                   strcpy(interp, "Present");
00321                snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
00322                ast_copy_string(output, tmp, maxlen);
00323                maxlen -= strlen(output); output += strlen(output);
00324             }
00325             found++;
00326          }
00327       }
00328       if (!found) {
00329          snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
00330          ast_copy_string(output, tmp, maxlen);
00331          maxlen -= strlen(output); output += strlen(output);
00332       }
00333       iedata += (2 + ielen);
00334       len -= (2 + ielen);
00335    }
00336 }
00337 
00338 static void dump_ies(unsigned char *iedata, int len)
00339 {
00340    int ielen;
00341    int ie;
00342    int x;
00343    int found;
00344    char interp[1024];
00345    char tmp[1024];
00346    if (len < 2)
00347       return;
00348    while(len > 2) {
00349       ie = iedata[0];
00350       ielen = iedata[1];
00351       if (ielen + 2> len) {
00352          snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
00353          outputf(tmp);
00354          return;
00355       }
00356       found = 0;
00357       for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00358          if (ies[x].ie == ie) {
00359             if (ies[x].dump) {
00360                ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00361                snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
00362                outputf(tmp);
00363             } else {
00364                if (ielen)
00365                   snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00366                else
00367                   strcpy(interp, "Present");
00368                snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
00369                outputf(tmp);
00370             }
00371             found++;
00372          }
00373       }
00374       if (!found) {
00375          snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
00376          outputf(tmp);
00377       }
00378       iedata += (2 + ielen);
00379       len -= (2 + ielen);
00380    }
00381    outputf("\n");
00382 }
00383 
00384 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
00385 {
00386    const char *frames[] = {
00387       "(0?)",
00388       "DTMF   ",
00389       "VOICE  ",
00390       "VIDEO  ",
00391       "CONTROL",
00392       "NULL   ",
00393       "IAX    ",
00394       "TEXT   ",
00395       "IMAGE  ",
00396       "HTML   ",
00397       "CNG    " };
00398    const char *iaxs[] = {
00399       "(0?)",
00400       "NEW    ",
00401       "PING   ",
00402       "PONG   ",
00403       "ACK    ",
00404       "HANGUP ",
00405       "REJECT ",
00406       "ACCEPT ",
00407       "AUTHREQ",
00408       "AUTHREP",
00409       "INVAL  ",
00410       "LAGRQ  ",
00411       "LAGRP  ",
00412       "REGREQ ",
00413       "REGAUTH",
00414       "REGACK ",
00415       "REGREJ ",
00416       "REGREL ",
00417       "VNAK   ",
00418       "DPREQ  ",
00419       "DPREP  ",
00420       "DIAL   ",
00421       "TXREQ  ",
00422       "TXCNT  ",
00423       "TXACC  ",
00424       "TXREADY",
00425       "TXREL  ",
00426       "TXREJ  ",
00427       "QUELCH ",
00428       "UNQULCH",
00429       "POKE   ",
00430       "PAGE   ",
00431       "MWI    ",
00432       "UNSPRTD",
00433       "TRANSFR",
00434       "PROVISN",
00435       "FWDWNLD",
00436       "FWDATA "
00437    };
00438    const char *cmds[] = {
00439       "(0?)",
00440       "HANGUP ",
00441       "RING   ",
00442       "RINGING",
00443       "ANSWER ",
00444       "BUSY   ",
00445       "TKOFFHK",
00446       "OFFHOOK" };
00447    struct ast_iax2_full_hdr *fh;
00448    char retries[20];
00449    char class2[20];
00450    char subclass2[20];
00451    const char *class;
00452    const char *subclass;
00453    char *dir;
00454    char tmp[512];
00455    char iabuf[INET_ADDRSTRLEN];
00456 
00457    switch(rx) {
00458    case 0:
00459       dir = "Tx";
00460       break;
00461    case 2:
00462       dir = "TE";
00463       break;
00464    case 3:
00465       dir = "RD";
00466       break;
00467    default:
00468       dir = "Rx";
00469       break;
00470    }
00471    if (f) {
00472       fh = f->data;
00473       snprintf(retries, sizeof(retries), "%03d", f->retries);
00474    } else {
00475       fh = fhi;
00476       if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
00477          strcpy(retries, "Yes");
00478       else
00479          strcpy(retries, " No");
00480    }
00481    if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
00482       /* Don't mess with mini-frames */
00483       return;
00484    }
00485    if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
00486       snprintf(class2, sizeof(class2), "(%d?)", fh->type);
00487       class = class2;
00488    } else {
00489       class = frames[(int)fh->type];
00490    }
00491    if (fh->type == AST_FRAME_DTMF) {
00492       sprintf(subclass2, "%c", fh->csub);
00493       subclass = subclass2;
00494    } else if (fh->type == AST_FRAME_IAX) {
00495       if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
00496          snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00497          subclass = subclass2;
00498       } else {
00499          subclass = iaxs[(int)fh->csub];
00500       }
00501    } else if (fh->type == AST_FRAME_CONTROL) {
00502       if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
00503          snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00504          subclass = subclass2;
00505       } else {
00506          subclass = cmds[(int)fh->csub];
00507       }
00508    } else {
00509       snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
00510       subclass = subclass2;
00511    }
00512    snprintf(tmp, sizeof(tmp), 
00513        "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
00514        dir,
00515        retries, fh->oseqno, fh->iseqno, class, subclass);
00516    outputf(tmp);
00517    snprintf(tmp, sizeof(tmp), 
00518        "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
00519        (unsigned long)ntohl(fh->ts),
00520        ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
00521        ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
00522    outputf(tmp);
00523    if (fh->type == AST_FRAME_IAX)
00524       dump_ies(fh->iedata, datalen);
00525 }
00526 
00527 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
00528 {
00529    char tmp[256];
00530    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00531       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);
00532       errorf(tmp);
00533       return -1;
00534    }
00535    ied->buf[ied->pos++] = ie;
00536    ied->buf[ied->pos++] = datalen;
00537    memcpy(ied->buf + ied->pos, data, datalen);
00538    ied->pos += datalen;
00539    return 0;
00540 }
00541 
00542 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
00543 {
00544    return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00545 }
00546 
00547 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
00548 {
00549    unsigned int newval;
00550    newval = htonl(value);
00551    return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00552 }
00553 
00554 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
00555 {
00556    unsigned short newval;
00557    newval = htons(value);
00558    return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00559 }
00560 
00561 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, char *str)
00562 {
00563    return iax_ie_append_raw(ied, ie, str, strlen(str));
00564 }
00565 
00566 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
00567 {
00568    return iax_ie_append_raw(ied, ie, &dat, 1);
00569 }
00570 
00571 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
00572 {
00573    return iax_ie_append_raw(ied, ie, NULL, 0);
00574 }
00575 
00576 void iax_set_output(void (*func)(const char *))
00577 {
00578    outputf = func;
00579 }
00580 
00581 void iax_set_error(void (*func)(const char *))
00582 {
00583    errorf = func;
00584 }
00585 
00586 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
00587 {
00588    /* Parse data into information elements */
00589    int len;
00590    int ie;
00591    char tmp[256];
00592    memset(ies, 0, (int)sizeof(struct iax_ies));
00593    ies->msgcount = -1;
00594    ies->firmwarever = -1;
00595    ies->calling_ton = -1;
00596    ies->calling_tns = -1;
00597    ies->calling_pres = -1;
00598    ies->samprate = IAX_RATE_8KHZ;
00599    while(datalen >= 2) {
00600       ie = data[0];
00601       len = data[1];
00602       if (len > datalen - 2) {
00603          errorf("Information element length exceeds message size\n");
00604          return -1;
00605       }
00606       switch(ie) {
00607       case IAX_IE_CALLED_NUMBER:
00608          ies->called_number = (char *)data + 2;
00609          break;
00610       case IAX_IE_CALLING_NUMBER:
00611          ies->calling_number = (char *)data + 2;
00612          break;
00613       case IAX_IE_CALLING_ANI:
00614          ies->calling_ani = (char *)data + 2;
00615          break;
00616       case IAX_IE_CALLING_NAME:
00617          ies->calling_name = (char *)data + 2;
00618          break;
00619       case IAX_IE_CALLED_CONTEXT:
00620          ies->called_context = (char *)data + 2;
00621          break;
00622       case IAX_IE_USERNAME:
00623          ies->username = (char *)data + 2;
00624          break;
00625       case IAX_IE_PASSWORD:
00626          ies->password = (char *)data + 2;
00627          break;
00628       case IAX_IE_CODEC_PREFS:
00629          ies->codec_prefs = (char *)data + 2;
00630          break;
00631       case IAX_IE_CAPABILITY:
00632          if (len != (int)sizeof(unsigned int)) {
00633             snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00634             errorf(tmp);
00635          } else
00636             ies->capability = ntohl(get_unaligned_uint32(data + 2));
00637          break;
00638       case IAX_IE_FORMAT:
00639          if (len != (int)sizeof(unsigned int)) {
00640             snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00641             errorf(tmp);
00642          } else
00643             ies->format = ntohl(get_unaligned_uint32(data + 2));
00644          break;
00645       case IAX_IE_LANGUAGE:
00646          ies->language = (char *)data + 2;
00647          break;
00648       case IAX_IE_VERSION:
00649          if (len != (int)sizeof(unsigned short)) {
00650             snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00651             errorf(tmp);
00652          } else
00653             ies->version = ntohs(get_unaligned_uint16(data + 2));
00654          break;
00655       case IAX_IE_ADSICPE:
00656          if (len != (int)sizeof(unsigned short)) {
00657             snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00658             errorf(tmp);
00659          } else
00660             ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
00661          break;
00662       case IAX_IE_SAMPLINGRATE:
00663          if (len != (int)sizeof(unsigned short)) {
00664             snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00665             errorf(tmp);
00666          } else
00667             ies->samprate = ntohs(get_unaligned_uint16(data + 2));
00668          break;
00669       case IAX_IE_DNID:
00670          ies->dnid = (char *)data + 2;
00671          break;
00672       case IAX_IE_RDNIS:
00673          ies->rdnis = (char *)data + 2;
00674          break;
00675       case IAX_IE_AUTHMETHODS:
00676          if (len != (int)sizeof(unsigned short))  {
00677             snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00678             errorf(tmp);
00679          } else
00680             ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
00681          break;
00682       case IAX_IE_ENCRYPTION:
00683          if (len != (int)sizeof(unsigned short))  {
00684             snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00685             errorf(tmp);
00686          } else
00687             ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
00688          break;
00689       case IAX_IE_CHALLENGE:
00690          ies->challenge = (char *)data + 2;
00691          break;
00692       case IAX_IE_MD5_RESULT:
00693          ies->md5_result = (char *)data + 2;
00694          break;
00695       case IAX_IE_RSA_RESULT:
00696          ies->rsa_result = (char *)data + 2;
00697          break;
00698       case IAX_IE_APPARENT_ADDR:
00699          ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
00700          break;
00701       case IAX_IE_REFRESH:
00702          if (len != (int)sizeof(unsigned short)) {
00703             snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00704             errorf(tmp);
00705          } else
00706             ies->refresh = ntohs(get_unaligned_uint16(data + 2));
00707          break;
00708       case IAX_IE_DPSTATUS:
00709          if (len != (int)sizeof(unsigned short)) {
00710             snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00711             errorf(tmp);
00712          } else
00713             ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
00714          break;
00715       case IAX_IE_CALLNO:
00716          if (len != (int)sizeof(unsigned short)) {
00717             snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00718             errorf(tmp);
00719          } else
00720             ies->callno = ntohs(get_unaligned_uint16(data + 2));
00721          break;
00722       case IAX_IE_CAUSE:
00723          ies->cause = (char *)data + 2;
00724          break;
00725       case IAX_IE_CAUSECODE:
00726          if (len != 1) {
00727             snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
00728             errorf(tmp);
00729          } else {
00730             ies->causecode = data[2];
00731          }
00732          break;
00733       case IAX_IE_IAX_UNKNOWN:
00734          if (len == 1)
00735             ies->iax_unknown = data[2];
00736          else {
00737             snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00738             errorf(tmp);
00739          }
00740          break;
00741       case IAX_IE_MSGCOUNT:
00742          if (len != (int)sizeof(unsigned short)) {
00743             snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00744             errorf(tmp);
00745          } else
00746             ies->msgcount = ntohs(get_unaligned_uint16(data + 2));   
00747          break;
00748       case IAX_IE_AUTOANSWER:
00749          ies->autoanswer = 1;
00750          break;
00751       case IAX_IE_MUSICONHOLD:
00752          ies->musiconhold = 1;
00753          break;
00754       case IAX_IE_TRANSFERID:
00755          if (len != (int)sizeof(unsigned int)) {
00756             snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00757             errorf(tmp);
00758          } else
00759             ies->transferid = ntohl(get_unaligned_uint32(data + 2));
00760          break;
00761       case IAX_IE_DATETIME:
00762          if (len != (int)sizeof(unsigned int)) {
00763             snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00764             errorf(tmp);
00765          } else
00766             ies->datetime = ntohl(get_unaligned_uint32(data + 2));
00767          break;
00768       case IAX_IE_FIRMWAREVER:
00769          if (len != (int)sizeof(unsigned short)) {
00770             snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00771             errorf(tmp);
00772          } else
00773             ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));   
00774          break;
00775       case IAX_IE_DEVICETYPE:
00776          ies->devicetype = (char *)data + 2;
00777          break;
00778       case IAX_IE_SERVICEIDENT:
00779          ies->serviceident = (char *)data + 2;
00780          break;
00781       case IAX_IE_FWBLOCKDESC:
00782          if (len != (int)sizeof(unsigned int)) {
00783             snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00784             errorf(tmp);
00785          } else
00786             ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
00787          break;
00788       case IAX_IE_FWBLOCKDATA:
00789          ies->fwdata = data + 2;
00790          ies->fwdatalen = len;
00791          break;
00792       case IAX_IE_ENCKEY:
00793          ies->enckey = data + 2;
00794          ies->enckeylen = len;
00795          break;
00796       case IAX_IE_PROVVER:
00797          if (len != (int)sizeof(unsigned int)) {
00798             snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00799             errorf(tmp);
00800          } else {
00801             ies->provverpres = 1;
00802             ies->provver = ntohl(get_unaligned_uint32(data + 2));
00803          }
00804          break;
00805       case IAX_IE_CALLINGPRES:
00806          if (len == 1)
00807             ies->calling_pres = data[2];
00808          else {
00809             snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
00810             errorf(tmp);
00811          }
00812          break;
00813       case IAX_IE_CALLINGTON:
00814          if (len == 1)
00815             ies->calling_ton = data[2];
00816          else {
00817             snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
00818             errorf(tmp);
00819          }
00820          break;
00821       case IAX_IE_CALLINGTNS:
00822          if (len != (int)sizeof(unsigned short)) {
00823             snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00824             errorf(tmp);
00825          } else
00826             ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));   
00827          break;
00828                case IAX_IE_RR_JITTER:
00829                        if (len != (int)sizeof(unsigned int)) {
00830                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00831                                errorf(tmp);
00832                        } else {
00833                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
00834                        }
00835                        break;
00836                case IAX_IE_RR_LOSS:
00837                        if (len != (int)sizeof(unsigned int)) {
00838                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00839                                errorf(tmp);
00840                        } else {
00841                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
00842                        }
00843                        break;
00844                case IAX_IE_RR_PKTS:
00845                        if (len != (int)sizeof(unsigned int)) {
00846                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00847                                errorf(tmp);
00848                        } else {
00849                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
00850                        }
00851                        break;
00852                case IAX_IE_RR_DELAY:
00853                        if (len != (int)sizeof(unsigned short)) {
00854                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00855                         errorf(tmp);
00856                        } else {
00857                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
00858                        }
00859                        break;
00860       case IAX_IE_RR_DROPPED:
00861          if (len != (int)sizeof(unsigned int)) {
00862             snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00863             errorf(tmp);
00864          } else {
00865             ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
00866          }
00867          break;
00868       case IAX_IE_RR_OOO:
00869          if (len != (int)sizeof(unsigned int)) {
00870             snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00871             errorf(tmp);
00872          } else {
00873             ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
00874          }
00875          break;
00876       default:
00877          snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
00878          outputf(tmp);
00879       }
00880       /* Overwrite information element with 0, to null terminate previous portion */
00881       data[0] = 0;
00882       datalen -= (len + 2);
00883       data += (len + 2);
00884    }
00885    /* Null-terminate last field */
00886    *data = '\0';
00887    if (datalen) {
00888       errorf("Invalid information element contents, strange boundary\n");
00889       return -1;
00890    }
00891    return 0;
00892 }
00893 
00894 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
00895 {
00896    fr->af.frametype = f->frametype;
00897    fr->af.subclass = f->subclass;
00898    fr->af.mallocd = 0;           /* Our frame is static relative to the container */
00899    fr->af.datalen = f->datalen;
00900    fr->af.samples = f->samples;
00901    fr->af.offset = AST_FRIENDLY_OFFSET;
00902    fr->af.src = f->src;
00903    fr->af.delivery.tv_sec = 0;
00904    fr->af.delivery.tv_usec = 0;
00905    fr->af.data = fr->afdata;
00906    if (fr->af.datalen) {
00907 #if __BYTE_ORDER == __LITTLE_ENDIAN
00908       /* We need to byte-swap slinear samples from network byte order */
00909       if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
00910          ast_swapcopy_samples(fr->af.data, f->data, fr->af.samples);
00911       } else
00912 #endif
00913       memcpy(fr->af.data, f->data, fr->af.datalen);
00914    }
00915 }
00916 
00917 struct iax_frame *iax_frame_new(int direction, int datalen)
00918 {
00919    struct iax_frame *fr;
00920    fr = malloc((int)sizeof(struct iax_frame) + datalen);
00921    if (fr) {
00922       fr->direction = direction;
00923       fr->retrans = -1;
00924       frames++;
00925       if (fr->direction == DIRECTION_INGRESS)
00926          iframes++;
00927       else
00928          oframes++;
00929    }
00930    return fr;
00931 }
00932 
00933 void iax_frame_free(struct iax_frame *fr)
00934 {
00935    /* Note: does not remove from scheduler! */
00936    if (fr->direction == DIRECTION_INGRESS)
00937       iframes--;
00938    else if (fr->direction == DIRECTION_OUTGRESS)
00939       oframes--;
00940    else {
00941       errorf("Attempt to double free frame detected\n");
00942       return;
00943    }
00944    fr->direction = 0;
00945    free(fr);
00946    frames--;
00947 }
00948 
00949 int iax_get_frames(void) { return frames; }
00950 int iax_get_iframes(void) { return iframes; }
00951 int iax_get_oframes(void) { return oframes; }

Generated on Sat Mar 24 23:26:05 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.6