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

Generated on Mon May 14 04:42:59 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1