📄 iax.c
字号:
}
#else
if ((flags = fcntl(netfd, F_GETFL)) < 0) {
close(netfd);
netfd = -1;
DEBU(G "Unable to retrieve socket flags.");
IAXERROR "Unable to retrieve socket flags.");
}
if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0) {
close(netfd);
netfd = -1;
DEBU(G "Unable to set non-blocking mode.");
IAXERROR "Unable to set non-blocking mode.");
}
#endif
portno = ntohs(sin.sin_port);
}
#ifdef _WIN32_WCE
srand(GetTickCount());
#else
srand(time(NULL));
#endif
callnums = rand() % 32767 + 1;
transfer_id = rand() % 32767 + 1;
DEBU(G "Started on port %d\n", portno);
return portno;
}
static void destroy_session(struct iax_session *session);
static void convert_reply(char *out, unsigned char *in)
{
int x;
for (x=0;x<16;x++)
out += sprintf(out, "%2.2x", (int)in[x]);
}
static unsigned char compress_subclass(int subclass)
{
int x;
int power=-1;
/* If it's 128 or smaller, just return it */
if (subclass < IAX_FLAG_SC_LOG)
return subclass;
/* Otherwise find its power */
for (x = 0; x < IAX_MAX_SHIFT; x++) {
if (subclass & (1 << x)) {
if (power > -1) {
DEBU(G "Can't compress subclass %d\n", subclass);
return 0;
} else
power = x;
}
}
return power | IAX_FLAG_SC_LOG;
}
static int iax_send(struct iax_session *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final)
{
/* Queue a packet for delivery on a given private structure. Use "ts" for
timestamp, or calculate if ts is 0. Send immediately without retransmission
or delayed, with retransmission */
struct ast_iax2_full_hdr *fh;
struct ast_iax2_mini_hdr *mh;
unsigned char buf[5120];
struct iax_frame *fr;
int res;
int sendmini=0;
unsigned int lastsent;
unsigned int fts;
OutputDebugString(L"iax_send in\n");
if (!pvt) {
IAXERROR "No private structure for packet?\n");
return -1;
}
/* this must come before the next call to calc_timestamp() since
calc_timestamp() will change lastsent to the returned value */
lastsent = pvt->lastsent;
/* Calculate actual timestamp */
fts = calc_timestamp(pvt, ts, f);
if (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L))
/* High two bits are the same on timestamp, or sending on a trunk */ &&
(f->frametype == AST_FRAME_VOICE)
/* is a voice frame */ &&
(f->subclass == pvt->svoiceformat)
/* is the same type */ ) {
/* Force immediate rather than delayed transmission */
now = 1;
/* Mark that mini-style frame is appropriate */
sendmini = 1;
}
/* Allocate an iax_frame */
if (now) {
fr = (struct iax_frame *) buf;
} else
fr = iax_frame_new(DIRECTION_OUTGRESS, f->datalen);
if (!fr) {
IAXERROR "Out of memory\n");
return -1;
}
/* Copy our prospective frame into our immediate or retransmitted wrapper */
iax_frame_wrap(fr, f);
fr->ts = fts;
if (!fr->ts) {
IAXERROR "timestamp is 0?\n");
if (!now)
iax_frame_free(fr);
return -1;
}
fr->callno = pvt->callno;
fr->transfer = transfer;
fr->final = final;
fr->session = pvt;
if (!sendmini) {
/* We need a full frame */
if (seqno > -1)
fr->oseqno = seqno;
else
fr->oseqno = pvt->oseqno++;
fr->iseqno = pvt->iseqno;
fh = (struct ast_iax2_full_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_full_hdr));
fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
fh->ts = htonl(fr->ts);
fh->oseqno = fr->oseqno;
if (transfer) {
fh->iseqno = 0;
} else
fh->iseqno = fr->iseqno;
/* Keep track of the last thing we've acknowledged */
pvt->aseqno = fr->iseqno;
fh->type = fr->af.frametype & 0xFF;
fh->csub = compress_subclass(fr->af.subclass);
if (transfer) {
fr->dcallno = pvt->transfercallno;
} else
fr->dcallno = pvt->peercallno;
fh->dcallno = htons(fr->dcallno);
fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr);
fr->data = fh;
fr->retries = maxretries;
/* Retry after 2x the ping time has passed */
fr->retrytime = pvt->pingtime * 2;
if (fr->retrytime < MIN_RETRY_TIME)
fr->retrytime = MIN_RETRY_TIME;
if (fr->retrytime > MAX_RETRY_TIME)
fr->retrytime = MAX_RETRY_TIME;
/* Acks' don't get retried */
if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK))
fr->retries = -1;
if (f->frametype == AST_FRAME_VOICE) {
pvt->svoiceformat = f->subclass;
}
if (now) {
res = iax_xmit_frame(fr);
} else
res = iax_reliable_xmit(fr);
} else {
/* Mini-frames have no sequence number */
fr->oseqno = -1;
fr->iseqno = -1;
/* Mini frame will do */
mh = (struct ast_iax2_mini_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_mini_hdr));
mh->callno = htons(fr->callno);
mh->ts = htons(fr->ts & 0xFFFF);
fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
fr->data = mh;
fr->retries = -1;
res = iax_xmit_frame(fr);
}
if( !now && fr!=NULL )
iax_frame_free( fr );
OutputDebugString(L"iax_send out\n");
return res;
}
#if 0
static int iax_predestroy(struct iax_session *pvt)
{
if (!pvt) {
return -1;
}
if (!pvt->alreadygone) {
/* No more pings or lagrq's */
if (pvt->pingid > -1)
ast_sched_del(sched, pvt->pingid);
if (pvt->lagid > -1)
ast_sched_del(sched, pvt->lagid);
if (pvt->autoid > -1)
ast_sched_del(sched, pvt->autoid);
if (pvt->initid > -1)
ast_sched_del(sched, pvt->initid);
pvt->pingid = -1;
pvt->lagid = -1;
pvt->autoid = -1;
pvt->initid = -1;
pvt->alreadygone = 1;
}
return 0;
}
#endif
static int __send_command(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno,
int now, int transfer, int final, int samples)
{
struct ast_frame f;
f.frametype = type;
f.subclass = command;
f.datalen = datalen;
f.samples = samples;
f.mallocd = 0;
f.offset = 0;
#ifdef __GNUC__
f.src = (char *) __FUNCTION__;
#else
f.src = (char *) __FILE__;
#endif
f.data = data;
return iax_send(i, &f, ts, seqno, now, transfer, final);
}
static int send_command(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
{
return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0);
}
static int send_command_final(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
{
#if 0
/* It is assumed that the callno has already been locked */
iax_predestroy(i);
#endif
int r;
r = __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
if (r >= 0) destroy_session(i);
return r;
}
static int send_command_immediate(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
{
return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0);
}
static int send_command_transfer(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen)
{
return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0);
}
static int send_command_samples(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno, int samples)
{
return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, samples);
}
int iax_transfer(struct iax_session *session, char *number)
{
static int res; //Return Code
struct iax_ie_data ied; //IE Data Structure (Stuff To Send)
// Clear The Memory Used For IE Buffer
memset(&ied, 0, sizeof(ied));
// Copy The Transfer Destination Into The IE Structure
iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
// Send The Transfer Command - Asterisk Will Handle The Rest!
res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
// Return Success
return 0;
}
static void stop_transfer(struct iax_session *session)
{
struct iax_sched *sch;
sch = schedq;
while(sch) {
if (sch->frame && (sch->frame->session == session))
sch->frame->retries = -1;
sch = sch->next;
}
} /* stop_transfer */
static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq)
{
session->peercallno = peercallno;
/* Change from transfer to session now */
if (xfr2peer) {
memcpy(&session->peeraddr, &session->transfer, sizeof(session->peeraddr));
memset(&session->transfer, 0, sizeof(session->transfer));
session->transferring = TRANSFER_NONE;
session->transferpeer = 0;
session->transfer_moh = 0;
/* Force retransmission of a real voice packet, and reset all timing */
session->svoiceformat = -1;
session->voiceformat = 0;
}
memset(&session->rxcore, 0, sizeof(session->rxcore));
memset(&session->offset, 0, sizeof(session->offset));
memset(&session->history, 0, sizeof(session->history));
#ifdef NEWJB
{ /* Reset jitterbuffer */
jb_frame frame;
while(jb_getall(session->jb,&frame) == JB_OK)
iax_event_free(frame.data);
jb_reset(session->jb);
}
#endif
session->jitterbuffer = 0;
session->jitter = 0;
session->lag = 0;
if (! preserveSeq)
{
/* Reset sequence numbers */
session->aseqno = 0;
session->oseqno = 0;
session->iseqno = 0;
}
session->lastsent = 0;
session->last_ts = 0;
session->lastvoicets = 0;
session->pingtime = 30;
/* We have to dump anything we were going to (re)transmit now that we've been
transferred since they're all invalid and for the old host. */
stop_transfer(session);
} /* complete_transfer */
int iax_setup_transfer(struct iax_session *org_session, struct iax_session *new_session)
{
int res;
struct iax_ie_data ied0;
struct iax_ie_data ied1;
struct iax_session *s0 = org_session;
struct iax_session *s1 = new_session;
memset(&ied0, 0, sizeof(ied0));
memset(&ied1, 0, sizeof(ied1));
/* reversed setup */
iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &s1->peeraddr);
iax_ie_append_short(&ied0, IAX_IE_CALLNO, s1->peercallno);
iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transfer_id);
iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &s0->peeraddr);
iax_ie_append_short(&ied1, IAX_IE_CALLNO, s0->peercallno);
iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transfer_id);
s0->transfer = s1->peeraddr;
s1->transfer = s0->peeraddr;
s0->transferid = transfer_id;
s1->transferid = transfer_id;
s0->transfercallno = s0->peercallno;
s1->transfercallno = s1->peercallno;
s0->transferring = TRANSFER_BEGIN;
s1->transferring = TRANSFER_BEGIN;
s0->transferpeer = s1->callno;
s1->transferpeer = s0->callno;
transfer_id++;
if (transfer_id > 32767)
transfer_id = 1;
res = send_command(s0, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
if (res < 0) {
return -1;
}
res = send_command(s1, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
if (res < 0) {
return -1;
}
return 0;
}
static int iax_finish_transfer(struct iax_session *s, short new_peer)
{
int res;
struct iax_ie_data ied;
memset(&ied, 0, sizeof(ied));
iax_ie_append_short(&ied, IAX_IE_CALLNO, new_peer);
res = send_command(s, AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied.buf, ied.pos, -1);
complete_transfer(s, new_peer, 0, 1);
return res;
}
static struct iax_session *iax_find_session2(short callno)
{
struct iax_session *cur = sessions;
while(cur) {
if (callno == cur->callno && callno != 0) {
return cur;
}
cur = cur->next;
}
return NULL;
}
static int iax_handle_txready(struct iax_session *s)
{
struct iax_session *s0, *s1;
short s0_org_peer, s1_org_peer;
if (s->transfer_moh) {
s->transfer_moh = 0;
iax_unquelch(s);
}
complete_transfer(s, s->peercallno, 0, 1);
s->transferring = TRANSFER_REL;
s0 = s;
s1 = iax_find_session2(s0->transferpeer);
if (s1 != NULL &&
s1->callno == s0->transferpeer &&
s0->transferring == TRANSFER_REL &&
s1->transferring == TRANSFER_REL) {
s0_org_peer = s0->peercallno;
s1_org_peer = s1->peercallno;
iax_finish_transfer(s0, s1_org_peer);
iax_finish_transfer(s1, s0_org_peer);
return 1;
}
return 0;
}
static void iax_handle_txreject(struct iax_session *s)
{
struct iax_session *s0, *s1;
s0 = s;
s1 = iax_find_session2(s0->transferpeer);
if (s1 != NULL &&
s0->transferpeer == s1->callno &&
s1->transferring) {
if (s1->transfer_moh) {
s1->transfer_moh = 0;
send_command_immediate(s1, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, s1->iseqno);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -