Thu Sep 7 01:03:01 2017

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

Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1