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

Generated on Wed Aug 15 01:24:21 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3