mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
Improve native transfers when a chain of IAX2 connections are in use.
(closes issue #7567) Reported by: tjd Patches: bug_7567_update_v2.diff uploaded by snuffy (license 35) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@116884 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -415,13 +415,9 @@ enum iax_transfer_state {
|
||||
TRANSFER_BEGIN,
|
||||
TRANSFER_READY,
|
||||
TRANSFER_RELEASED,
|
||||
TRANSFER_PASSTHROUGH,
|
||||
TRANSFER_MBEGIN,
|
||||
TRANSFER_MREADY,
|
||||
TRANSFER_MRELEASED,
|
||||
TRANSFER_MPASSTHROUGH,
|
||||
TRANSFER_MEDIA,
|
||||
TRANSFER_MEDIAPASS
|
||||
TRANSFER_MRELEASED
|
||||
};
|
||||
|
||||
struct iax2_registry {
|
||||
@@ -612,6 +608,13 @@ struct chan_iax2_pvt {
|
||||
unsigned short transfercallno;
|
||||
/*! Transfer encrypt AES-128 Key */
|
||||
ast_aes_encrypt_key tdcx;
|
||||
|
||||
/*! If transfer has been attempted */
|
||||
unsigned int triedtransfer:1;
|
||||
/*! Whether media is released */
|
||||
unsigned int mediareleased:1;
|
||||
/*! If media released, the peer to send media to */
|
||||
struct sockaddr_in media;
|
||||
|
||||
/*! Status of knowledge of peer ADSI capability */
|
||||
int peeradsicpe;
|
||||
@@ -899,7 +902,7 @@ static int iax2_hangup(struct ast_channel *c);
|
||||
static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
|
||||
static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
|
||||
static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
|
||||
static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
|
||||
static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final, int media);
|
||||
static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen);
|
||||
static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
|
||||
static int iax2_sendtext(struct ast_channel *c, const char *text);
|
||||
@@ -912,6 +915,7 @@ static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, c
|
||||
static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
|
||||
static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
|
||||
static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
|
||||
static int send_command_media(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
|
||||
static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause);
|
||||
static struct ast_frame *iax2_read(struct ast_channel *c);
|
||||
static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
|
||||
@@ -1484,7 +1488,7 @@ static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short
|
||||
if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
|
||||
(cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
|
||||
/* We're transferring */
|
||||
if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
|
||||
if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_NONE && cur->transfercallno == callno))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -2147,6 +2151,7 @@ static int send_packet(struct iax_frame *f)
|
||||
{
|
||||
int res;
|
||||
int callno = f->callno;
|
||||
struct sockaddr_in *addr;
|
||||
|
||||
/* Don't send if there was an error, but return error instead */
|
||||
if (!callno || !iaxs[callno] || iaxs[callno]->error)
|
||||
@@ -2155,23 +2160,28 @@ static int send_packet(struct iax_frame *f)
|
||||
/* Called with iaxsl held */
|
||||
if (iaxdebug)
|
||||
ast_debug(3, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));
|
||||
if (f->transfer) {
|
||||
if (iaxdebug)
|
||||
iax_showframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
|
||||
res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer,
|
||||
sizeof(iaxs[callno]->transfer));
|
||||
|
||||
if (f->media) {
|
||||
addr = &iaxs[callno]->media;
|
||||
} else if (f->transfer) {
|
||||
addr = &iaxs[callno]->transfer;
|
||||
} else {
|
||||
if (iaxdebug)
|
||||
iax_showframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr));
|
||||
res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr,
|
||||
sizeof(iaxs[callno]->addr));
|
||||
addr = &iaxs[callno]->addr;
|
||||
}
|
||||
|
||||
if (iaxdebug)
|
||||
iax_showframe(f, NULL, 0, addr, f->datalen - sizeof(struct ast_iax2_full_hdr));
|
||||
|
||||
res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)addr,
|
||||
sizeof(iaxs[callno]->media));
|
||||
|
||||
if (res < 0) {
|
||||
if (iaxdebug)
|
||||
ast_debug(1, "Received error: %s\n", strerror(errno));
|
||||
handle_error();
|
||||
} else
|
||||
res = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2286,7 +2296,14 @@ static void __attempt_transmit(const void *data)
|
||||
if (f->retries >= max_retries) {
|
||||
if (f->transfer) {
|
||||
/* Transfer timeout */
|
||||
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
|
||||
struct iax_ie_data ied;
|
||||
memset(&ied, 0, sizeof(ied));
|
||||
iax_ie_append_int(&ied, IAX_IE_TRANSFERID, iaxs[callno]->transferid);
|
||||
if (iaxs[callno]->mediareleased) {
|
||||
send_command_media(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos);
|
||||
} else {
|
||||
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos, -1);
|
||||
}
|
||||
} else if (f->final) {
|
||||
if (f->final)
|
||||
iax2_destroy(callno);
|
||||
@@ -3717,23 +3734,38 @@ static int iax2_start_transfer(unsigned short callno0, unsigned short callno1, i
|
||||
struct iax_ie_data ied1;
|
||||
unsigned int transferid = (unsigned int)ast_random();
|
||||
memset(&ied0, 0, sizeof(ied0));
|
||||
iaxs[callno0]->transferid = transferid;
|
||||
iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &iaxs[callno1]->addr);
|
||||
iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[callno1]->peercallno);
|
||||
iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transferid);
|
||||
|
||||
memset(&ied1, 0, sizeof(ied1));
|
||||
iaxs[callno1]->transferid = transferid;
|
||||
iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &iaxs[callno0]->addr);
|
||||
iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[callno0]->peercallno);
|
||||
iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transferid);
|
||||
|
||||
res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
|
||||
if (iaxs[callno0]->mediareleased) {
|
||||
res = send_command_media(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos);
|
||||
} else {
|
||||
res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
|
||||
}
|
||||
|
||||
if (res)
|
||||
return -1;
|
||||
res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
|
||||
|
||||
if (iaxs[callno1]->mediareleased)
|
||||
res = send_command_media(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos);
|
||||
else
|
||||
res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
|
||||
|
||||
if (res)
|
||||
return -1;
|
||||
iaxs[callno0]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
|
||||
iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
|
||||
iaxs[callno0]->triedtransfer = 1;
|
||||
iaxs[callno1]->triedtransfer = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3759,7 +3791,6 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
|
||||
struct ast_channel *who, *other;
|
||||
int to = -1;
|
||||
int res = -1;
|
||||
int transferstarted=0;
|
||||
struct ast_frame *f;
|
||||
unsigned short callno0 = PTR_TO_CALLNO(c0->tech_pvt);
|
||||
unsigned short callno1 = PTR_TO_CALLNO(c1->tech_pvt);
|
||||
@@ -3819,13 +3850,17 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
|
||||
unlock_both(callno0, callno1);
|
||||
return AST_BRIDGE_FAILED_NOWARN;
|
||||
}
|
||||
/* check if transfered and if we really want native bridging */
|
||||
if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) {
|
||||
/* Try the transfer */
|
||||
if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) ||
|
||||
ast_test_flag(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag(iaxs[callno1], IAX_TRANSFERMEDIA)))
|
||||
ast_log(LOG_WARNING, "Unable to start the transfer\n");
|
||||
transferstarted = 1;
|
||||
/* check if if we really want native bridging */
|
||||
if (!ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) {
|
||||
if (!iaxs[callno0]->triedtransfer && !iaxs[callno1]->triedtransfer &&
|
||||
(iaxs[callno0]->transferring == TRANSFER_NONE) &&
|
||||
(iaxs[callno1]->transferring == TRANSFER_NONE)) {
|
||||
/* Try the transfer */
|
||||
if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) ||
|
||||
ast_test_flag(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag(iaxs[callno1], IAX_TRANSFERMEDIA))) {
|
||||
ast_log(LOG_WARNING, "Unable to start the transfer\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((iaxs[callno0]->transferring == TRANSFER_RELEASED) && (iaxs[callno1]->transferring == TRANSFER_RELEASED)) {
|
||||
/* Call has been transferred. We're no longer involved */
|
||||
@@ -4572,7 +4607,7 @@ static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_fr
|
||||
return res;
|
||||
}
|
||||
|
||||
static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final)
|
||||
static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final, int media)
|
||||
{
|
||||
/* Queue a packet for delivery on a given private structure. Use "ts" for
|
||||
timestamp, or calculate if ts is 0. Send immediately without retransmission
|
||||
@@ -4654,6 +4689,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
||||
fr->ts = fts;
|
||||
fr->callno = pvt->callno;
|
||||
fr->transfer = transfer;
|
||||
fr->media = media;
|
||||
fr->final = final;
|
||||
if (!sendmini) {
|
||||
/* We need a full frame */
|
||||
@@ -4666,12 +4702,12 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
||||
fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
|
||||
fh->ts = htonl(fr->ts);
|
||||
fh->oseqno = fr->oseqno;
|
||||
if (transfer) {
|
||||
if (transfer || media) {
|
||||
fh->iseqno = 0;
|
||||
} else
|
||||
fh->iseqno = fr->iseqno;
|
||||
/* Keep track of the last thing we've acknowledged */
|
||||
if (!transfer)
|
||||
if (!transfer || media)
|
||||
pvt->aseqno = fr->iseqno;
|
||||
fh->type = fr->af.frametype & 0xFF;
|
||||
if (fr->af.frametype == AST_FRAME_VIDEO)
|
||||
@@ -4704,6 +4740,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
||||
if (iaxdebug) {
|
||||
if (fr->transfer)
|
||||
iax_showframe(fr, NULL, 2, &pvt->transfer, fr->datalen - sizeof(struct ast_iax2_full_hdr));
|
||||
else if (fr->media)
|
||||
iax_showframe(fr, NULL, 2, &pvt->media, fr->datalen - sizeof(struct ast_iax2_full_hdr));
|
||||
|
||||
else
|
||||
iax_showframe(fr, NULL, 2, &pvt->addr, fr->datalen - sizeof(struct ast_iax2_full_hdr));
|
||||
}
|
||||
@@ -4731,6 +4770,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
||||
fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr);
|
||||
fr->data = vh;
|
||||
fr->retries = -1;
|
||||
if (pvt->mediareleased) {
|
||||
fr->media = 1;
|
||||
}
|
||||
res = send_packet(fr);
|
||||
} else {
|
||||
/* Mini-frames have no sequence number */
|
||||
@@ -4743,8 +4785,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
||||
fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
|
||||
fr->data = mh;
|
||||
fr->retries = -1;
|
||||
if (pvt->transferring == TRANSFER_MEDIAPASS)
|
||||
fr->transfer = 1;
|
||||
if (pvt->mediareleased) {
|
||||
fr->media = 1;
|
||||
}
|
||||
if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
|
||||
if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
|
||||
encrypt_frame(&pvt->ecx, (struct ast_iax2_full_hdr *)mh, pvt->semirand, &fr->datalen);
|
||||
@@ -5604,7 +5647,7 @@ static int iax2_write(struct ast_channel *c, struct ast_frame *f)
|
||||
res = 0;
|
||||
else
|
||||
/* Simple, just queue for transmission */
|
||||
res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0);
|
||||
res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0, 0);
|
||||
} else {
|
||||
ast_debug(1, "Write error: %s\n", strerror(errno));
|
||||
}
|
||||
@@ -5615,7 +5658,7 @@ static int iax2_write(struct ast_channel *c, struct ast_frame *f)
|
||||
}
|
||||
|
||||
static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno,
|
||||
int now, int transfer, int final)
|
||||
int now, int transfer, int final, int media)
|
||||
{
|
||||
struct ast_frame f = { 0, };
|
||||
|
||||
@@ -5625,12 +5668,12 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig
|
||||
f.src = __FUNCTION__;
|
||||
f.data = (void *) data;
|
||||
|
||||
return iax2_send(i, &f, ts, seqno, now, transfer, final);
|
||||
return iax2_send(i, &f, ts, seqno, now, transfer, final, media);
|
||||
}
|
||||
|
||||
static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
|
||||
{
|
||||
return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
|
||||
return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
|
||||
@@ -5654,17 +5697,22 @@ static int send_command_final(struct chan_iax2_pvt *i, char type, int command, u
|
||||
iax2_predestroy(i->callno);
|
||||
if (!iaxs[call_num])
|
||||
return -1;
|
||||
return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1);
|
||||
return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
|
||||
}
|
||||
|
||||
static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
|
||||
{
|
||||
return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0);
|
||||
return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen)
|
||||
{
|
||||
return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0);
|
||||
return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
static int send_command_media(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen)
|
||||
{
|
||||
return __send_command(i, type, command, ts, data, datalen, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
static int apply_context(struct iax2_context *con, const char *context)
|
||||
@@ -6468,6 +6516,8 @@ static int complete_transfer(int callno, struct iax_ies *ies)
|
||||
}
|
||||
memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
|
||||
memset(&pvt->transfer, 0, sizeof(pvt->transfer));
|
||||
pvt->mediareleased = 0;
|
||||
memset(&pvt->media, 0, sizeof(pvt->media));
|
||||
/* Reset sequence numbers */
|
||||
pvt->oseqno = 0;
|
||||
pvt->rseqno = 0;
|
||||
@@ -8038,6 +8088,7 @@ static int socket_process(struct iax2_thread *thread)
|
||||
((f.subclass != IAX_COMMAND_TXCNT) &&
|
||||
(f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_TXMEDIA) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_TXACC)) ||
|
||||
(f.frametype != AST_FRAME_IAX))) {
|
||||
@@ -8047,6 +8098,7 @@ static int socket_process(struct iax2_thread *thread)
|
||||
(f.subclass != IAX_COMMAND_TXCNT) &&
|
||||
(f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_TXMEDIA) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */
|
||||
(f.subclass != IAX_COMMAND_TXACC) &&
|
||||
(f.subclass != IAX_COMMAND_VNAK)) ||
|
||||
@@ -8149,7 +8201,7 @@ static int socket_process(struct iax2_thread *thread)
|
||||
ast_debug(1, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno);
|
||||
}
|
||||
}
|
||||
if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
|
||||
if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) && inaddrcmp(&sin, &iaxs[fr->callno]->media) &&
|
||||
((f.frametype != AST_FRAME_IAX) ||
|
||||
((f.subclass != IAX_COMMAND_TXACC) &&
|
||||
(f.subclass != IAX_COMMAND_TXCNT)))) {
|
||||
@@ -8334,18 +8386,23 @@ retryowner:
|
||||
}
|
||||
break;
|
||||
case IAX_COMMAND_TXACC:
|
||||
if (iaxs[fr->callno]->transferring == TRANSFER_BEGIN) {
|
||||
/* Ack the packet with the given timestamp */
|
||||
if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) &&
|
||||
(iaxs[fr->callno]->transferid == ies.transferid)) {
|
||||
/* Cancel any outstanding txcnt's */
|
||||
AST_LIST_LOCK(&frame_queue);
|
||||
AST_LIST_TRAVERSE(&frame_queue, cur, list) {
|
||||
/* Cancel any outstanding txcnt's */
|
||||
if ((fr->callno == cur->callno) && (cur->transfer))
|
||||
cur->retries = -1;
|
||||
}
|
||||
AST_LIST_UNLOCK(&frame_queue);
|
||||
memset(&ied1, 0, sizeof(ied1));
|
||||
iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->callno);
|
||||
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1);
|
||||
iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
|
||||
if (iaxs[fr->callno]->mediareleased) {
|
||||
send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos);
|
||||
} else {
|
||||
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1);
|
||||
}
|
||||
iaxs[fr->callno]->transferring = TRANSFER_READY;
|
||||
}
|
||||
break;
|
||||
@@ -8776,7 +8833,7 @@ retryowner2:
|
||||
if(f.subclass == IAX_COMMAND_LAGRQ) {
|
||||
/* Received a LAGRQ - echo back a LAGRP */
|
||||
fr->af.subclass = IAX_COMMAND_LAGRP;
|
||||
iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0);
|
||||
iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0, 0);
|
||||
} else {
|
||||
/* Received LAGRP in response to our LAGRQ */
|
||||
unsigned int ts;
|
||||
@@ -9154,19 +9211,28 @@ retryowner2:
|
||||
}
|
||||
break;
|
||||
case IAX_COMMAND_TXREJ:
|
||||
iaxs[fr->callno]->transferring = 0;
|
||||
ast_verb(3, "Channel '%s' unable to transfer\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
|
||||
memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
|
||||
if (iaxs[fr->callno]->bridgecallno) {
|
||||
if (iaxs[iaxs[fr->callno]->bridgecallno]->transferring) {
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->transferring = 0;
|
||||
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
|
||||
if ((iaxs[fr->callno]->transferring != TRANSFER_NONE) &&
|
||||
(iaxs[fr->callno]->transferid == ies.transferid)) {
|
||||
iaxs[fr->callno]->transferring = TRANSFER_NONE;
|
||||
ast_verb(3, "Channel '%s' transfer rejected\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
|
||||
memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
|
||||
if (iaxs[fr->callno]->bridgecallno &&
|
||||
(iaxs[fr->callno]->transferid == iaxs[iaxs[fr->callno]->bridgecallno]->transferid)) {
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_NONE;
|
||||
memset(&ied0, 0, sizeof(ied0));
|
||||
iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
|
||||
if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) {
|
||||
send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos);
|
||||
} else {
|
||||
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IAX_COMMAND_TXREADY:
|
||||
if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) ||
|
||||
(iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) {
|
||||
if (((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) ||
|
||||
(iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) &&
|
||||
(iaxs[fr->callno]->transferid == ies.transferid)) {
|
||||
if (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)
|
||||
iaxs[fr->callno]->transferring = TRANSFER_MREADY;
|
||||
else
|
||||
@@ -9176,19 +9242,33 @@ retryowner2:
|
||||
if ((iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_READY) ||
|
||||
(iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_MREADY)) {
|
||||
/* They're both ready, now release them. */
|
||||
if (iaxs[fr->callno]->transferring == TRANSFER_MREADY) {
|
||||
/* If a peer is media released, we must also do a media release as there may be peers in between */
|
||||
if (iaxs[fr->callno]->mediareleased ||
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased ||
|
||||
(iaxs[fr->callno]->transferring == TRANSFER_MREADY)) {
|
||||
|
||||
ast_verb(3, "Attempting media bridge of %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
|
||||
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MEDIA;
|
||||
iaxs[fr->callno]->transferring = TRANSFER_MEDIA;
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MRELEASED;
|
||||
iaxs[fr->callno]->transferring = TRANSFER_MRELEASED;
|
||||
|
||||
memset(&ied0, 0, sizeof(ied0));
|
||||
memset(&ied1, 0, sizeof(ied1));
|
||||
iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno);
|
||||
iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
|
||||
iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno);
|
||||
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1);
|
||||
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1);
|
||||
iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
|
||||
if (iaxs[fr->callno]->mediareleased) {
|
||||
send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos);
|
||||
} else {
|
||||
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1);
|
||||
}
|
||||
if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) {
|
||||
send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos);
|
||||
} else {
|
||||
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1);
|
||||
}
|
||||
} else {
|
||||
ast_verb(3, "Releasing %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
|
||||
@@ -9205,9 +9285,19 @@ retryowner2:
|
||||
memset(&ied0, 0, sizeof(ied0));
|
||||
memset(&ied1, 0, sizeof(ied1));
|
||||
iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno);
|
||||
iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
|
||||
iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno);
|
||||
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1);
|
||||
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1);
|
||||
iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
|
||||
if (iaxs[fr->callno]->mediareleased) {
|
||||
send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos);
|
||||
} else {
|
||||
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1);
|
||||
}
|
||||
if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) {
|
||||
send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos);
|
||||
} else {
|
||||
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9215,20 +9305,50 @@ retryowner2:
|
||||
}
|
||||
break;
|
||||
case IAX_COMMAND_TXREQ:
|
||||
try_transfer(iaxs[fr->callno], &ies);
|
||||
/* Try transfer only if none in progress, or use the transferid to resolve contention */
|
||||
if ((iaxs[fr->callno]->transferring == TRANSFER_NONE) ||
|
||||
(iaxs[fr->callno]->transferid <= ies.transferid)) {
|
||||
/* If there is a bridged channel and it is the same transfer, reject it */
|
||||
if (iaxs[fr->callno]->bridgecallno &&
|
||||
(iaxs[fr->callno]->transferid == iaxs[iaxs[fr->callno]->bridgecallno]->transferid)) {
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_NONE;
|
||||
memset(&ied0, 0, sizeof(ied0));
|
||||
iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
|
||||
if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) {
|
||||
send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos);
|
||||
} else {
|
||||
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos, -1);
|
||||
}
|
||||
/* Start our transfer again later */
|
||||
iaxs[fr->callno]->triedtransfer = 0;
|
||||
iaxs[iaxs[fr->callno]->bridgecallno]->triedtransfer = 0;
|
||||
}
|
||||
try_transfer(iaxs[fr->callno], &ies);
|
||||
}
|
||||
|
||||
break;
|
||||
case IAX_COMMAND_TXCNT:
|
||||
if (iaxs[fr->callno]->transferring)
|
||||
send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, NULL, 0);
|
||||
if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) &&
|
||||
(iaxs[fr->callno]->transferid == ies.transferid)) {
|
||||
memcpy(&iaxs[fr->callno]->transfer, &sin, sizeof(iaxs[fr->callno]->transfer));
|
||||
memset(&ied0, 0, sizeof(ied0));
|
||||
iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
|
||||
send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, ied0.buf, ied0.pos);
|
||||
}
|
||||
break;
|
||||
case IAX_COMMAND_TXREL:
|
||||
if ((iaxs[fr->callno]->transferring == TRANSFER_READY) &&
|
||||
(iaxs[fr->callno]->transferid == ies.transferid)) {
|
||||
/* Send ack immediately, rather than waiting until we've changed addresses */
|
||||
send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
|
||||
complete_transfer(fr->callno, &ies);
|
||||
stop_stuff(fr->callno); /* for attended transfer to work with libiax */
|
||||
stop_stuff(fr->callno); /* for attended transfer to work with libiax */
|
||||
}
|
||||
break;
|
||||
case IAX_COMMAND_TXMEDIA:
|
||||
if (iaxs[fr->callno]->transferring == TRANSFER_READY) {
|
||||
if ((iaxs[fr->callno]->transferring == TRANSFER_READY) &&
|
||||
(iaxs[fr->callno]->transferid == ies.transferid)) {
|
||||
|
||||
AST_LIST_LOCK(&frame_queue);
|
||||
AST_LIST_TRAVERSE(&frame_queue, cur, list) {
|
||||
/* Cancel any outstanding frames and start anew */
|
||||
@@ -9237,7 +9357,10 @@ retryowner2:
|
||||
}
|
||||
AST_LIST_UNLOCK(&frame_queue);
|
||||
/* Start sending our media to the transfer address, but otherwise leave the call as-is */
|
||||
iaxs[fr->callno]->transferring = TRANSFER_MEDIAPASS;
|
||||
memcpy(&iaxs[fr->callno]->media, &iaxs[fr->callno]->transfer, sizeof(iaxs[fr->callno]->addr));
|
||||
memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
|
||||
iaxs[fr->callno]->transferring = TRANSFER_NONE;
|
||||
iaxs[fr->callno]->mediareleased = 1;
|
||||
}
|
||||
break;
|
||||
case IAX_COMMAND_DPREP:
|
||||
@@ -9376,7 +9499,6 @@ retryowner2:
|
||||
ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Always run again */
|
||||
ast_mutex_unlock(&iaxsl[fr->callno]);
|
||||
return 1;
|
||||
|
@@ -109,6 +109,8 @@ struct iax_frame {
|
||||
unsigned int sentyet:1;
|
||||
/* Non-zero if should be sent to transfer peer */
|
||||
unsigned int transfer:1;
|
||||
/* Non-zero if should be sent to media peer */
|
||||
unsigned int media:1;
|
||||
/* Non-zero if this is the final message */
|
||||
unsigned int final:1;
|
||||
/* Ingress or outgres */
|
||||
|
Reference in New Issue
Block a user