Tue Jul 14 23:09:50 2009

Asterisk developer's documentation


iax2-parser.c

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

Generated on Tue Jul 14 23:09:50 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7