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