Thu Apr 28 2011 17:13:34

Asterisk developer's documentation


iax2-parser.c

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