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