diff --git a/channels/chan_iax.c b/channels/chan_iax.c index 679ba65a5086dd83979f654a67036633494e7916..74c75393e03999b6c02800e9c92eb7ae4ad5b5b7 100755 --- a/channels/chan_iax.c +++ b/channels/chan_iax.c @@ -42,6 +42,15 @@ #include "iax.h" +/* + * Uncomment to try experimental IAX bridge optimization, + * designed to reduce latency when IAX calls cannot + * be trasnferred + */ + +#define BRIDGE_OPTIMIZATION + + #define DEFAULT_RETRY_TIME 1000 #define MEMORY_SIZE 100 #define DEFAULT_DROP 3 @@ -161,7 +170,10 @@ struct iax_peer { char inkeys[80]; /* Key(s) this peer can use to authenticate to us */ int hascallerid; + /* Suggested caller id if registering */ char callerid[AST_MAX_EXTENSION]; + /* Whether or not to send ANI */ + int sendani; int expire; /* Schedule entry for expirey */ int expirey; /* How soon to expire */ int capability; /* Capability */ @@ -268,8 +280,10 @@ struct chan_iax_pvt { char context[80]; /* Caller ID if available */ char callerid[80]; - /* Hidden Caller ID if appropriate */ - char hidden_callerid[80]; + /* Hidden Caller ID (i.e. ANI) if appropriate */ + char ani[80]; + /* Whether or not ani should be transmitted in addition to Caller*ID */ + int sendani; /* DNID */ char dnid[80]; /* Requested Extension */ @@ -519,8 +533,12 @@ static unsigned int calc_timestamp(struct chan_iax_pvt *p, unsigned int ts); static int send_ping(void *data) { int callno = (long)data; + /* Ping only if it's real, not if it's bridged */ if (iaxs[callno]) { - send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, 0, NULL, 0, -1); +#ifdef BRIDGE_OPTIMIZATION + if (iaxs[callno]->bridgecallno < 0) +#endif + send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, 0, NULL, 0, -1); return 1; } else return 0; @@ -529,8 +547,12 @@ static int send_ping(void *data) static int send_lagrq(void *data) { int callno = (long)data; + /* Ping only if it's real not if it's bridged */ if (iaxs[callno]) { - send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_LAGRQ, 0, NULL, 0, -1); +#ifdef BRIDGE_OPTIMIZATION + if (iaxs[callno]->bridgecallno < 0) +#endif + send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_LAGRQ, 0, NULL, 0, -1); return 1; } else return 0; @@ -734,7 +756,7 @@ static int find_callno(short callno, short dcallno ,struct sockaddr_in *sin, int if ((res < 0) && (new >= NEW_ALLOW)) { /* Create a new one */ start = nextcallno; - for (x = nextcallno + 1; iaxs[x] && (x != start); x = (x + 1) % AST_IAX_MAX_CALLS) + for (x = (nextcallno + 1) % AST_IAX_MAX_CALLS; iaxs[x] && (x != start); x = (x + 1) % AST_IAX_MAX_CALLS) if (x == start) { ast_log(LOG_WARNING, "Unable to accept more calls\n"); return -1; @@ -1106,6 +1128,22 @@ static struct ast_cli_entry cli_show_cache = static unsigned int calc_rxstamp(struct chan_iax_pvt *p); +#ifdef BRIDGE_OPTIMIZATION +static unsigned int calc_fakestamp(struct chan_iax_pvt *from, struct chan_iax_pvt *to, unsigned int ts); + +static int forward_delivery(struct ast_iax_frame *fr) +{ + struct chan_iax_pvt *p1, *p2; + p1 = iaxs[fr->callno]; + p2 = iaxs[p1->bridgecallno]; + /* Fix relative timestamp */ + fr->ts = calc_fakestamp(p1, p2, fr->ts); + /* Now just send it send on the 2nd one + with adjusted timestamp */ + return iax_send(p2, fr->f, fr->ts, -1, 0, 0, 0); +} +#endif + static int schedule_delivery(struct ast_iax_frame *fr, int reallydeliver) { int ms,x; @@ -1114,6 +1152,7 @@ static int schedule_delivery(struct ast_iax_frame *fr, int reallydeliver) /* ms is a measure of the "lateness" of the packet relative to the first packet we received, which always has a lateness of 1. */ ms = calc_rxstamp(iaxs[fr->callno]) - fr->ts; + if (ms > 32768) { /* What likely happened here is that our counter has circled but we haven't gotten the update from the main packet. We'll just pretend that we did, and @@ -1292,11 +1331,13 @@ static int iax_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan return 0; } -static int create_addr(struct sockaddr_in *sin, int *capability, char *peer) +static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, char *peer) { struct hostent *hp; struct iax_peer *p; int found=0; + if (sendani) + *sendani = 0; sin->sin_family = AF_INET; ast_pthread_mutex_lock(&peerl.lock); p = peerl.peers; @@ -1306,6 +1347,8 @@ static int create_addr(struct sockaddr_in *sin, int *capability, char *peer) if (capability) *capability = p->capability; if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) { + if (sendani) + *sendani = p->sendani; if (p->addr.sin_addr.s_addr) { sin->sin_addr = p->addr.sin_addr; sin->sin_port = p->addr.sin_port; @@ -1376,7 +1419,7 @@ static int iax_call(struct ast_channel *c, char *dest, int timeout) strtok(hname, ":"); portno = strtok(hname, ":"); } - if (create_addr(&sin, NULL, hname)) { + if (create_addr(&sin, NULL, NULL, hname)) { ast_log(LOG_WARNING, "No address associated with '%s'\n", hname); return -1; } @@ -1389,6 +1432,8 @@ static int iax_call(struct ast_channel *c, char *dest, int timeout) MYSNPRINTF "exten=%s;", rdest); if (c->callerid) MYSNPRINTF "callerid=%s;", c->callerid); + if (p->sendani && c->ani) + MYSNPRINTF "ani=%s;", c->ani); if (c->language && strlen(c->language)) MYSNPRINTF "language=%s;", c->language); if (c->dnid) @@ -1548,8 +1593,11 @@ static int iax_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, cs[1] = c1; for (/* ever */;;) { /* Check in case we got masqueraded into */ - if ((c0->type != type) || (c1->type != type)) + if ((c0->type != type) || (c1->type != type)) { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Can't masquerade, we're different...\n"); return -2; + } if (!transferstarted) { /* Try the transfer */ if (iax_start_transfer(c0, c1)) @@ -1708,8 +1756,8 @@ static struct ast_channel *ast_iax_new(struct chan_iax_pvt *i, int state, int ca tmp->pvt->bridge = iax_bridge; if (strlen(i->callerid)) tmp->callerid = strdup(i->callerid); - if (strlen(i->hidden_callerid)) - tmp->hidden_callerid = strdup(i->hidden_callerid); + if (strlen(i->ani)) + tmp->ani = strdup(i->ani); if (strlen(i->language)) strncpy(tmp->language, i->language, sizeof(tmp->language)-1); if (strlen(i->dnid)) @@ -1758,13 +1806,42 @@ static unsigned int calc_timestamp(struct chan_iax_pvt *p, unsigned int ts) return ms; } +#ifdef BRIDGE_OPTIMIZATION +static unsigned int calc_fakestamp(struct chan_iax_pvt *p1, struct chan_iax_pvt *p2, unsigned int fakets) +{ + int ms; + /* Receive from p1, send to p2 */ + + /* Setup rxcore if necessary on outgoing channel */ + if (!p1->rxcore.tv_sec && !p1->rxcore.tv_usec) + gettimeofday(&p1->rxcore, NULL); + + /* Setup txcore if necessary on outgoing channel */ + if (!p2->offset.tv_sec && !p2->offset.tv_usec) + gettimeofday(&p2->offset, NULL); + + /* Now, ts is the timestamp of the original packet in the orignal context. + Adding rxcore to it gives us when we would want the packet to be delivered normally. + Subtracting txcore of the outgoing channel gives us what we'd expect */ + + ms = (p1->rxcore.tv_sec - p2->offset.tv_sec) * 1000 + (p1->rxcore.tv_usec - p1->offset.tv_usec) / 1000; + fakets += ms; + if (fakets <= p2->lastsent) + fakets = p2->lastsent + 1; + p2->lastsent = fakets; + return fakets; +} +#endif + static unsigned int calc_rxstamp(struct chan_iax_pvt *p) { /* Returns where in "receive time" we are */ struct timeval tv; unsigned int ms; + /* Setup rxcore if necessary */ if (!p->rxcore.tv_sec && !p->rxcore.tv_usec) gettimeofday(&p->rxcore, NULL); + gettimeofday(&tv, NULL); ms = (tv.tv_sec - p->rxcore.tv_sec) * 1000 + (tv.tv_usec - p->rxcore.tv_usec) / 1000; return ms; @@ -2099,6 +2176,13 @@ static int send_command(struct chan_iax_pvt *i, char type, int command, unsigned return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0); } +#ifdef BRIDGE_OPTIMIZATION +static int forward_command(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno) +{ + return __send_command(iaxs[i->bridgecallno], type, command, ts, data, datalen, seqno, 0, 0, 0); +} +#endif + static int send_command_final(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno) { iax_predestroy(i); @@ -2183,6 +2267,8 @@ static int check_access(int callno, struct sockaddr_in *sin, char *orequest, int strncpy(iaxs[callno]->exten, value, sizeof(iaxs[callno]->exten)-1); else if (!strcmp(var, "callerid")) strncpy(iaxs[callno]->callerid, value, sizeof(iaxs[callno]->callerid)-1); + else if (!strcmp(var, "ani")) + strncpy(iaxs[callno]->ani, value, sizeof(iaxs[callno]->ani) - 1); else if (!strcmp(var, "dnid")) strncpy(iaxs[callno]->dnid, value, sizeof(iaxs[callno]->dnid)-1); else if (!strcmp(var, "context")) @@ -2239,11 +2325,11 @@ static int check_access(int callno, struct sockaddr_in *sin, char *orequest, int strncpy(iaxs[callno]->inkeys, user->inkeys, sizeof(iaxs[callno]->inkeys)); /* And the permitted authentication methods */ strncpy(iaxs[callno]->methods, user->methods, sizeof(iaxs[callno]->methods)-1); - /* If they have callerid, override the given caller id. Always store the hidden */ + /* If they have callerid, override the given caller id. Always store the ANI */ if (strlen(iaxs[callno]->callerid)) { if (user->hascallerid) strncpy(iaxs[callno]->callerid, user->callerid, sizeof(iaxs[callno]->callerid)-1); - strncpy(iaxs[callno]->hidden_callerid, user->callerid, sizeof(iaxs[callno]->hidden_callerid)-1); + strncpy(iaxs[callno]->ani, user->callerid, sizeof(iaxs[callno]->ani)-1); } if (strlen(user->accountcode)) strncpy(iaxs[callno]->accountcode, user->accountcode, sizeof(iaxs[callno]->accountcode)-1); @@ -2332,7 +2418,7 @@ static int authenticate_verify(struct chan_iax_pvt *p, char *orequest) res = 0; break; } else if (!key) - ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n"); + ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n", keyn); keyn = strtok(NULL, ":"); } } else if (strstr(p->methods, "md5")) { @@ -3364,24 +3450,53 @@ static int socket_read(int *id, int fd, short events, void *cbdata) ast_pthread_mutex_unlock(&dpcache_lock); break; case AST_IAX_COMMAND_PING: +#ifdef BRIDGE_OPTIMIZATION + if (iaxs[fr.callno]->bridgecallno > -1) { + /* If we're in a bridged call, just forward this */ + forward_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, fr.ts, NULL, 0, -1); + } else { + /* Send back a pong packet with the original timestamp */ + send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1); + } +#else /* Send back a pong packet with the original timestamp */ send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1); +#endif break; case AST_IAX_COMMAND_PONG: +#ifdef BRIDGE_OPTIMIZATION + if (iaxs[fr.callno]->bridgecallno > -1) { + /* Forward to the other side of the bridge */ + forward_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1); + } else { + /* Calculate ping time */ + iaxs[fr.callno]->pingtime = calc_timestamp(iaxs[fr.callno], 0) - fr.ts; + } +#else + /* Calculate ping time */ iaxs[fr.callno]->pingtime = calc_timestamp(iaxs[fr.callno], 0) - fr.ts; +#endif break; case AST_IAX_COMMAND_LAGRQ: case AST_IAX_COMMAND_LAGRP: - /* A little strange -- We have to actually go through the motions of - delivering the packet. In the very last step, it will be properly - handled by do_deliver */ - snprintf(src, sizeof(src), "LAGRQ-IAX/%s/%d", inet_ntoa(sin.sin_addr),fr.callno); - f.src = src; - f.mallocd = 0; - f.offset = 0; - fr.f = &f; - f.timelen = 0; - schedule_delivery(iaxfrdup2(&fr, 0), 1); +#ifdef BRIDGE_OPTIMIZATION + if (iaxs[fr.callno]->bridgecallno > -1) { + forward_command(iaxs[fr.callno], AST_FRAME_IAX, f.subclass, fr.ts, NULL, 0, -1); + } else { +#endif + /* A little strange -- We have to actually go through the motions of + delivering the packet. In the very last step, it will be properly + handled by do_deliver */ + snprintf(src, sizeof(src), "LAGRQ-IAX/%s/%d", inet_ntoa(sin.sin_addr),fr.callno); + f.src = src; + f.mallocd = 0; + f.offset = 0; + fr.f = &f; + f.timelen = 0; + schedule_delivery(iaxfrdup2(&fr, 0), 1); +#ifdef BRIDGE_OPTIMIZATION + } +#endif break; case AST_IAX_COMMAND_AUTHREQ: if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD)) { @@ -3632,7 +3747,15 @@ static int socket_read(int *id, int fd, short events, void *cbdata) ast_log(LOG_DEBUG, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass, fr.ts, iaxs[fr.callno]->last); fr.outoforder = -1; } +#ifdef BRIDGE_OPTIMIZATION + if (iaxs[fr.callno]->bridgecallno > -1) { + forward_delivery(&fr); + } else { + schedule_delivery(iaxfrdup2(&fr, 0), 1); + } +#else schedule_delivery(iaxfrdup2(&fr, 0), 1); +#endif /* Always run again */ ast_pthread_mutex_unlock(&iaxs_lock); return 1; @@ -3690,6 +3813,7 @@ static struct ast_channel *iax_request(char *type, int format, void *data) { int callno; int res; + int sendani; int fmt, native; struct sockaddr_in sin; char s[256]; @@ -3703,7 +3827,7 @@ static struct ast_channel *iax_request(char *type, int format, void *data) if (!st) st = s; /* Populate our address from the given */ - if (create_addr(&sin, &capability, st)) { + if (create_addr(&sin, &capability, &sendani, st)) { return NULL; } ast_pthread_mutex_lock(&iaxs_lock); @@ -3712,6 +3836,8 @@ static struct ast_channel *iax_request(char *type, int format, void *data) ast_log(LOG_WARNING, "Unable to create call\n"); return NULL; } + /* Keep track of sendani flag */ + iaxs[callno]->sendani = sendani; c = ast_iax_new(iaxs[callno], AST_STATE_DOWN, capability); if (c) { /* Choose a format we can live with */ @@ -3963,6 +4089,8 @@ static struct iax_peer *build_peer(char *name, struct ast_variable *v) } else if (!strcasecmp(v->name, "callerid")) { strncpy(peer->callerid, v->value, sizeof(peer->callerid)-1); peer->hascallerid=1; + } else if (!strcasecmp(v->name, "sendani")) { + peer->sendani = ast_true(v->value); } else if (!strcasecmp(v->name, "inkeys")) { strncpy(peer->inkeys, v->value, sizeof(peer->inkeys)); } else if (!strcasecmp(v->name, "outkey")) { @@ -4293,7 +4421,7 @@ static int cache_get_callno(char *data) host = st; } /* Populate our address from the given */ - if (create_addr(&sin, NULL, host)) { + if (create_addr(&sin, NULL, NULL, host)) { return -1; } ast_log(LOG_DEBUG, "host: %s, user: %s, password: %s, context: %s\n", host, username, password, context); diff --git a/channels/chan_phone.c b/channels/chan_phone.c index c481abb99264b569bda45873be6babcac632e946..7300646b60e72d813237336d3b09ddde1606467a 100755 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -588,6 +588,8 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte tmp->fds[0] = i->fd; /* XXX Switching formats silently causes kernel panics XXX */ tmp->nativeformats = prefformat; + tmp->pvt->rawreadformat = prefformat; + tmp->pvt->rawwriteformat = prefformat; tmp->state = state; if (state == AST_STATE_RING) tmp->rings = 1; @@ -911,7 +913,7 @@ static struct phone_pvt *mkif(char *iface, int mode, int txgain, int rxgain) ast_log(LOG_DEBUG, "Unable to set port to PSTN\n"); } else { if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS)) - ast_log(LOG_DEBUG, "Unable to set port to PSTN\n"); + ast_log(LOG_DEBUG, "Unable to set port to POTS\n"); } ioctl(tmp->fd, PHONE_PLAY_STOP); ioctl(tmp->fd, PHONE_REC_STOP); @@ -1088,7 +1090,7 @@ int load_module() ast_pthread_mutex_unlock(&iflock); /* Make sure we can register our Adtranphone channel type */ if (ast_channel_register(type, tdesc, - AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW, phone_request)) { + AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW, phone_request)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); ast_destroy(cfg); unload_module();