Wed Oct 28 11:45:38 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: 216003 $")
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    case IAX_COMMAND_CALLTOKEN:
00524       cmd = "CTOKEN ";
00525       break;
00526    }
00527    ast_copy_string(str, cmd, len);
00528 }
00529 
00530 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
00531 {
00532    const char *frames[] = {
00533       "(0?)",
00534       "DTMF_E ",
00535       "VOICE  ",
00536       "VIDEO  ",
00537       "CONTROL",
00538       "NULL   ",
00539       "IAX    ",
00540       "TEXT   ",
00541       "IMAGE  ",
00542       "HTML   ",
00543       "CNG    ",
00544       "MODEM  ",
00545       "DTMF_B ",
00546    };
00547    const char *cmds[] = {
00548       "(0?)",
00549       "HANGUP ",
00550       "RING   ",
00551       "RINGING",
00552       "ANSWER ",
00553       "BUSY   ",
00554       "TKOFFHK",
00555       "OFFHOOK",
00556       "CONGSTN",
00557       "FLASH  ",
00558       "WINK   ",
00559       "OPTION ",
00560       "RDKEY  ",
00561       "RDUNKEY",
00562       "PROGRES",
00563       "PROCDNG",
00564       "HOLD   ",
00565       "UNHOLD ",
00566       "VIDUPDT", };
00567    struct ast_iax2_full_hdr *fh;
00568    char retries[20];
00569    char class2[20];
00570    char subclass2[20];
00571    const char *class;
00572    const char *subclass;
00573    char *dir;
00574    char tmp[512];
00575 
00576    switch(rx) {
00577    case 0:
00578       dir = "Tx";
00579       break;
00580    case 2:
00581       dir = "TE";
00582       break;
00583    case 3:
00584       dir = "RD";
00585       break;
00586    default:
00587       dir = "Rx";
00588       break;
00589    }
00590    if (f) {
00591       fh = f->data;
00592       snprintf(retries, sizeof(retries), "%03d", f->retries);
00593    } else {
00594       fh = fhi;
00595       if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
00596          strcpy(retries, "Yes");
00597       else
00598          strcpy(retries, " No");
00599    }
00600    if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
00601       /* Don't mess with mini-frames */
00602       return;
00603    }
00604    if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
00605       snprintf(class2, sizeof(class2), "(%d?)", fh->type);
00606       class = class2;
00607    } else {
00608       class = frames[(int)fh->type];
00609    }
00610    if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
00611       sprintf(subclass2, "%c", fh->csub);
00612       subclass = subclass2;
00613    } else if (fh->type == AST_FRAME_IAX) {
00614          iax_frame_subclass2str((int)fh->csub, subclass2, sizeof(subclass2));
00615          subclass = subclass2;
00616    } else if (fh->type == AST_FRAME_CONTROL) {
00617       if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
00618          snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00619          subclass = subclass2;
00620       } else {
00621          subclass = cmds[(int)fh->csub];
00622       }
00623    } else {
00624       snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
00625       subclass = subclass2;
00626    }
00627    snprintf(tmp, sizeof(tmp), 
00628        "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
00629        dir,
00630        retries, fh->oseqno, fh->iseqno, class, subclass);
00631    outputf(tmp);
00632    snprintf(tmp, sizeof(tmp), 
00633        "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
00634        (unsigned long)ntohl(fh->ts),
00635        ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
00636        ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
00637    outputf(tmp);
00638    if (fh->type == AST_FRAME_IAX)
00639       dump_ies(fh->iedata, datalen);
00640 }
00641 
00642 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
00643 {
00644    char tmp[256];
00645    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00646       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);
00647       errorf(tmp);
00648       return -1;
00649    }
00650    ied->buf[ied->pos++] = ie;
00651    ied->buf[ied->pos++] = datalen;
00652    memcpy(ied->buf + ied->pos, data, datalen);
00653    ied->pos += datalen;
00654    return 0;
00655 }
00656 
00657 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
00658 {
00659    return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00660 }
00661 
00662 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
00663 {
00664    unsigned int newval;
00665    newval = htonl(value);
00666    return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00667 }
00668 
00669 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
00670 {
00671    unsigned short newval;
00672    newval = htons(value);
00673    return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00674 }
00675 
00676 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
00677 {
00678    return iax_ie_append_raw(ied, ie, str, strlen(str));
00679 }
00680 
00681 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
00682 {
00683    return iax_ie_append_raw(ied, ie, &dat, 1);
00684 }
00685 
00686 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
00687 {
00688    return iax_ie_append_raw(ied, ie, NULL, 0);
00689 }
00690 
00691 void iax_set_output(void (*func)(const char *))
00692 {
00693    outputf = func;
00694 }
00695 
00696 void iax_set_error(void (*func)(const char *))
00697 {
00698    errorf = func;
00699 }
00700 
00701 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
00702 {
00703    /* Parse data into information elements */
00704    int len;
00705    int ie;
00706    char tmp[256], *tmp2;
00707    struct ast_variable *var, *var2, *prev;
00708    unsigned int count;
00709    memset(ies, 0, (int)sizeof(struct iax_ies));
00710    ies->msgcount = -1;
00711    ies->firmwarever = -1;
00712    ies->calling_ton = -1;
00713    ies->calling_tns = -1;
00714    ies->calling_pres = -1;
00715    ies->samprate = IAX_RATE_8KHZ;
00716    while(datalen >= 2) {
00717       ie = data[0];
00718       len = data[1];
00719       if (len > datalen - 2) {
00720          errorf("Information element length exceeds message size\n");
00721          return -1;
00722       }
00723       switch(ie) {
00724       case IAX_IE_CALLED_NUMBER:
00725          ies->called_number = (char *)data + 2;
00726          break;
00727       case IAX_IE_CALLING_NUMBER:
00728          ies->calling_number = (char *)data + 2;
00729          break;
00730       case IAX_IE_CALLING_ANI:
00731          ies->calling_ani = (char *)data + 2;
00732          break;
00733       case IAX_IE_CALLING_NAME:
00734          ies->calling_name = (char *)data + 2;
00735          break;
00736       case IAX_IE_CALLED_CONTEXT:
00737          ies->called_context = (char *)data + 2;
00738          break;
00739       case IAX_IE_USERNAME:
00740          ies->username = (char *)data + 2;
00741          break;
00742       case IAX_IE_PASSWORD:
00743          ies->password = (char *)data + 2;
00744          break;
00745       case IAX_IE_CODEC_PREFS:
00746          ies->codec_prefs = (char *)data + 2;
00747          break;
00748       case IAX_IE_CAPABILITY:
00749          if (len != (int)sizeof(unsigned int)) {
00750             snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00751             errorf(tmp);
00752          } else
00753             ies->capability = ntohl(get_unaligned_uint32(data + 2));
00754          break;
00755       case IAX_IE_FORMAT:
00756          if (len != (int)sizeof(unsigned int)) {
00757             snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00758             errorf(tmp);
00759          } else
00760             ies->format = ntohl(get_unaligned_uint32(data + 2));
00761          break;
00762       case IAX_IE_LANGUAGE:
00763          ies->language = (char *)data + 2;
00764          break;
00765       case IAX_IE_VERSION:
00766          if (len != (int)sizeof(unsigned short)) {
00767             snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00768             errorf(tmp);
00769          } else
00770             ies->version = ntohs(get_unaligned_uint16(data + 2));
00771          break;
00772       case IAX_IE_ADSICPE:
00773          if (len != (int)sizeof(unsigned short)) {
00774             snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00775             errorf(tmp);
00776          } else
00777             ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
00778          break;
00779       case IAX_IE_SAMPLINGRATE:
00780          if (len != (int)sizeof(unsigned short)) {
00781             snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00782             errorf(tmp);
00783          } else
00784             ies->samprate = ntohs(get_unaligned_uint16(data + 2));
00785          break;
00786       case IAX_IE_DNID:
00787          ies->dnid = (char *)data + 2;
00788          break;
00789       case IAX_IE_RDNIS:
00790          ies->rdnis = (char *)data + 2;
00791          break;
00792       case IAX_IE_AUTHMETHODS:
00793          if (len != (int)sizeof(unsigned short))  {
00794             snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00795             errorf(tmp);
00796          } else
00797             ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
00798          break;
00799       case IAX_IE_ENCRYPTION:
00800          if (len != (int)sizeof(unsigned short))  {
00801             snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00802             errorf(tmp);
00803          } else
00804             ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
00805          break;
00806       case IAX_IE_CHALLENGE:
00807          ies->challenge = (char *)data + 2;
00808          break;
00809       case IAX_IE_MD5_RESULT:
00810          ies->md5_result = (char *)data + 2;
00811          break;
00812       case IAX_IE_RSA_RESULT:
00813          ies->rsa_result = (char *)data + 2;
00814          break;
00815       case IAX_IE_APPARENT_ADDR:
00816          ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
00817          break;
00818       case IAX_IE_REFRESH:
00819          if (len != (int)sizeof(unsigned short)) {
00820             snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00821             errorf(tmp);
00822          } else
00823             ies->refresh = ntohs(get_unaligned_uint16(data + 2));
00824          break;
00825       case IAX_IE_DPSTATUS:
00826          if (len != (int)sizeof(unsigned short)) {
00827             snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00828             errorf(tmp);
00829          } else
00830             ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
00831          break;
00832       case IAX_IE_CALLNO:
00833          if (len != (int)sizeof(unsigned short)) {
00834             snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00835             errorf(tmp);
00836          } else
00837             ies->callno = ntohs(get_unaligned_uint16(data + 2));
00838          break;
00839       case IAX_IE_CAUSE:
00840          ies->cause = (char *)data + 2;
00841          break;
00842       case IAX_IE_CAUSECODE:
00843          if (len != 1) {
00844             snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
00845             errorf(tmp);
00846          } else {
00847             ies->causecode = data[2];
00848          }
00849          break;
00850       case IAX_IE_IAX_UNKNOWN:
00851          if (len == 1)
00852             ies->iax_unknown = data[2];
00853          else {
00854             snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00855             errorf(tmp);
00856          }
00857          break;
00858       case IAX_IE_MSGCOUNT:
00859          if (len != (int)sizeof(unsigned short)) {
00860             snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00861             errorf(tmp);
00862          } else
00863             ies->msgcount = ntohs(get_unaligned_uint16(data + 2));   
00864          break;
00865       case IAX_IE_AUTOANSWER:
00866          ies->autoanswer = 1;
00867          break;
00868       case IAX_IE_MUSICONHOLD:
00869          ies->musiconhold = 1;
00870          break;
00871       case IAX_IE_TRANSFERID:
00872          if (len != (int)sizeof(unsigned int)) {
00873             snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00874             errorf(tmp);
00875          } else
00876             ies->transferid = ntohl(get_unaligned_uint32(data + 2));
00877          break;
00878       case IAX_IE_DATETIME:
00879          if (len != (int)sizeof(unsigned int)) {
00880             snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00881             errorf(tmp);
00882          } else
00883             ies->datetime = ntohl(get_unaligned_uint32(data + 2));
00884          break;
00885       case IAX_IE_FIRMWAREVER:
00886          if (len != (int)sizeof(unsigned short)) {
00887             snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00888             errorf(tmp);
00889          } else
00890             ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));   
00891          break;
00892       case IAX_IE_DEVICETYPE:
00893          ies->devicetype = (char *)data + 2;
00894          break;
00895       case IAX_IE_SERVICEIDENT:
00896          ies->serviceident = (char *)data + 2;
00897          break;
00898       case IAX_IE_FWBLOCKDESC:
00899          if (len != (int)sizeof(unsigned int)) {
00900             snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00901             errorf(tmp);
00902          } else
00903             ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
00904          break;
00905       case IAX_IE_FWBLOCKDATA:
00906          ies->fwdata = data + 2;
00907          ies->fwdatalen = len;
00908          break;
00909       case IAX_IE_ENCKEY:
00910          ies->enckey = data + 2;
00911          ies->enckeylen = len;
00912          break;
00913       case IAX_IE_PROVVER:
00914          if (len != (int)sizeof(unsigned int)) {
00915             snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00916             errorf(tmp);
00917          } else {
00918             ies->provverpres = 1;
00919             ies->provver = ntohl(get_unaligned_uint32(data + 2));
00920          }
00921          break;
00922       case IAX_IE_CALLINGPRES:
00923          if (len == 1)
00924             ies->calling_pres = data[2];
00925          else {
00926             snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
00927             errorf(tmp);
00928          }
00929          break;
00930       case IAX_IE_CALLINGTON:
00931          if (len == 1)
00932             ies->calling_ton = data[2];
00933          else {
00934             snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
00935             errorf(tmp);
00936          }
00937          break;
00938       case IAX_IE_CALLINGTNS:
00939          if (len != (int)sizeof(unsigned short)) {
00940             snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00941             errorf(tmp);
00942          } else
00943             ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));   
00944          break;
00945                case IAX_IE_RR_JITTER:
00946                        if (len != (int)sizeof(unsigned int)) {
00947                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00948                                errorf(tmp);
00949                        } else {
00950                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
00951                        }
00952                        break;
00953                case IAX_IE_RR_LOSS:
00954                        if (len != (int)sizeof(unsigned int)) {
00955                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00956                                errorf(tmp);
00957                        } else {
00958                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
00959                        }
00960                        break;
00961                case IAX_IE_RR_PKTS:
00962                        if (len != (int)sizeof(unsigned int)) {
00963                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00964                                errorf(tmp);
00965                        } else {
00966                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
00967                        }
00968                        break;
00969                case IAX_IE_RR_DELAY:
00970                        if (len != (int)sizeof(unsigned short)) {
00971                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00972                         errorf(tmp);
00973                        } else {
00974                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
00975                        }
00976                        break;
00977       case IAX_IE_RR_DROPPED:
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_dropped = ntohl(get_unaligned_uint32(data + 2));
00983          }
00984          break;
00985       case IAX_IE_RR_OOO:
00986          if (len != (int)sizeof(unsigned int)) {
00987             snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00988             errorf(tmp);
00989          } else {
00990             ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
00991          }
00992          break;
00993       case IAX_IE_VARIABLE:
00994          ast_copy_string(tmp, (char *)data + 2, len + 1);
00995          tmp2 = strchr(tmp, '=');
00996          if (tmp2)
00997             *tmp2++ = '\0';
00998          else
00999             tmp2 = "";
01000          {
01001             struct ast_str *str = ast_str_create(16);
01002             /* Existing variable or new variable? */
01003             for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
01004                if (strcmp(tmp, var2->name) == 0) {
01005                   ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
01006                   var = ast_variable_new(tmp, str->str, var2->file);
01007                   var->next = var2->next;
01008                   if (prev)
01009                      prev->next = var;
01010                   else
01011                      ies->vars = var;
01012                   ast_free(var2);
01013                   break;
01014                }
01015             }
01016          }
01017          if (!var2) {
01018             var = ast_variable_new(tmp, tmp2, "");
01019             var->next = ies->vars;
01020             ies->vars = var;
01021          }
01022          break;
01023       case IAX_IE_OSPTOKEN:
01024          if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
01025             ies->osptokenblock[count] = (char *)data + 2 + 1;
01026             ies->ospblocklength[count] = len - 1;
01027          } else {
01028             snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
01029             errorf(tmp);
01030          }
01031          break;
01032       case IAX_IE_CALLTOKEN:
01033          if (len) {
01034             ies->calltokendata = (unsigned char *) data + 2;
01035          }
01036          ies->calltoken = 1;
01037          break;
01038       default:
01039          snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
01040          outputf(tmp);
01041       }
01042       /* Overwrite information element with 0, to null terminate previous portion */
01043       data[0] = 0;
01044       datalen -= (len + 2);
01045       data += (len + 2);
01046    }
01047    /* Null-terminate last field */
01048    *data = '\0';
01049    if (datalen) {
01050       errorf("Invalid information element contents, strange boundary\n");
01051       return -1;
01052    }
01053    return 0;
01054 }
01055 
01056 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
01057 {
01058    fr->af.frametype = f->frametype;
01059    fr->af.subclass = f->subclass;
01060    fr->af.mallocd = 0;           /* Our frame is static relative to the container */
01061    fr->af.datalen = f->datalen;
01062    fr->af.samples = f->samples;
01063    fr->af.offset = AST_FRIENDLY_OFFSET;
01064    fr->af.src = f->src;
01065    fr->af.delivery.tv_sec = 0;
01066    fr->af.delivery.tv_usec = 0;
01067    fr->af.data = fr->afdata;
01068    fr->af.len = f->len;
01069    if (fr->af.datalen) {
01070       size_t copy_len = fr->af.datalen;
01071       if (copy_len > fr->afdatalen) {
01072          ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
01073             (int) fr->afdatalen, (int) fr->af.datalen);
01074          copy_len = fr->afdatalen;
01075       }
01076 #if __BYTE_ORDER == __LITTLE_ENDIAN
01077       /* We need to byte-swap slinear samples from network byte order */
01078       if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
01079          /* 2 bytes / sample for SLINEAR */
01080          ast_swapcopy_samples(fr->af.data, f->data, copy_len / 2);
01081       } else
01082 #endif
01083          memcpy(fr->af.data, f->data, copy_len);
01084    }
01085 }
01086 
01087 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
01088 {
01089    struct iax_frame *fr = NULL;
01090 
01091 #if !defined(LOW_MEMORY)
01092    struct iax_frames *iax_frames = NULL;
01093 
01094    /* Attempt to get a frame from this thread's cache */
01095    if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01096       AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
01097          if (fr->afdatalen >= datalen) {
01098             size_t afdatalen = fr->afdatalen;
01099             AST_LIST_REMOVE_CURRENT(list);
01100             iax_frames->size--;
01101             memset(fr, 0, sizeof(*fr));
01102             fr->afdatalen = afdatalen;
01103             break;
01104          }
01105       }
01106       AST_LIST_TRAVERSE_SAFE_END;
01107    }
01108    if (!fr) {
01109       if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
01110          return NULL;
01111       fr->afdatalen = datalen;
01112    }
01113 #else
01114    if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
01115       return NULL;
01116    fr->afdatalen = datalen;
01117 #endif
01118 
01119 
01120    fr->direction = direction;
01121    fr->retrans = -1;
01122    fr->cacheable = cacheable;
01123    
01124    if (fr->direction == DIRECTION_INGRESS)
01125       ast_atomic_fetchadd_int(&iframes, 1);
01126    else
01127       ast_atomic_fetchadd_int(&oframes, 1);
01128    
01129    ast_atomic_fetchadd_int(&frames, 1);
01130 
01131    return fr;
01132 }
01133 
01134 void iax_frame_free(struct iax_frame *fr)
01135 {
01136 #if !defined(LOW_MEMORY)
01137    struct iax_frames *iax_frames = NULL;
01138 #endif
01139 
01140    /* Note: does not remove from scheduler! */
01141    if (fr->direction == DIRECTION_INGRESS)
01142       ast_atomic_fetchadd_int(&iframes, -1);
01143    else if (fr->direction == DIRECTION_OUTGRESS)
01144       ast_atomic_fetchadd_int(&oframes, -1);
01145    else {
01146       errorf("Attempt to double free frame detected\n");
01147       return;
01148    }
01149    ast_atomic_fetchadd_int(&frames, -1);
01150 
01151 #if !defined(LOW_MEMORY)
01152    if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01153       ast_free(fr);
01154       return;
01155    }
01156 
01157    if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
01158       fr->direction = 0;
01159       AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
01160       iax_frames->size++;
01161       return;
01162    }
01163 #endif
01164    ast_free(fr);
01165 }
01166 
01167 #if !defined(LOW_MEMORY)
01168 static void frame_cache_cleanup(void *data)
01169 {
01170    struct iax_frames *frames = data;
01171    struct iax_frame *cur;
01172 
01173    while ((cur = AST_LIST_REMOVE_HEAD(&frames->list, list)))
01174       ast_free(cur);
01175 
01176    ast_free(frames);
01177 }
01178 #endif
01179 
01180 int iax_get_frames(void) { return frames; }
01181 int iax_get_iframes(void) { return iframes; }
01182 int iax_get_oframes(void) { return oframes; }

Generated on Wed Oct 28 11:45:38 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6