⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iax.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 5 页
字号:
	    }
	    
#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 + -