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