Tue Apr 28 22:50:08 2009

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

Generated on Tue Apr 28 22:50:08 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7