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: 243945 $")
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 "T38 ",
00581 "SRCUPDT",
00582 };
00583 struct ast_iax2_full_hdr *fh;
00584 char retries[20];
00585 char class2[20];
00586 char subclass2[20];
00587 const char *class;
00588 const char *subclass;
00589 char *dir;
00590 char tmp[512];
00591
00592 switch(rx) {
00593 case 0:
00594 dir = "Tx";
00595 break;
00596 case 2:
00597 dir = "TE";
00598 break;
00599 case 3:
00600 dir = "RD";
00601 break;
00602 default:
00603 dir = "Rx";
00604 break;
00605 }
00606 if (f) {
00607 fh = f->data;
00608 snprintf(retries, sizeof(retries), "%03d", f->retries);
00609 } else {
00610 fh = fhi;
00611 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
00612 strcpy(retries, "Yes");
00613 else
00614 strcpy(retries, " No");
00615 }
00616 if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
00617
00618 return;
00619 }
00620 if (fh->type >= ARRAY_LEN(framelist)) {
00621 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
00622 class = class2;
00623 } else {
00624 class = framelist[(int)fh->type];
00625 }
00626 if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
00627 sprintf(subclass2, "%c", fh->csub);
00628 subclass = subclass2;
00629 } else if (fh->type == AST_FRAME_IAX) {
00630 iax_frame_subclass2str((int)fh->csub, subclass2, sizeof(subclass2));
00631 subclass = subclass2;
00632 } else if (fh->type == AST_FRAME_CONTROL) {
00633 if (fh->csub >= ARRAY_LEN(cmds)) {
00634 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00635 subclass = subclass2;
00636 } else {
00637 subclass = cmds[(int)fh->csub];
00638 }
00639 } else {
00640 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
00641 subclass = subclass2;
00642 }
00643 snprintf(tmp, sizeof(tmp),
00644 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
00645 dir,
00646 retries, fh->oseqno, fh->iseqno, class, subclass);
00647 outputf(tmp);
00648 snprintf(tmp, sizeof(tmp),
00649 " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
00650 (unsigned long)ntohl(fh->ts),
00651 ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
00652 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
00653 outputf(tmp);
00654 if (fh->type == AST_FRAME_IAX)
00655 dump_ies(fh->iedata, datalen);
00656 }
00657
00658 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
00659 {
00660 char tmp[256];
00661 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00662 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);
00663 errorf(tmp);
00664 return -1;
00665 }
00666 ied->buf[ied->pos++] = ie;
00667 ied->buf[ied->pos++] = datalen;
00668 memcpy(ied->buf + ied->pos, data, datalen);
00669 ied->pos += datalen;
00670 return 0;
00671 }
00672
00673 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
00674 {
00675 return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00676 }
00677
00678 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
00679 {
00680 unsigned int newval;
00681 newval = htonl(value);
00682 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00683 }
00684
00685 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
00686 {
00687 unsigned short newval;
00688 newval = htons(value);
00689 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00690 }
00691
00692 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
00693 {
00694 return iax_ie_append_raw(ied, ie, str, strlen(str));
00695 }
00696
00697 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
00698 {
00699 return iax_ie_append_raw(ied, ie, &dat, 1);
00700 }
00701
00702 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
00703 {
00704 return iax_ie_append_raw(ied, ie, NULL, 0);
00705 }
00706
00707 void iax_set_output(void (*func)(const char *))
00708 {
00709 outputf = func;
00710 }
00711
00712 void iax_set_error(void (*func)(const char *))
00713 {
00714 errorf = func;
00715 }
00716
00717 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
00718 {
00719
00720 int len;
00721 int ie;
00722 char tmp[256], *tmp2;
00723 struct ast_variable *var, *var2, *prev;
00724 unsigned int count;
00725 memset(ies, 0, (int)sizeof(struct iax_ies));
00726 ies->msgcount = -1;
00727 ies->firmwarever = -1;
00728 ies->calling_ton = -1;
00729 ies->calling_tns = -1;
00730 ies->calling_pres = -1;
00731 ies->samprate = IAX_RATE_8KHZ;
00732 while(datalen >= 2) {
00733 ie = data[0];
00734 len = data[1];
00735 if (len > datalen - 2) {
00736 errorf("Information element length exceeds message size\n");
00737 return -1;
00738 }
00739 switch(ie) {
00740 case IAX_IE_CALLED_NUMBER:
00741 ies->called_number = (char *)data + 2;
00742 break;
00743 case IAX_IE_CALLING_NUMBER:
00744 ies->calling_number = (char *)data + 2;
00745 break;
00746 case IAX_IE_CALLING_ANI:
00747 ies->calling_ani = (char *)data + 2;
00748 break;
00749 case IAX_IE_CALLING_NAME:
00750 ies->calling_name = (char *)data + 2;
00751 break;
00752 case IAX_IE_CALLED_CONTEXT:
00753 ies->called_context = (char *)data + 2;
00754 break;
00755 case IAX_IE_USERNAME:
00756 ies->username = (char *)data + 2;
00757 break;
00758 case IAX_IE_PASSWORD:
00759 ies->password = (char *)data + 2;
00760 break;
00761 case IAX_IE_CODEC_PREFS:
00762 ies->codec_prefs = (char *)data + 2;
00763 break;
00764 case IAX_IE_CAPABILITY:
00765 if (len != (int)sizeof(unsigned int)) {
00766 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00767 errorf(tmp);
00768 } else
00769 ies->capability = ntohl(get_unaligned_uint32(data + 2));
00770 break;
00771 case IAX_IE_FORMAT:
00772 if (len != (int)sizeof(unsigned int)) {
00773 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00774 errorf(tmp);
00775 } else
00776 ies->format = ntohl(get_unaligned_uint32(data + 2));
00777 break;
00778 case IAX_IE_LANGUAGE:
00779 ies->language = (char *)data + 2;
00780 break;
00781 case IAX_IE_VERSION:
00782 if (len != (int)sizeof(unsigned short)) {
00783 snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00784 errorf(tmp);
00785 } else
00786 ies->version = ntohs(get_unaligned_uint16(data + 2));
00787 break;
00788 case IAX_IE_ADSICPE:
00789 if (len != (int)sizeof(unsigned short)) {
00790 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00791 errorf(tmp);
00792 } else
00793 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
00794 break;
00795 case IAX_IE_SAMPLINGRATE:
00796 if (len != (int)sizeof(unsigned short)) {
00797 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00798 errorf(tmp);
00799 } else
00800 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
00801 break;
00802 case IAX_IE_DNID:
00803 ies->dnid = (char *)data + 2;
00804 break;
00805 case IAX_IE_RDNIS:
00806 ies->rdnis = (char *)data + 2;
00807 break;
00808 case IAX_IE_AUTHMETHODS:
00809 if (len != (int)sizeof(unsigned short)) {
00810 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00811 errorf(tmp);
00812 } else
00813 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
00814 break;
00815 case IAX_IE_ENCRYPTION:
00816 if (len != (int)sizeof(unsigned short)) {
00817 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00818 errorf(tmp);
00819 } else
00820 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
00821 break;
00822 case IAX_IE_CHALLENGE:
00823 ies->challenge = (char *)data + 2;
00824 break;
00825 case IAX_IE_MD5_RESULT:
00826 ies->md5_result = (char *)data + 2;
00827 break;
00828 case IAX_IE_RSA_RESULT:
00829 ies->rsa_result = (char *)data + 2;
00830 break;
00831 case IAX_IE_APPARENT_ADDR:
00832 ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
00833 break;
00834 case IAX_IE_REFRESH:
00835 if (len != (int)sizeof(unsigned short)) {
00836 snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00837 errorf(tmp);
00838 } else
00839 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
00840 break;
00841 case IAX_IE_DPSTATUS:
00842 if (len != (int)sizeof(unsigned short)) {
00843 snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00844 errorf(tmp);
00845 } else
00846 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
00847 break;
00848 case IAX_IE_CALLNO:
00849 if (len != (int)sizeof(unsigned short)) {
00850 snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00851 errorf(tmp);
00852 } else
00853 ies->callno = ntohs(get_unaligned_uint16(data + 2));
00854 break;
00855 case IAX_IE_CAUSE:
00856 ies->cause = (char *)data + 2;
00857 break;
00858 case IAX_IE_CAUSECODE:
00859 if (len != 1) {
00860 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
00861 errorf(tmp);
00862 } else {
00863 ies->causecode = data[2];
00864 }
00865 break;
00866 case IAX_IE_IAX_UNKNOWN:
00867 if (len == 1)
00868 ies->iax_unknown = data[2];
00869 else {
00870 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00871 errorf(tmp);
00872 }
00873 break;
00874 case IAX_IE_MSGCOUNT:
00875 if (len != (int)sizeof(unsigned short)) {
00876 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00877 errorf(tmp);
00878 } else
00879 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));
00880 break;
00881 case IAX_IE_AUTOANSWER:
00882 ies->autoanswer = 1;
00883 break;
00884 case IAX_IE_MUSICONHOLD:
00885 ies->musiconhold = 1;
00886 break;
00887 case IAX_IE_TRANSFERID:
00888 if (len != (int)sizeof(unsigned int)) {
00889 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00890 errorf(tmp);
00891 } else
00892 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
00893 break;
00894 case IAX_IE_DATETIME:
00895 if (len != (int)sizeof(unsigned int)) {
00896 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00897 errorf(tmp);
00898 } else
00899 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
00900 break;
00901 case IAX_IE_FIRMWAREVER:
00902 if (len != (int)sizeof(unsigned short)) {
00903 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00904 errorf(tmp);
00905 } else
00906 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));
00907 break;
00908 case IAX_IE_DEVICETYPE:
00909 ies->devicetype = (char *)data + 2;
00910 break;
00911 case IAX_IE_SERVICEIDENT:
00912 ies->serviceident = (char *)data + 2;
00913 break;
00914 case IAX_IE_FWBLOCKDESC:
00915 if (len != (int)sizeof(unsigned int)) {
00916 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00917 errorf(tmp);
00918 } else
00919 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
00920 break;
00921 case IAX_IE_FWBLOCKDATA:
00922 ies->fwdata = data + 2;
00923 ies->fwdatalen = len;
00924 break;
00925 case IAX_IE_ENCKEY:
00926 ies->enckey = data + 2;
00927 ies->enckeylen = len;
00928 break;
00929 case IAX_IE_PROVVER:
00930 if (len != (int)sizeof(unsigned int)) {
00931 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00932 errorf(tmp);
00933 } else {
00934 ies->provverpres = 1;
00935 ies->provver = ntohl(get_unaligned_uint32(data + 2));
00936 }
00937 break;
00938 case IAX_IE_CALLINGPRES:
00939 if (len == 1)
00940 ies->calling_pres = data[2];
00941 else {
00942 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
00943 errorf(tmp);
00944 }
00945 break;
00946 case IAX_IE_CALLINGTON:
00947 if (len == 1)
00948 ies->calling_ton = data[2];
00949 else {
00950 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
00951 errorf(tmp);
00952 }
00953 break;
00954 case IAX_IE_CALLINGTNS:
00955 if (len != (int)sizeof(unsigned short)) {
00956 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00957 errorf(tmp);
00958 } else
00959 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));
00960 break;
00961 case IAX_IE_RR_JITTER:
00962 if (len != (int)sizeof(unsigned int)) {
00963 snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00964 errorf(tmp);
00965 } else {
00966 ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
00967 }
00968 break;
00969 case IAX_IE_RR_LOSS:
00970 if (len != (int)sizeof(unsigned int)) {
00971 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00972 errorf(tmp);
00973 } else {
00974 ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
00975 }
00976 break;
00977 case IAX_IE_RR_PKTS:
00978 if (len != (int)sizeof(unsigned int)) {
00979 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00980 errorf(tmp);
00981 } else {
00982 ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
00983 }
00984 break;
00985 case IAX_IE_RR_DELAY:
00986 if (len != (int)sizeof(unsigned short)) {
00987 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00988 errorf(tmp);
00989 } else {
00990 ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
00991 }
00992 break;
00993 case IAX_IE_RR_DROPPED:
00994 if (len != (int)sizeof(unsigned int)) {
00995 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00996 errorf(tmp);
00997 } else {
00998 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
00999 }
01000 break;
01001 case IAX_IE_RR_OOO:
01002 if (len != (int)sizeof(unsigned int)) {
01003 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
01004 errorf(tmp);
01005 } else {
01006 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
01007 }
01008 break;
01009 case IAX_IE_VARIABLE:
01010 ast_copy_string(tmp, (char *)data + 2, len + 1);
01011 tmp2 = strchr(tmp, '=');
01012 if (tmp2)
01013 *tmp2++ = '\0';
01014 else
01015 tmp2 = "";
01016 {
01017 struct ast_str *str = ast_str_create(16);
01018
01019 for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
01020 if (strcmp(tmp, var2->name) == 0) {
01021 ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
01022 var = ast_variable_new(tmp, ast_str_buffer(str), var2->file);
01023 var->next = var2->next;
01024 if (prev) {
01025 prev->next = var;
01026 } else {
01027 ies->vars = var;
01028 }
01029 snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
01030 outputf(tmp);
01031 ast_free(var2);
01032 break;
01033 }
01034 }
01035 ast_free(str);
01036 }
01037
01038 if (!var2) {
01039 var = ast_variable_new(tmp, tmp2, "");
01040 snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
01041 outputf(tmp);
01042 var->next = ies->vars;
01043 ies->vars = var;
01044 }
01045 break;
01046 case IAX_IE_OSPTOKEN:
01047 if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
01048 ies->osptokenblock[count] = (char *)data + 2 + 1;
01049 ies->ospblocklength[count] = len - 1;
01050 } else {
01051 snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
01052 errorf(tmp);
01053 }
01054 break;
01055 case IAX_IE_CALLTOKEN:
01056 if (len) {
01057 ies->calltokendata = (unsigned char *) data + 2;
01058 }
01059 ies->calltoken = 1;
01060 break;
01061 default:
01062 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
01063 outputf(tmp);
01064 }
01065
01066 data[0] = 0;
01067 datalen -= (len + 2);
01068 data += (len + 2);
01069 }
01070
01071 *data = '\0';
01072 if (datalen) {
01073 errorf("Invalid information element contents, strange boundary\n");
01074 return -1;
01075 }
01076 return 0;
01077 }
01078
01079 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
01080 {
01081 fr->af.frametype = f->frametype;
01082 fr->af.subclass = f->subclass;
01083 fr->af.mallocd = 0;
01084 fr->af.datalen = f->datalen;
01085 fr->af.samples = f->samples;
01086 fr->af.offset = AST_FRIENDLY_OFFSET;
01087 fr->af.src = f->src;
01088 fr->af.delivery.tv_sec = 0;
01089 fr->af.delivery.tv_usec = 0;
01090 fr->af.data.ptr = fr->afdata;
01091 fr->af.len = f->len;
01092 if (fr->af.datalen) {
01093 size_t copy_len = fr->af.datalen;
01094 if (copy_len > fr->afdatalen) {
01095 ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
01096 (int) fr->afdatalen, (int) fr->af.datalen);
01097 copy_len = fr->afdatalen;
01098 }
01099 #if __BYTE_ORDER == __LITTLE_ENDIAN
01100
01101 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
01102
01103 ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
01104 } else
01105 #endif
01106 memcpy(fr->af.data.ptr, f->data.ptr, copy_len);
01107 }
01108 }
01109
01110 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
01111 {
01112 struct iax_frame *fr = NULL;
01113
01114 #if !defined(LOW_MEMORY)
01115 struct iax_frames *iax_frames = NULL;
01116 struct iax_frame *smallest = NULL;
01117
01118
01119 if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01120 smallest = AST_LIST_FIRST(&iax_frames->list);
01121 AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
01122 if (fr->afdatalen >= datalen) {
01123 size_t afdatalen = fr->afdatalen;
01124 AST_LIST_REMOVE_CURRENT(list);
01125 iax_frames->size--;
01126 memset(fr, 0, sizeof(*fr));
01127 fr->afdatalen = afdatalen;
01128 break;
01129 } else if (smallest->afdatalen > fr->afdatalen) {
01130 smallest = fr;
01131 }
01132 }
01133 AST_LIST_TRAVERSE_SAFE_END;
01134 }
01135 if (!fr) {
01136 if (iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) {
01137
01138 AST_LIST_REMOVE(&iax_frames->list, smallest, list);
01139 if (!(fr = ast_realloc(smallest, sizeof(*fr) + datalen))) {
01140 AST_LIST_INSERT_TAIL(&iax_frames->list, smallest, list);
01141 return NULL;
01142 }
01143 } else if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
01144 return NULL;
01145 fr->afdatalen = datalen;
01146 }
01147 #else
01148 if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
01149 return NULL;
01150 fr->afdatalen = datalen;
01151 #endif
01152
01153
01154 fr->direction = direction;
01155 fr->retrans = -1;
01156 fr->cacheable = cacheable;
01157
01158 if (fr->direction == DIRECTION_INGRESS)
01159 ast_atomic_fetchadd_int(&iframes, 1);
01160 else
01161 ast_atomic_fetchadd_int(&oframes, 1);
01162
01163 ast_atomic_fetchadd_int(&frames, 1);
01164
01165 return fr;
01166 }
01167
01168 void iax_frame_free(struct iax_frame *fr)
01169 {
01170 #if !defined(LOW_MEMORY)
01171 struct iax_frames *iax_frames = NULL;
01172 #endif
01173
01174
01175 if (fr->direction == DIRECTION_INGRESS)
01176 ast_atomic_fetchadd_int(&iframes, -1);
01177 else if (fr->direction == DIRECTION_OUTGRESS)
01178 ast_atomic_fetchadd_int(&oframes, -1);
01179 else {
01180 errorf("Attempt to double free frame detected\n");
01181 return;
01182 }
01183 ast_atomic_fetchadd_int(&frames, -1);
01184
01185 #if !defined(LOW_MEMORY)
01186 if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01187 ast_free(fr);
01188 return;
01189 }
01190
01191 if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
01192 fr->direction = 0;
01193
01194
01195 if (AST_LIST_FIRST(&iax_frames->list) && AST_LIST_FIRST(&iax_frames->list)->afdatalen < fr->afdatalen) {
01196 AST_LIST_INSERT_TAIL(&iax_frames->list, fr, list);
01197 } else {
01198 AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
01199 }
01200 iax_frames->size++;
01201 return;
01202 }
01203 #endif
01204 ast_free(fr);
01205 }
01206
01207 #if !defined(LOW_MEMORY)
01208 static void frame_cache_cleanup(void *data)
01209 {
01210 struct iax_frames *framelist = data;
01211 struct iax_frame *current;
01212
01213 while ((current = AST_LIST_REMOVE_HEAD(&framelist->list, list)))
01214 ast_free(current);
01215
01216 ast_free(framelist);
01217 }
01218 #endif
01219
01220 int iax_get_frames(void) { return frames; }
01221 int iax_get_iframes(void) { return iframes; }
01222 int iax_get_oframes(void) { return oframes; }