Thu Jul 9 13:40:35 2009

Asterisk developer's documentation


iax2-parser.c

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

Generated on Thu Jul 9 13:40:35 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7