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