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