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