Mon Jun 27 16:50:54 2011

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

Generated on Mon Jun 27 16:50:54 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7