Wed Aug 18 22:33:52 2010

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

Generated on Wed Aug 18 22:33:52 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7