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

📄 iax.c

📁 IAX协议客户端源码
💻 C
📖 第 1 页 / 共 5 页
字号:
static int iax_regauth_reply(struct iax_session *session, char *password, char *challenge, int methods){	char reply[16];	struct MD5Context md5;	char realreply[256];	struct iax_ie_data ied;	memset(&ied, 0, sizeof(ied));	iax_ie_append_str(&ied, IAX_IE_USERNAME, session->username);	if ((methods & IAX_AUTHMETHOD_MD5) && challenge) {		MD5Init(&md5);		MD5Update(&md5, (const unsigned char *) challenge,				(unsigned int)strlen(challenge));		MD5Update(&md5, (const unsigned char *) password,				(unsigned int)strlen(password));		MD5Final((unsigned char *) reply, &md5);		memset(realreply, 0, sizeof(realreply));		convert_reply(realreply, (unsigned char *) reply);		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, realreply);	} else {		iax_ie_append_str(&ied, IAX_IE_PASSWORD, password);	}	if (strlen(session->unregreason)) {		/* Non-zero unregreason length indicates REGREL */		iax_ie_append_str(&ied, IAX_IE_CAUSE, session->unregreason);		return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREL, 0, ied.buf, ied.pos, -1);	} else {		iax_ie_append_short(&ied, IAX_IE_REFRESH, session->refresh);		return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);	}}int iax_dial(struct iax_session *session, char *number){	struct iax_ie_data ied;	memset(&ied, 0, sizeof(ied));	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, number);	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DIAL, 0, ied.buf, ied.pos, -1);}int iax_quelch(struct iax_session *session){	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, NULL, 0, -1);}int iax_unquelch(struct iax_session *session){	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, -1);}int iax_dialplan_request(struct iax_session *session, char *number){	struct iax_ie_data ied;	memset(&ied, 0, sizeof(ied));	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, number);	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DPREQ, 0, ied.buf, ied.pos, -1);}static inline int which_bit(unsigned int i){	char x;	for(x = 0; x < 32; x++) {		if ((1U << x) == i) {			return x + 1;		}	}	return 0;}char iax_pref_codec_add(struct iax_session *session, unsigned int format){	int diff = (int) 'A';	session->codec_order[session->codec_order_len++] = (which_bit(format)) + diff;	session->codec_order[session->codec_order_len] = '\0';	return session->codec_order[session->codec_order_len-1];}void iax_pref_codec_del(struct iax_session *session, unsigned int format){	int diff = (int) 'A';	int x;	char old[32];	char remove = which_bit(format) + diff;	strncpy(old, session->codec_order, sizeof(old));	session->codec_order_len = 0;	for (x = 0;  x < (int) strlen(old);  x++) {		if (old[x] != remove) {			session->codec_order[session->codec_order_len++] = old[x];		}	}	session->codec_order[session->codec_order_len] = '\0';}int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len){	int diff = (int) 'A';	int x;	for (x = 0; x < session->codec_order_len && x < len; x++) {		array[x] = (1 << (session->codec_order[x] - diff - 1));	}	return x;}int iax_call(struct iax_session *session, const char *cidnum, const char *cidname, const char *ich, const char *lang, int wait, int formats, int capabilities){	char tmp[256]="";	char *part1, *part2;	int res;	int portno;	char *username, *hostname, *secret, *context, *exten, *dnid;	struct iax_ie_data ied;	struct hostent *hp;	/* We start by parsing up the temporary variable which is of the form of:	   [user@]peer[:portno][/exten[@context]] */	if (!ich) {		IAXERROR "Invalid IAX Call Handle\n");		DEBU(G "Invalid IAX Call Handle\n");		return -1;	}	memset(&ied, 0, sizeof(ied));	strncpy(tmp, ich, sizeof(tmp) - 1);	iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);	if (cidnum)		iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, cidnum);	if (cidname)		iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, cidname);	if (session->codec_order_len) {		iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, session->codec_order);	}	session->capability = capabilities;	session->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)session, 2 * 1000);	/* XXX We should have a preferred format XXX */	iax_ie_append_int(&ied, IAX_IE_FORMAT, formats);	iax_ie_append_int(&ied, IAX_IE_CAPABILITY, capabilities);	if (lang)		iax_ie_append_str(&ied, IAX_IE_LANGUAGE, lang);	/* Part 1 is [user[:password]@]peer[:port] */	part1 = strtok(tmp, "/");	/* Part 2 is exten[@context] if it is anything all */	part2 = strtok(NULL, "/");	if (strchr(part1, '@')) {		username = strtok(part1, "@");		hostname = strtok(NULL, "@");	} else {		username = NULL;		hostname = part1;	}	if (username && strchr(username, ':')) {		username = strtok(username, ":");		secret = strtok(NULL, ":");	} else		secret = NULL;	if(username)		strncpy(session->username, username, sizeof(session->username) - 1);	if(secret)		strncpy(session->secret, secret, sizeof(session->secret) - 1);	if (strchr(hostname, ':')) {		strtok(hostname, ":");		portno = atoi(strtok(NULL, ":"));	} else {		portno = IAX_DEFAULT_PORTNO;	}	if (part2) {		exten = strtok(part2, "@");		dnid = exten;		context = strtok(NULL, "@");	} else {		exten = NULL;		dnid = NULL;		context = NULL;	}	if (username)		iax_ie_append_str(&ied, IAX_IE_USERNAME, username);	if (exten && strlen(exten))		iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, exten);	if (dnid && strlen(dnid))		iax_ie_append_str(&ied, IAX_IE_DNID, dnid);	if (context && strlen(context))		iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context);	/* Setup host connection */	hp = gethostbyname(hostname);	if (!hp) {		snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", hostname);		return -1;	}	memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));	session->peeraddr.sin_port = htons(portno);	session->peeraddr.sin_family = AF_INET;	res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);	if (res < 0)		return res;	if (wait) {		DEBU(G "Waiting not yet implemented\n");		return -1;	}	return res;}static int calc_rxstamp(struct iax_session *session){	struct timeval tv;	int ms;	if (!session->rxcore.tv_sec && !session->rxcore.tv_usec) {		session->rxcore = iax_tvnow();	}	tv = iax_tvnow();	ms = (tv.tv_sec - session->rxcore.tv_sec) * 1000 +		 (tv.tv_usec - session->rxcore.tv_usec) / 1000;		return ms;}#ifdef notdef_cruftstatic int match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur){	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&		(cur->peeraddr.sin_port == sin->sin_port)) {		/* This is the main host */		if ((cur->peercallno == callno) ||			((dcallno == cur->callno) && !cur->peercallno)) {			/* That's us.  Be sure we keep track of the peer call number */			cur->peercallno = callno;			return 1;		}	}	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)			return 1;	}	return 0;}#endif/* splitted match into 2 passes otherwise causing problem of matching   up the wrong session using the dcallno and the peercallno because   during a transfer (2 IAX channels on the same client/system) the   same peercallno (from two different asterisks) exist in more than   one session. */static int forward_match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur){	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)		{			return 1;		}	}	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&		(cur->peeraddr.sin_port == sin->sin_port)) {		if (dcallno == cur->callno && dcallno != 0)  {			/* That's us.  Be sure we keep track of the peer call number */			if (cur->peercallno == 0) {				cur->peercallno = callno;			}			else if ( cur->peercallno != callno ) 			{				// print a warning when the callno's don't match				fprintf( stderr, "WARNING: peercallno does not match callno"					", peercallno => %d, callno => %d, dcallno => %d",					cur->peercallno, callno, dcallno ) ;				return 0 ;			}			return 1;		}	}	return 0;}static int reverse_match(struct sockaddr_in *sin, short callno, struct iax_session *cur){	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 (callno == cur->peercallno)  {			return 1;		}	}	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&		(cur->peeraddr.sin_port == sin->sin_port)) {		if (callno == cur->peercallno)  {			return 1;		}	}	return 0;}static struct iax_session *iax_find_session(struct sockaddr_in *sin,		short callno,		short dcallno,		int makenew){	struct iax_session *cur = sessions;	while(cur) {		if (forward_match(sin, callno, dcallno, cur)) {			return cur;		}		cur = cur->next;	}	cur = sessions;	while(cur) {		if (reverse_match(sin, callno, cur)) {			return cur;		}		cur = cur->next;	}	if (makenew && !dcallno) {		cur = iax_session_new();		cur->peercallno = callno;		cur->peeraddr.sin_addr.s_addr = sin->sin_addr.s_addr;		cur->peeraddr.sin_port = sin->sin_port;		cur->peeraddr.sin_family = AF_INET;		cur->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)cur, 2 * 1000);		DEBU(G "Making new session, peer callno %d, our callno %d\n", callno, cur->callno);	} else {		DEBU(G "No session, peer = %d, us = %d\n", callno, dcallno);	}	return cur;}#ifdef EXTREME_DEBUGstatic int display_time(int ms){	static int oldms = -1;	if (oldms < 0) {		DEBU(G "First measure\n");		oldms = ms;		return 0;	}	DEBU(G "Time from last frame is %d ms\n", ms - oldms);	oldms = ms;	return 0;}#endif/* From chan_iax2/steve davies:  need to get permission from steve or digium, I guess */static long unwrap_timestamp(long ts, long last){	int x;	if ( (ts & 0xFFFF0000) == (last & 0xFFFF0000) ) {		x = ts - last;		if (x < -50000) {			/* Sudden big jump backwards in timestamp:			   What likely happened here is that miniframe			   timestamp has circled but we haven't gotten the			   update from the main packet. We'll just pretend			   that we did, and update the timestamp			   appropriately. */			ts = ( (last & 0xFFFF0000) + 0x10000) | (ts & 0xFFFF);			DEBU(G "schedule_delivery: pushed forward timestamp\n");		}		if (x > 50000) {			/* Sudden apparent big jump forwards in timestamp:			   What's likely happened is this is an old miniframe			   belonging to the previous top-16-bit timestamp that			   has turned up out of order. Adjust the timestamp			   appropriately. */			ts = ( (last & 0xFFFF0000) - 0x10000) | (ts & 0xFFFF);			DEBU(G "schedule_delivery: pushed back timestamp\n");		}	}	else if ( (ts & 0xFFFF8000L) == (last & 0xFFFF8000L) ) {		x = ts - last;		if (x < -50000) {			/* Sudden big jump backwards in timestamp:			   What likely happened here is that miniframe			   timestamp has circled but we haven't gotten the			   update from the main packet. We'll just pretend			   that we did, and update the timestamp			   appropriately. */			ts = ( (last & 0xFFFF8000L) + 0x10000) | (ts & 0xFFFF);			DEBU(G "schedule_delivery: pushed forward timestamp\n");		}		if (x > 50000) {			/* Sudden apparent big jump forwards in timestamp:			 * What's likely happened is this is an old miniframe			 * belonging to the previous top-16-bit timestamp that			 * has turned up out of order. Adjust the timestamp			 * appropriately. */			ts = ( (last & 0xFFFF8000L) - 0x10000) | (ts & 0xFFFF);			DEBU(G "schedule_delivery: pushed back timestamp\n");		}	}	return ts;}static struct iax_event *schedule_delivery(struct iax_event *e, unsigned int ts, int updatehistory){	/*	 * This is the core of the IAX jitterbuffer delivery mechanism:	 * Dynamically adjust the jitterbuffer and decide how long to wait	 * before delivering the packet.	 */#ifdef EXTREME_DEBUG	DEBU(G "[%p] We are at %d, packet is for %d\n", e->session, calc_rxstamp(e->session), ts);#endif	/* insert into jitterbuffer */	/* TODO: Perhaps we could act immediately if it's not droppable and late */	if ( !iax_use_jitterbuffer ||			(e->etype == IAX_EVENT_VIDEO &&			 video_bypass_jitterbuffer) )	{		iax_sched_add(e, NULL, NULL, NULL, 0);		return NULL;	} else	{		int type = JB_TYPE_CONTROL;		int len = 0;		if(e->etype == IAX_EVENT_VOICE)		{			type = JB_TYPE_VOICE;			/* The frame time only has an effect for voice */			len = get_sample_cnt(e) / 8;		} else if(e->etype == IAX_EVENT_VIDEO)		{			type = JB_TYPE_VIDEO;		} else if(e->etype == IAX_EVENT_CNG)		{			type = JB_TYPE_SILENCE;		}		/* unwrap timestamp */		ts = unwrap_timestamp(ts,e->session->last_ts);		/* move forward last_ts if it's greater. We do this _after_		 * unwrapping, because asterisk _still_ has cases where it		 * doesn't send full frames when it ought to */		if(ts > e->session->last_ts)		{			e->session->last_ts = ts;		}		if(jb_put(e->session->jb, e, type, len, ts,					calc_rxstamp(e->session)) == JB_DROP)		{			iax_event_free(e);		}	}	return NULL;}static int uncompress_subclass(unsigned char csub){	/* If the SC_LOG flag is set, return 2^csub otherwise csub */	if (csub & IAX_FLAG_SC_LOG)		return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);	else		return csub;}static void iax_handle_vnak(struct iax_session *session, struct ast_iax2_full_hdr *fh){	struct iax_sched *sch, *list, *l, *tmp;	/*	 * According to the IAX2 02 draft, we MUST immediately retransmit all frames	 * with higher sequence number than the VNAK's iseqno	 * However, it seems that the right thing to do would be to retransmit	 * frames with sequence numbers higher OR EQUAL to VNAK's iseqno.	 */	sch = schedq;	list = NULL;	while ( sch != NULL )	{		if ( sch->frame != NULL &&		     sch->frame->session == session		   )		{		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -