Mon Oct 8 12:39:03 2012

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 /*** MODULEINFO
00027    <support_level>core</support_level>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369001 $")
00033 
00034 #include <sys/socket.h>
00035 #include <netinet/in.h>
00036 #include <arpa/inet.h>
00037 
00038 #include "asterisk/frame.h"
00039 #include "asterisk/utils.h"
00040 #include "asterisk/unaligned.h"
00041 #include "asterisk/config.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, NULL, 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       ast_copy_string(output, "Invalid Address", maxlen);
00092    }
00093 }
00094 
00095 static void dump_string_hex(char *output, int maxlen, void *value, int len)
00096 {
00097    int i = 0;
00098 
00099    while (len-- && (i + 1) * 4 < maxlen) {
00100       sprintf(output + (4 * i), "\\x%2.2x", *((unsigned char *)value + i));
00101       i++;
00102    }
00103 }
00104 
00105 static void dump_string(char *output, int maxlen, void *value, int len)
00106 {
00107    maxlen--;
00108    if (maxlen > len)
00109       maxlen = len;
00110    strncpy(output, value, maxlen);
00111    output[maxlen] = '\0';
00112 }
00113 
00114 static void dump_prefs(char *output, int maxlen, void *value, int len)
00115 {
00116    struct ast_codec_pref pref;
00117    int total_len = 0;
00118 
00119    maxlen--;
00120    total_len = maxlen;
00121 
00122    if (maxlen > len)
00123       maxlen = len;
00124 
00125    strncpy(output, value, maxlen);
00126    output[maxlen] = '\0';
00127    
00128    ast_codec_pref_convert(&pref, output, total_len, 0);
00129    memset(output,0,total_len);
00130    ast_codec_pref_string(&pref, output, total_len);
00131 }
00132 
00133 static void dump_int(char *output, int maxlen, void *value, int len)
00134 {
00135    if (len == (int)sizeof(unsigned int))
00136       snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
00137    else
00138       ast_copy_string(output, "Invalid INT", maxlen); 
00139 }
00140 
00141 static void dump_short(char *output, int maxlen, void *value, int len)
00142 {
00143    if (len == (int)sizeof(unsigned short))
00144       snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
00145    else
00146       ast_copy_string(output, "Invalid SHORT", maxlen);
00147 }
00148 
00149 static void dump_byte(char *output, int maxlen, void *value, int len)
00150 {
00151    if (len == (int)sizeof(unsigned char))
00152       snprintf(output, maxlen, "%d", *((unsigned char *)value));
00153    else
00154       ast_copy_string(output, "Invalid BYTE", maxlen);
00155 }
00156 
00157 static void dump_datetime(char *output, int maxlen, void *value, int len)
00158 {
00159    struct ast_tm tm;
00160    unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
00161    if (len == (int)sizeof(unsigned int)) {
00162       tm.tm_sec  = (val & 0x1f) << 1;
00163       tm.tm_min  = (val >> 5) & 0x3f;
00164       tm.tm_hour = (val >> 11) & 0x1f;
00165       tm.tm_mday = (val >> 16) & 0x1f;
00166       tm.tm_mon  = ((val >> 21) & 0x0f) - 1;
00167       tm.tm_year = ((val >> 25) & 0x7f) + 100;
00168       ast_strftime(output, maxlen, "%Y-%m-%d  %T", &tm); 
00169    } else
00170       ast_copy_string(output, "Invalid DATETIME format!", maxlen);
00171 }
00172 
00173 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
00174 {
00175    struct sockaddr_in sin;
00176    if (len == (int)sizeof(unsigned int)) {
00177       memcpy(&sin.sin_addr, value, len);
00178       snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
00179    } else
00180       ast_copy_string(output, "Invalid IPADDR", maxlen);
00181 }
00182 
00183 
00184 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
00185 {
00186    char buf[256] = "";
00187    if (len == (int)sizeof(unsigned int))
00188       snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
00189          iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
00190    else
00191       ast_copy_string(output, "Invalid INT", maxlen);
00192 }
00193 
00194 static void dump_samprate(char *output, int maxlen, void *value, int len)
00195 {
00196    char tmp[256]="";
00197    int sr;
00198    if (len == (int)sizeof(unsigned short)) {
00199       sr = ntohs(*((unsigned short *)value));
00200       if (sr & IAX_RATE_8KHZ)
00201          strcat(tmp, ",8khz");
00202       if (sr & IAX_RATE_11KHZ)
00203          strcat(tmp, ",11.025khz");
00204       if (sr & IAX_RATE_16KHZ)
00205          strcat(tmp, ",16khz");
00206       if (sr & IAX_RATE_22KHZ)
00207          strcat(tmp, ",22.05khz");
00208       if (sr & IAX_RATE_44KHZ)
00209          strcat(tmp, ",44.1khz");
00210       if (sr & IAX_RATE_48KHZ)
00211          strcat(tmp, ",48khz");
00212       if (strlen(tmp))
00213          ast_copy_string(output, &tmp[1], maxlen);
00214       else
00215          ast_copy_string(output, "None Specified!\n", maxlen);
00216    } else
00217       ast_copy_string(output, "Invalid SHORT", maxlen);
00218 
00219 }
00220 
00221 static void dump_versioned_codec(char *output, int maxlen, void *value, int len)
00222 {
00223    char *version = (char *) value;
00224    if (version[0] == 0) {
00225       if (len == (int) (sizeof(format_t) + sizeof(char))) {
00226          format_t codec = ntohll(get_unaligned_uint64(value + 1));
00227          ast_copy_string(output, ast_getformatname(codec), maxlen);
00228       } else {
00229          ast_copy_string(output, "Invalid length!", maxlen);
00230       }
00231    } else {
00232       ast_copy_string(output, "Unknown version!", maxlen);
00233    }
00234 }
00235 
00236 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
00237 static void dump_prov(char *output, int maxlen, void *value, int len)
00238 {
00239    dump_prov_ies(output, maxlen, value, len);
00240 }
00241 
00242 static struct iax2_ie {
00243    int ie;
00244    char *name;
00245    void (*dump)(char *output, int maxlen, void *value, int len);
00246 } infoelts[] = {
00247    { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
00248    { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
00249    { IAX_IE_CALLING_ANI, "ANI", dump_string },
00250    { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
00251    { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
00252    { IAX_IE_USERNAME, "USERNAME", dump_string },
00253    { IAX_IE_PASSWORD, "PASSWORD", dump_string },
00254    { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
00255    { IAX_IE_CAPABILITY2, "CAPABILITY2", dump_versioned_codec },
00256    { IAX_IE_FORMAT, "FORMAT", dump_int },
00257    { IAX_IE_FORMAT2, "FORMAT2", dump_versioned_codec },
00258    { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
00259    { IAX_IE_VERSION, "VERSION", dump_short },
00260    { IAX_IE_ADSICPE, "ADSICPE", dump_short },
00261    { IAX_IE_DNID, "DNID", dump_string },
00262    { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
00263    { IAX_IE_CHALLENGE, "CHALLENGE", dump_string_hex },
00264    { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
00265    { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
00266    { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
00267    { IAX_IE_REFRESH, "REFRESH", dump_short },
00268    { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
00269    { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
00270    { IAX_IE_CAUSE, "CAUSE", dump_string },
00271    { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
00272    { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
00273    { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
00274    { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
00275    { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
00276    { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
00277    { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
00278    { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
00279    { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
00280    { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
00281    { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
00282    { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
00283    { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
00284    { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
00285    { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
00286    { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
00287    { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
00288    { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
00289    { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
00290    { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
00291    { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
00292    { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
00293    { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
00294    { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
00295    { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
00296    { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
00297    { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
00298    { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
00299    { IAX_IE_VARIABLE, "VARIABLE", dump_string },
00300    { IAX_IE_OSPTOKEN, "OSPTOKEN" },
00301    { IAX_IE_CALLTOKEN, "CALLTOKEN" },
00302 };
00303 
00304 static const struct iax2_ie prov_ies[] = {
00305    { PROV_IE_USEDHCP, "USEDHCP" },
00306    { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
00307    { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
00308    { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
00309    { PROV_IE_PORTNO, "BINDPORT", dump_short },
00310    { PROV_IE_USER, "USERNAME", dump_string },
00311    { PROV_IE_PASS, "PASSWORD", dump_string },
00312    { PROV_IE_LANG, "LANGUAGE", dump_string },
00313    { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
00314    { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
00315    { PROV_IE_FORMAT, "FORMAT", dump_int },
00316    { PROV_IE_AESKEY, "AESKEY" },
00317    { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
00318    { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
00319    { PROV_IE_NEWAESKEY, "NEWAESKEY" },
00320    { PROV_IE_PROVVER, "PROV VERSION", dump_int },
00321    { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
00322 };
00323 
00324 const char *iax_ie2str(int ie)
00325 {
00326    int x;
00327    for (x = 0; x < ARRAY_LEN(infoelts); x++) {
00328       if (infoelts[x].ie == ie)
00329          return infoelts[x].name;
00330    }
00331    return "Unknown IE";
00332 }
00333 
00334 
00335 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
00336 {
00337    int ielen;
00338    int ie;
00339    int x;
00340    int found;
00341    char interp[80];
00342    char tmp[256];
00343    if (len < 2)
00344       return;
00345    strcpy(output, "\n"); 
00346    maxlen -= strlen(output); output += strlen(output);
00347    while(len > 2) {
00348       ie = iedata[0];
00349       ielen = iedata[1];
00350       if (ielen + 2> len) {
00351          snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
00352          ast_copy_string(output, tmp, maxlen);
00353          maxlen -= strlen(output);
00354          output += strlen(output);
00355          return;
00356       }
00357       found = 0;
00358       for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
00359          if (prov_ies[x].ie == ie) {
00360             if (prov_ies[x].dump) {
00361                prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00362                snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
00363                ast_copy_string(output, tmp, maxlen);
00364                maxlen -= strlen(output); output += strlen(output);
00365             } else {
00366                if (ielen)
00367                   snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00368                else
00369                   strcpy(interp, "Present");
00370                snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
00371                ast_copy_string(output, tmp, maxlen);
00372                maxlen -= strlen(output); output += strlen(output);
00373             }
00374             found++;
00375          }
00376       }
00377       if (!found) {
00378          snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
00379          ast_copy_string(output, tmp, maxlen);
00380          maxlen -= strlen(output); output += strlen(output);
00381       }
00382       iedata += (2 + ielen);
00383       len -= (2 + ielen);
00384    }
00385 }
00386 
00387 static void dump_ies(unsigned char *iedata, int len)
00388 {
00389    int ielen;
00390    int ie;
00391    int x;
00392    int found;
00393    char interp[1024];
00394    char tmp[1024];
00395    if (len < 2)
00396       return;
00397    while(len > 2) {
00398       ie = iedata[0];
00399       ielen = iedata[1];
00400       if (ielen + 2> len) {
00401          snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
00402          outputf(tmp);
00403          return;
00404       }
00405       found = 0;
00406       for (x = 0; x < ARRAY_LEN(infoelts); x++) {
00407          if (infoelts[x].ie == ie) {
00408             if (infoelts[x].dump) {
00409                infoelts[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00410                snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", infoelts[x].name, interp);
00411                outputf(tmp);
00412             } else {
00413                if (ielen)
00414                   snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00415                else
00416                   strcpy(interp, "Present");
00417                snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", infoelts[x].name, interp);
00418                outputf(tmp);
00419             }
00420             found++;
00421          }
00422       }
00423       if (!found) {
00424          snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
00425          outputf(tmp);
00426       }
00427       iedata += (2 + ielen);
00428       len -= (2 + ielen);
00429    }
00430    outputf("\n");
00431 }
00432 
00433 void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len)
00434 {
00435    const char *cmd = "Unknown";
00436 
00437    /* if an error occurs here during compile, that means a new iax frame subclass
00438     * has been added to the iax_frame_subclass enum.  Add the new subclass to the
00439     * switch case and make sure to update it with a new string representation. */
00440    switch (subclass) {
00441    case IAX_COMMAND_NEW:
00442       cmd = "NEW    ";
00443       break;
00444    case IAX_COMMAND_PING:
00445       cmd = "PING   ";
00446       break;
00447    case IAX_COMMAND_PONG:
00448       cmd = "PONG   ";
00449       break;
00450    case IAX_COMMAND_ACK:
00451       cmd = "ACK    ";
00452       break;
00453    case IAX_COMMAND_HANGUP:
00454       cmd = "HANGUP ";
00455       break;
00456    case IAX_COMMAND_REJECT:
00457       cmd = "REJECT ";
00458       break;
00459    case IAX_COMMAND_ACCEPT:
00460       cmd = "ACCEPT ";
00461       break;
00462    case IAX_COMMAND_AUTHREQ:
00463       cmd = "AUTHREQ";
00464       break;
00465    case IAX_COMMAND_AUTHREP:
00466       cmd = "AUTHREP";
00467       break;
00468    case IAX_COMMAND_INVAL:
00469       cmd = "INVAL  ";
00470       break;
00471    case IAX_COMMAND_LAGRQ:
00472       cmd = "LAGRQ  ";
00473       break;
00474    case IAX_COMMAND_LAGRP:
00475       cmd = "LAGRP  ";
00476       break;
00477    case IAX_COMMAND_REGREQ:
00478       cmd = "REGREQ ";
00479       break;
00480    case IAX_COMMAND_REGAUTH:
00481       cmd = "REGAUTH";
00482       break;
00483    case IAX_COMMAND_REGACK:
00484       cmd = "REGACK ";
00485       break;
00486    case IAX_COMMAND_REGREJ:
00487       cmd = "REGREJ ";
00488       break;
00489    case IAX_COMMAND_REGREL:
00490       cmd = "REGREL ";
00491       break;
00492    case IAX_COMMAND_VNAK:
00493       cmd = "VNAK   ";
00494       break;
00495    case IAX_COMMAND_DPREQ:
00496       cmd = "DPREQ  ";
00497       break;
00498    case IAX_COMMAND_DPREP:
00499       cmd = "DPREP  ";
00500       break;
00501    case IAX_COMMAND_DIAL:
00502       cmd = "DIAL   ";
00503       break;
00504    case IAX_COMMAND_TXREQ:
00505       cmd = "TXREQ  ";
00506       break;
00507    case IAX_COMMAND_TXCNT:
00508       cmd = "TXCNT  ";
00509       break;
00510    case IAX_COMMAND_TXACC:
00511       cmd = "TXACC  ";
00512       break;
00513    case IAX_COMMAND_TXREADY:
00514       cmd = "TXREADY";
00515       break;
00516    case IAX_COMMAND_TXREL:
00517       cmd = "TXREL  ";
00518       break;
00519    case IAX_COMMAND_TXREJ:
00520       cmd = "TXREJ  ";
00521       break;
00522    case IAX_COMMAND_QUELCH:
00523       cmd = "QUELCH ";
00524       break;
00525    case IAX_COMMAND_UNQUELCH:
00526       cmd = "UNQULCH";
00527       break;
00528    case IAX_COMMAND_POKE:
00529       cmd = "POKE   ";
00530       break;
00531    case IAX_COMMAND_PAGE:
00532       cmd = "PAGE   ";
00533       break;
00534    case IAX_COMMAND_MWI:
00535       cmd = "MWI    ";
00536       break;
00537    case IAX_COMMAND_UNSUPPORT:
00538       cmd = "UNSPRTD";
00539       break;
00540    case IAX_COMMAND_TRANSFER:
00541       cmd = "TRANSFR";
00542       break;
00543    case IAX_COMMAND_PROVISION:
00544       cmd = "PROVISN";
00545       break;
00546    case IAX_COMMAND_FWDOWNL:
00547       cmd = "FWDWNLD";
00548       break;
00549    case IAX_COMMAND_FWDATA:
00550       cmd = "FWDATA ";
00551       break;
00552    case IAX_COMMAND_TXMEDIA:
00553       cmd = "TXMEDIA";
00554       break;
00555    case IAX_COMMAND_RTKEY:
00556       cmd = "RTKEY  ";
00557       break;
00558    case IAX_COMMAND_CALLTOKEN:
00559       cmd = "CTOKEN ";
00560       break;
00561    }
00562    ast_copy_string(str, cmd, len);
00563 }
00564 
00565 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
00566 {
00567    const char *framelist[] = {
00568       "(0?)",
00569       "DTMF_E ",
00570       "VOICE  ",
00571       "VIDEO  ",
00572       "CONTROL",
00573       "NULL   ",
00574       "IAX    ",
00575       "TEXT   ",
00576       "IMAGE  ",
00577       "HTML   ",
00578       "CNG    ",
00579       "MODEM  ",
00580       "DTMF_B ",
00581    };
00582    const char *cmds[] = {
00583       "(0?)",
00584       "HANGUP ",
00585       "RING   ",
00586       "RINGING",
00587       "ANSWER ",
00588       "BUSY   ",
00589       "TKOFFHK",
00590       "OFFHOOK",
00591       "CONGSTN",
00592       "FLASH  ",
00593       "WINK   ",
00594       "OPTION ",
00595       "RDKEY  ",
00596       "RDUNKEY",
00597       "PROGRES",
00598       "PROCDNG",
00599       "HOLD   ",
00600       "UNHOLD ",
00601       "VIDUPDT",
00602       "T38    ",
00603       "SRCUPDT",
00604       "TXFER  ",
00605       "CNLINE ",
00606       "REDIR  ",
00607    };
00608    struct ast_iax2_full_hdr *fh;
00609    char retries[20];
00610    char class2[20];
00611    char subclass2[20];
00612    const char *class;
00613    const char *subclass;
00614    char *dir;
00615    char tmp[512];
00616 
00617    switch(rx) {
00618    case 0:
00619       dir = "Tx";
00620       break;
00621    case 2:
00622       dir = "TE";
00623       break;
00624    case 3:
00625       dir = "RD";
00626       break;
00627    default:
00628       dir = "Rx";
00629       break;
00630    }
00631    if (f) {
00632       fh = f->data;
00633       snprintf(retries, sizeof(retries), "%03d", f->retries);
00634    } else {
00635       fh = fhi;
00636       if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
00637          strcpy(retries, "Yes");
00638       else
00639          strcpy(retries, " No");
00640    }
00641    if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
00642       /* Don't mess with mini-frames */
00643       return;
00644    }
00645    if (fh->type >= ARRAY_LEN(framelist)) {
00646       snprintf(class2, sizeof(class2), "(%d?)", fh->type);
00647       class = class2;
00648    } else {
00649       class = framelist[(int)fh->type];
00650    }
00651    if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
00652       sprintf(subclass2, "%c", fh->csub);
00653       subclass = subclass2;
00654    } else if (fh->type == AST_FRAME_IAX) {
00655          iax_frame_subclass2str((int)fh->csub, subclass2, sizeof(subclass2));
00656          subclass = subclass2;
00657    } else if (fh->type == AST_FRAME_CONTROL) {
00658       if (fh->csub >= ARRAY_LEN(cmds)) {
00659          snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00660          subclass = subclass2;
00661       } else {
00662          subclass = cmds[(int)fh->csub];
00663       }
00664    } else {
00665       snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
00666       subclass = subclass2;
00667    }
00668    snprintf(tmp, sizeof(tmp), 
00669        "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
00670        dir,
00671        retries, fh->oseqno, fh->iseqno, class, subclass);
00672    outputf(tmp);
00673    snprintf(tmp, sizeof(tmp), 
00674        "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
00675        (unsigned long)ntohl(fh->ts),
00676        ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
00677        ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
00678    outputf(tmp);
00679    if (fh->type == AST_FRAME_IAX)
00680       dump_ies(fh->iedata, datalen);
00681 }
00682 
00683 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
00684 {
00685    char tmp[256];
00686    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00687       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);
00688       errorf(tmp);
00689       return -1;
00690    }
00691    ied->buf[ied->pos++] = ie;
00692    ied->buf[ied->pos++] = datalen;
00693    memcpy(ied->buf + ied->pos, data, datalen);
00694    ied->pos += datalen;
00695    return 0;
00696 }
00697 
00698 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
00699 {
00700    return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00701 }
00702 
00703 int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value)
00704 {
00705    struct _local {
00706       unsigned char version;
00707       uint64_t value;
00708    } __attribute__((packed)) newval = { version, };
00709    put_unaligned_uint64(&newval.value, htonll(value));
00710    return iax_ie_append_raw(ied, ie, &newval, (int) sizeof(newval));
00711 }
00712 
00713 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
00714 {
00715    unsigned int newval;
00716    newval = htonl(value);
00717    return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00718 }
00719 
00720 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
00721 {
00722    unsigned short newval;
00723    newval = htons(value);
00724    return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00725 }
00726 
00727 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
00728 {
00729    return iax_ie_append_raw(ied, ie, str, strlen(str));
00730 }
00731 
00732 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
00733 {
00734    return iax_ie_append_raw(ied, ie, &dat, 1);
00735 }
00736 
00737 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
00738 {
00739    return iax_ie_append_raw(ied, ie, NULL, 0);
00740 }
00741 
00742 void iax_set_output(void (*func)(const char *))
00743 {
00744    outputf = func;
00745 }
00746 
00747 void iax_set_error(void (*func)(const char *))
00748 {
00749    errorf = func;
00750 }
00751 
00752 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
00753 {
00754    /* Parse data into information elements */
00755    int len;
00756    int ie;
00757    char tmp[256], *tmp2;
00758    struct ast_variable *var, *var2, *prev;
00759    unsigned int count;
00760    memset(ies, 0, (int)sizeof(struct iax_ies));
00761    ies->msgcount = -1;
00762    ies->firmwarever = -1;
00763    ies->calling_ton = -1;
00764    ies->calling_tns = -1;
00765    ies->calling_pres = -1;
00766    ies->samprate = IAX_RATE_8KHZ;
00767    while(datalen >= 2) {
00768       ie = data[0];
00769       len = data[1];
00770       if (len > datalen - 2) {
00771          errorf("Information element length exceeds message size\n");
00772          return -1;
00773       }
00774       switch(ie) {
00775       case IAX_IE_CALLED_NUMBER:
00776          ies->called_number = (char *)data + 2;
00777          break;
00778       case IAX_IE_CALLING_NUMBER:
00779          ies->calling_number = (char *)data + 2;
00780          break;
00781       case IAX_IE_CALLING_ANI:
00782          ies->calling_ani = (char *)data + 2;
00783          break;
00784       case IAX_IE_CALLING_NAME:
00785          ies->calling_name = (char *)data + 2;
00786          break;
00787       case IAX_IE_CALLED_CONTEXT:
00788          ies->called_context = (char *)data + 2;
00789          break;
00790       case IAX_IE_USERNAME:
00791          ies->username = (char *)data + 2;
00792          break;
00793       case IAX_IE_PASSWORD:
00794          ies->password = (char *)data + 2;
00795          break;
00796       case IAX_IE_CODEC_PREFS:
00797          ies->codec_prefs = (char *)data + 2;
00798          break;
00799       case IAX_IE_CAPABILITY:
00800          if (len != (int)sizeof(unsigned int)) {
00801             snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00802             errorf(tmp);
00803          } else if (ies->capability == 0) { /* Don't overwrite capability2, if specified */
00804             ies->capability = ntohl(get_unaligned_uint32(data + 2));
00805          }
00806          break;
00807       case IAX_IE_CAPABILITY2:
00808          {
00809             int version = data[2];
00810             if (version == 0) {
00811                if (len != (int)sizeof(char) + sizeof(format_t)) {
00812                   snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int) (sizeof(format_t) + sizeof(char)), len);
00813                   errorf(tmp);
00814                } else {
00815                   ies->capability = (format_t) ntohll(get_unaligned_uint64(data + 3));
00816                }
00817             } /* else unknown version */
00818          }
00819          break;
00820       case IAX_IE_FORMAT:
00821          if (len != (int)sizeof(unsigned int)) {
00822             snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00823             errorf(tmp);
00824          } else if (ies->format == 0) { /* Don't overwrite format2, if specified */
00825             ies->format = ntohl(get_unaligned_uint32(data + 2));
00826          }
00827          break;
00828       case IAX_IE_FORMAT2:
00829          {
00830             int version = data[2];
00831             if (version == 0) {
00832                if (len != (int)sizeof(char) + sizeof(format_t)) {
00833                   snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int) (sizeof(format_t) + sizeof(char)), len);
00834                   errorf(tmp);
00835                } else {
00836                   ies->format = (format_t) ntohll(get_unaligned_uint64(data + 3));
00837                }
00838             } /* else unknown version */
00839          }
00840          break;
00841       case IAX_IE_LANGUAGE:
00842          ies->language = (char *)data + 2;
00843          break;
00844       case IAX_IE_VERSION:
00845          if (len != (int)sizeof(unsigned short)) {
00846             snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00847             errorf(tmp);
00848          } else
00849             ies->version = ntohs(get_unaligned_uint16(data + 2));
00850          break;
00851       case IAX_IE_ADSICPE:
00852          if (len != (int)sizeof(unsigned short)) {
00853             snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00854             errorf(tmp);
00855          } else
00856             ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
00857          break;
00858       case IAX_IE_SAMPLINGRATE:
00859          if (len != (int)sizeof(unsigned short)) {
00860             snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00861             errorf(tmp);
00862          } else
00863             ies->samprate = ntohs(get_unaligned_uint16(data + 2));
00864          break;
00865       case IAX_IE_DNID:
00866          ies->dnid = (char *)data + 2;
00867          break;
00868       case IAX_IE_RDNIS:
00869          ies->rdnis = (char *)data + 2;
00870          break;
00871       case IAX_IE_AUTHMETHODS:
00872          if (len != (int)sizeof(unsigned short))  {
00873             snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00874             errorf(tmp);
00875          } else
00876             ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
00877          break;
00878       case IAX_IE_ENCRYPTION:
00879          if (len != (int)sizeof(unsigned short))  {
00880             snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00881             errorf(tmp);
00882          } else
00883             ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
00884          break;
00885       case IAX_IE_CHALLENGE:
00886          ies->challenge = (char *)data + 2;
00887          break;
00888       case IAX_IE_MD5_RESULT:
00889          ies->md5_result = (char *)data + 2;
00890          break;
00891       case IAX_IE_RSA_RESULT:
00892          ies->rsa_result = (char *)data + 2;
00893          break;
00894       case IAX_IE_APPARENT_ADDR:
00895          ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
00896          break;
00897       case IAX_IE_REFRESH:
00898          if (len != (int)sizeof(unsigned short)) {
00899             snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00900             errorf(tmp);
00901          } else
00902             ies->refresh = ntohs(get_unaligned_uint16(data + 2));
00903          break;
00904       case IAX_IE_DPSTATUS:
00905          if (len != (int)sizeof(unsigned short)) {
00906             snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00907             errorf(tmp);
00908          } else
00909             ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
00910          break;
00911       case IAX_IE_CALLNO:
00912          if (len != (int)sizeof(unsigned short)) {
00913             snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00914             errorf(tmp);
00915          } else
00916             ies->callno = ntohs(get_unaligned_uint16(data + 2));
00917          break;
00918       case IAX_IE_CAUSE:
00919          ies->cause = (char *)data + 2;
00920          break;
00921       case IAX_IE_CAUSECODE:
00922          if (len != 1) {
00923             snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
00924             errorf(tmp);
00925          } else {
00926             ies->causecode = data[2];
00927          }
00928          break;
00929       case IAX_IE_IAX_UNKNOWN:
00930          if (len == 1)
00931             ies->iax_unknown = data[2];
00932          else {
00933             snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00934             errorf(tmp);
00935          }
00936          break;
00937       case IAX_IE_MSGCOUNT:
00938          if (len != (int)sizeof(unsigned short)) {
00939             snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00940             errorf(tmp);
00941          } else
00942             ies->msgcount = ntohs(get_unaligned_uint16(data + 2));   
00943          break;
00944       case IAX_IE_AUTOANSWER:
00945          ies->autoanswer = 1;
00946          break;
00947       case IAX_IE_MUSICONHOLD:
00948          ies->musiconhold = 1;
00949          break;
00950       case IAX_IE_TRANSFERID:
00951          if (len != (int)sizeof(unsigned int)) {
00952             snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00953             errorf(tmp);
00954          } else
00955             ies->transferid = ntohl(get_unaligned_uint32(data + 2));
00956          break;
00957       case IAX_IE_DATETIME:
00958          if (len != (int)sizeof(unsigned int)) {
00959             snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00960             errorf(tmp);
00961          } else
00962             ies->datetime = ntohl(get_unaligned_uint32(data + 2));
00963          break;
00964       case IAX_IE_FIRMWAREVER:
00965          if (len != (int)sizeof(unsigned short)) {
00966             snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00967             errorf(tmp);
00968          } else
00969             ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));   
00970          break;
00971       case IAX_IE_DEVICETYPE:
00972          ies->devicetype = (char *)data + 2;
00973          break;
00974       case IAX_IE_SERVICEIDENT:
00975          ies->serviceident = (char *)data + 2;
00976          break;
00977       case IAX_IE_FWBLOCKDESC:
00978          if (len != (int)sizeof(unsigned int)) {
00979             snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00980             errorf(tmp);
00981          } else
00982             ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
00983          break;
00984       case IAX_IE_FWBLOCKDATA:
00985          ies->fwdata = data + 2;
00986          ies->fwdatalen = len;
00987          break;
00988       case IAX_IE_ENCKEY:
00989          ies->enckey = data + 2;
00990          ies->enckeylen = len;
00991          break;
00992       case IAX_IE_PROVVER:
00993          if (len != (int)sizeof(unsigned int)) {
00994             snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00995             errorf(tmp);
00996          } else {
00997             ies->provverpres = 1;
00998             ies->provver = ntohl(get_unaligned_uint32(data + 2));
00999          }
01000          break;
01001       case IAX_IE_CALLINGPRES:
01002          if (len == 1)
01003             ies->calling_pres = data[2];
01004          else {
01005             snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
01006             errorf(tmp);
01007          }
01008          break;
01009       case IAX_IE_CALLINGTON:
01010          if (len == 1)
01011             ies->calling_ton = data[2];
01012          else {
01013             snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
01014             errorf(tmp);
01015          }
01016          break;
01017       case IAX_IE_CALLINGTNS:
01018          if (len != (int)sizeof(unsigned short)) {
01019             snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
01020             errorf(tmp);
01021          } else
01022             ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));   
01023          break;
01024                case IAX_IE_RR_JITTER:
01025                        if (len != (int)sizeof(unsigned int)) {
01026                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
01027                                errorf(tmp);
01028                        } else {
01029                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
01030                        }
01031                        break;
01032                case IAX_IE_RR_LOSS:
01033                        if (len != (int)sizeof(unsigned int)) {
01034                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
01035                                errorf(tmp);
01036                        } else {
01037                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
01038                        }
01039                        break;
01040                case IAX_IE_RR_PKTS:
01041                        if (len != (int)sizeof(unsigned int)) {
01042                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
01043                                errorf(tmp);
01044                        } else {
01045                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
01046                        }
01047                        break;
01048                case IAX_IE_RR_DELAY:
01049                        if (len != (int)sizeof(unsigned short)) {
01050                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
01051                         errorf(tmp);
01052                        } else {
01053                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
01054                        }
01055                        break;
01056       case IAX_IE_RR_DROPPED:
01057          if (len != (int)sizeof(unsigned int)) {
01058             snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
01059             errorf(tmp);
01060          } else {
01061             ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
01062          }
01063          break;
01064       case IAX_IE_RR_OOO:
01065          if (len != (int)sizeof(unsigned int)) {
01066             snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
01067             errorf(tmp);
01068          } else {
01069             ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
01070          }
01071          break;
01072       case IAX_IE_VARIABLE:
01073          ast_copy_string(tmp, (char *)data + 2, len + 1);
01074          tmp2 = strchr(tmp, '=');
01075          if (tmp2)
01076             *tmp2++ = '\0';
01077          else
01078             tmp2 = "";
01079          {
01080             struct ast_str *str = ast_str_create(16);
01081             /* Existing variable or new variable? */
01082             for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
01083                if (strcmp(tmp, var2->name) == 0) {
01084                   ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
01085                   var = ast_variable_new(tmp, ast_str_buffer(str), var2->file);
01086                   var->next = var2->next;
01087                   if (prev) {
01088                      prev->next = var;
01089                   } else {
01090                      ies->vars = var;
01091                   }
01092                   snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
01093                   outputf(tmp);
01094                   ast_free(var2);
01095                   break;
01096                }
01097             }
01098             ast_free(str);
01099          }
01100 
01101          if (!var2) {
01102             var = ast_variable_new(tmp, tmp2, "");
01103             snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
01104             outputf(tmp);
01105             var->next = ies->vars;
01106             ies->vars = var;
01107          }
01108          break;
01109       case IAX_IE_OSPTOKEN:
01110          if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
01111             ies->osptokenblock[count] = (char *)data + 2 + 1;
01112             ies->ospblocklength[count] = len - 1;
01113          } else {
01114             snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
01115             errorf(tmp);
01116          }
01117          break;
01118       case IAX_IE_CALLTOKEN:
01119          if (len) {
01120             ies->calltokendata = (unsigned char *) data + 2;
01121          }
01122          ies->calltoken = 1;
01123          break;
01124       default:
01125          snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
01126          outputf(tmp);
01127       }
01128       /* Overwrite information element with 0, to null terminate previous portion */
01129       data[0] = 0;
01130       datalen -= (len + 2);
01131       data += (len + 2);
01132    }
01133    /* Null-terminate last field */
01134    *data = '\0';
01135    if (datalen) {
01136       errorf("Invalid information element contents, strange boundary\n");
01137       return -1;
01138    }
01139    return 0;
01140 }
01141 
01142 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
01143 {
01144    fr->af.frametype = f->frametype;
01145    fr->af.subclass.codec = f->subclass.codec;
01146    fr->af.mallocd = 0;           /* Our frame is static relative to the container */
01147    fr->af.datalen = f->datalen;
01148    fr->af.samples = f->samples;
01149    fr->af.offset = AST_FRIENDLY_OFFSET;
01150    fr->af.src = f->src;
01151    fr->af.delivery.tv_sec = 0;
01152    fr->af.delivery.tv_usec = 0;
01153    fr->af.data.ptr = fr->afdata;
01154    fr->af.len = f->len;
01155    if (fr->af.datalen) {
01156       size_t copy_len = fr->af.datalen;
01157       if (copy_len > fr->afdatalen) {
01158          ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
01159             (int) fr->afdatalen, (int) fr->af.datalen);
01160          copy_len = fr->afdatalen;
01161       }
01162 #if __BYTE_ORDER == __LITTLE_ENDIAN
01163       /* We need to byte-swap slinear samples from network byte order */
01164       if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass.codec == AST_FORMAT_SLINEAR)) {
01165          /* 2 bytes / sample for SLINEAR */
01166          ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
01167       } else
01168 #endif
01169          memcpy(fr->af.data.ptr, f->data.ptr, copy_len);
01170    }
01171 }
01172 
01173 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
01174 {
01175    struct iax_frame *fr = NULL;
01176 
01177 #if !defined(LOW_MEMORY)
01178    struct iax_frames *iax_frames = NULL;
01179    struct iax_frame *smallest = NULL;
01180 
01181    /* Attempt to get a frame from this thread's cache */
01182    if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01183       smallest = AST_LIST_FIRST(&iax_frames->list);
01184       AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
01185          if (fr->afdatalen >= datalen) {
01186             size_t afdatalen = fr->afdatalen;
01187             AST_LIST_REMOVE_CURRENT(list);
01188             iax_frames->size--;
01189             memset(fr, 0, sizeof(*fr));
01190             fr->afdatalen = afdatalen;
01191             break;
01192          } else if (smallest->afdatalen > fr->afdatalen) {
01193             smallest = fr;
01194          }
01195       }
01196       AST_LIST_TRAVERSE_SAFE_END;
01197    }
01198    if (!fr) {
01199       if (iax_frames && iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) {
01200          /* Make useless cache into something more useful */
01201          AST_LIST_REMOVE(&iax_frames->list, smallest, list);
01202          if (!(fr = ast_realloc(smallest, sizeof(*fr) + datalen))) {
01203             AST_LIST_INSERT_TAIL(&iax_frames->list, smallest, list);
01204             return NULL;
01205          }
01206       } else if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
01207          return NULL;
01208       fr->afdatalen = datalen;
01209    }
01210 #else
01211    if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
01212       return NULL;
01213    fr->afdatalen = datalen;
01214 #endif
01215 
01216 
01217    fr->direction = direction;
01218    fr->retrans = -1;
01219    fr->cacheable = cacheable;
01220    
01221    if (fr->direction == DIRECTION_INGRESS)
01222       ast_atomic_fetchadd_int(&iframes, 1);
01223    else
01224       ast_atomic_fetchadd_int(&oframes, 1);
01225    
01226    ast_atomic_fetchadd_int(&frames, 1);
01227 
01228    return fr;
01229 }
01230 
01231 void iax_frame_free(struct iax_frame *fr)
01232 {
01233 #if !defined(LOW_MEMORY)
01234    struct iax_frames *iax_frames = NULL;
01235 #endif
01236 
01237    /* Note: does not remove from scheduler! */
01238    if (fr->direction == DIRECTION_INGRESS)
01239       ast_atomic_fetchadd_int(&iframes, -1);
01240    else if (fr->direction == DIRECTION_OUTGRESS)
01241       ast_atomic_fetchadd_int(&oframes, -1);
01242    else {
01243       errorf("Attempt to double free frame detected\n");
01244       return;
01245    }
01246    ast_atomic_fetchadd_int(&frames, -1);
01247 
01248 #if !defined(LOW_MEMORY)
01249    if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01250       ast_free(fr);
01251       return;
01252    }
01253 
01254    if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
01255       fr->direction = 0;
01256       /* Pseudo-sort: keep smaller frames at the top of the list. This should
01257        * increase the chance that we pick the smallest applicable frame for use. */
01258       if (AST_LIST_FIRST(&iax_frames->list) && AST_LIST_FIRST(&iax_frames->list)->afdatalen < fr->afdatalen) {
01259          AST_LIST_INSERT_TAIL(&iax_frames->list, fr, list);
01260       } else {
01261          AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
01262       }
01263       iax_frames->size++;
01264       return;
01265    }
01266 #endif
01267    ast_free(fr);
01268 }
01269 
01270 #if !defined(LOW_MEMORY)
01271 static void frame_cache_cleanup(void *data)
01272 {
01273    struct iax_frames *framelist = data;
01274    struct iax_frame *current;
01275 
01276    while ((current = AST_LIST_REMOVE_HEAD(&framelist->list, list)))
01277       ast_free(current);
01278 
01279    ast_free(framelist);
01280 }
01281 #endif
01282 
01283 int iax_get_frames(void) { return frames; }
01284 int iax_get_iframes(void) { return iframes; }
01285 int iax_get_oframes(void) { return oframes; }

Generated on Mon Oct 8 12:39:03 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7