Sat Apr 26 2014 22:01:37

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