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

📄 iax.c

📁 iax协议Source Code
💻 C
📖 第 1 页 / 共 5 页
字号:
		(cur->peeraddr.sin_port == sin->sin_port)) {		/* This is the main host */		if ((cur->peercallno == callno) || 			((dcallno == cur->callno) && (cur->peercallno) == -1)) {			/* 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;}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 (match(sin, callno, dcallno, cur))			return cur;		cur = cur->next;	}	if (makenew && (dcallno == -1)) {		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;		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#define FUDGE 1static struct iax_event *schedule_delivery(struct iax_event *e, unsigned int ts){	/* 	 * This is the core of the IAX jitterbuffer delivery mechanism: 	 * Dynamically adjust the jitterbuffer and decide how long to wait	 * before delivering the packet.	 */	int ms, x;	int drops[MEMORY_SIZE];	int min, max=0, maxone=0, y, z, match;#ifdef EXTREME_DEBUG		DEBU(G "[%p] We are at %d, packet is for %d\n", e->session, calc_rxstamp(e->session), ts);#endif	#ifdef VOICE_SMOOTHING	if (e->etype == IAX_EVENT_VOICE) {		/* Smooth voices if we know enough about the format */		switch(e->event.voice.format) {		case AST_FORMAT_GSM:			/* GSM frames are 20 ms long, although there could be periods of 			   silence.  If the time is < 50 ms, assume it ought to be 20 ms */			if (ts - e->session->lastts < 50)  				ts = e->session->lastts + 20;#ifdef EXTREME_DEBUG			display_time(ts);#endif			break;		default:			/* Can't do anything */		}		e->session->lastts = ts;	}#endif		/* How many ms from now should this packet be delivered? (remember	   this can be a negative number, too */	ms = calc_rxstamp(e->session) - 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		   update the timestamp appropriately. */		ms -= 65536;	}	if (ms < -32768) {		/* We got this packet out of order.  Lets add 65536 to it to bring it into our new		   time frame */		ms += 65536;	}#if 0		printf("rxstamp is %d, timestamp is %d, ms is %d\n", calc_rxstamp(e->session), ts, ms);#endif	/* Rotate history queue.  Leading 0's are irrelevant. */	for (x=0; x < MEMORY_SIZE - 1; x++) 		e->session->history[x] = e->session->history[x+1];		/* Add new entry for this time */	e->session->history[x] = ms;		/* We have to find the maximum and minimum time delay we've had to deliver. */	min = e->session->history[0];	for (z=0;z < iax_dropcount + 1; z++) {		/* We drop the top iax_dropcount entries.  iax_dropcount represents		   a tradeoff between quality of voice and latency.  3% drop seems to		   be unnoticable to the client and can significantly improve latency.  		   We add one more to our droplist, but that's the one we actually use, 		   and don't drop.  */		max = -99999999;		for (x=0;x<MEMORY_SIZE;x++) {			if (max < e->session->history[x]) {				/* New candidate value.  Make sure we haven't dropped it. */				match=0;				for(y=0;!match && (y<z); y++) 					match |= (drops[y] == x);				/* If there is no match, this is our new maximum */				if (!match) {					max = e->session->history[x];					maxone = x;				}			}			if (!z) {				/* First pass, calcualte our minimum, too */				if (min > e->session->history[x])					min = e->session->history[x];			}		}		drops[z] = maxone;	}	/* Again, just for reference.  The "jitter buffer" is the max.  The difference	   is the perceived jitter correction. */	e->session->jitter = max - min;		/* If the jitter buffer is substantially too large, shrink it, slowly enough	   that the client won't notice ;-) . */	if (max < e->session->jitterbuffer - max_extra_jitterbuffer) {#ifdef EXTREME_DEBUG		DEBU(G "Shrinking jitterbuffer (target = %d, current = %d...\n", max, e->session->jitterbuffer);#endif		e->session->jitterbuffer -= 2;	}			/* Keep the jitter buffer from becoming unreasonably large */	if (max > min + max_jitterbuffer) {		DEBU(G "Constraining jitter buffer (min = %d, max = %d)...\n", min, max);		max = min + max_jitterbuffer;	}		/* If the jitter buffer is too small, we immediately grow our buffer to	   accomodate */	if (max > e->session->jitterbuffer)		e->session->jitterbuffer = max;		/* Start with our jitter buffer delay, and subtract the lateness (or earliness).	   Remember these times are all relative to the first packet, so their absolute	   values are really irrelevant. */	ms = e->session->jitterbuffer - ms - IAX_SCHEDULE_FUZZ;		/* If the jitterbuffer is disabled, always deliver immediately */	if (!iax_use_jitterbuffer)		ms = 0;		if (ms < 1) {#ifdef EXTREME_DEBUG		DEBU(G "Calculated delay is only %d\n", ms);#endif		if ((ms > -4) || (e->etype != IAX_EVENT_VOICE)) {			/* Return the event immediately if it's it's less than 3 milliseconds			   too late, or if it's not voice (believe me, you don't want to			   just drop a hangup frame because it's late, or a ping, or some such.			   That kinda ruins retransmissions too ;-) */			return e;		}		DEBU(G "(not so) Silently dropping a packet (ms = %d)\n", ms);		/* Silently discard this as if it were to be delivered */		free(e->event.voice.data);		free(e);		return NULL;	}	/* We need this to be delivered in the future, so we use our scheduler */	iax_sched_event(e, NULL, ms);#ifdef EXTREME_DEBUG	DEBU(G "Delivering packet in %d ms\n", ms);#endif	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#ifndef	WIN32inline#endifchar *extract(char *src, char *string){	/* Extract and duplicate what we need from a string */	char *s, *t;	s = strstr(src, string);	if (s) {		s += strlen(string);		s = strdup(s);		/* End at ; */		t = strchr(s, ';');		if (t) {			*t = '\0';		}	}	return s;		}static void send_ack(struct iax_session *session, struct iax_full_hdr *fhi){	short tco;	struct iax_frame f;	struct iax_full_hdr h;	struct iax_full_hdr *fh = &h;	/* To ack, we use the same sequence number and	   timestamp, just swapping the source and destination	    */	memcpy(fh, fhi, sizeof(h));	tco = ntohs(fh->callno) & ~IAX_FLAG_FULL;#ifdef EXTREME_DEBUG	DEBU(G "Acking peer's callno %d (our callno %d) seqno %d\n", tco, (int)session->callno, ntohs(fh->seqno));#endif	fh->dcallno = htons(tco);	fh->callno = htons((short) (session->callno | IAX_FLAG_FULL));	fh->type = AST_FRAME_IAX;	fh->csub = IAX_COMMAND_ACK;	f.retries = -1;	f.session = session;	f.data = fh;	f.datalen = sizeof(struct iax_full_hdr);	f.transferpacket = 0;	iax_xmit_frame(&f);}static struct iax_event *iax_header_to_event(struct iax_session *session,											 struct iax_full_hdr *fh,											 int datalen){	struct iax_event *e;	struct iax_sched *sch;	unsigned int ts;	int subclass = uncompress_subclass(fh->csub);	char *text = fh->data;	char *s;	char *methods;	int nowts;	ts = ntohl(fh->ts);	session->last_ts = ts;	e = (struct iax_event *)malloc(sizeof(struct iax_event));#ifdef DEBUG_SUPPORT	showframe(NULL, fh, 1);#endif	/* Get things going with it, timestamp wise, if we	   haven't already. */	if ((fh->type != AST_FRAME_IAX) ||	    ((subclass != IAX_COMMAND_ACK) && 		 (subclass != IAX_COMMAND_INVAL) &&		 (subclass != IAX_COMMAND_REJECT) &&		 (subclass != IAX_COMMAND_TXCNT) &&		 (subclass != IAX_COMMAND_TXACC)))			send_ack(session, fh);	/* Null terminate text */	if (text)		text[datalen] = '\0';				if (e) {		memset(e, 0, sizeof(struct iax_event));		e->session = session;		switch(fh->type) {		case AST_FRAME_DTMF:			e->etype = IAX_EVENT_DTMF;			e->event.dtmf.digit = subclass;			return schedule_delivery(e, ts);		case AST_FRAME_VOICE:			e->etype = IAX_EVENT_VOICE;			e->event.voice.format = subclass;			session->voiceformat = subclass;			if (datalen) {				e->event.voice.data = (char *)malloc(datalen);				e->event.voice.datalen = datalen;				if (e->event.voice.data) {					memcpy(e->event.voice.data, fh->data, datalen);				} else {					free(e);					e = NULL;					DEBU(G "Out of memory\n");					return e;				}			} else {				/* Empty voice frame?  Maybe it could happen... */				e->event.voice.data = NULL;				e->event.voice.datalen = 0;			}			return schedule_delivery(e, ts);		case AST_FRAME_IAX:			switch(subclass) {			case IAX_COMMAND_NEW:				/* This is a new, incoming call */				e->etype = IAX_EVENT_CONNECT;				/* Now we search for each each component of				   the call, if present. */				e->event.connect.callerid = extract(text, "callerid=");				e->event.connect.dnid = extract(text, "dnid=");				e->event.connect.exten = extract(text, "exten=");				e->event.connect.context = extract(text, "context=");				e->event.connect.username = extract(text, "username=");				e->event.connect.language = extract(text, "language=");				s = extract(text, "formats=");				if (s) 					e->event.connect.formats = atoi(s);				else					e->event.connect.formats = 0;				s = extract(text, "version=");				if (s)					e->event.connect.version = atoi(s);				else					e->event.connect.version = 0;				e->event.connect.hostname = strdup(inet_ntoa(e->session->peeraddr.sin_addr));				return schedule_delivery(e, ts);			case IAX_COMMAND_AUTHREQ:				/* This is a new, incoming call */				e->etype = IAX_EVENT_AUTHRQ;				/* Now we search for each each component of				   the call, if present. */				e->event.authrequest.username = extract(text, "username=");				methods = extract(text, "methods=");				e->event.authrequest.authmethods = 0;				if (methods) {					if (strstr(methods, "md5"))						e->event.authrequest.authmethods |= IAX_AUTHMETHOD_MD5;					if (strstr(methods, "plaintext"))						e->event.authrequest.authmethods |= IAX_AUTHMETHOD_PLAINTEXT;					free(methods);				}				e->event.authrequest.challenge = extract(text, "challenge=");				return schedule_delivery(e, ts);			case IAX_COMMAND_HANGUP:				e->etype = IAX_EVENT_HANGUP;				if (datalen)					e->event.hangup.byemsg = strdup(text);				else					e->event.hangup.byemsg = NULL;				return schedule_delivery(e, ts);			case IAX_COMMAND_INVAL:				e->etype = IAX_EVENT_HANGUP;				e->event.hangup.byemsg = NULL;				return schedule_delivery(e, ts);			case IAX_COMMAND_REJECT:				e->etype = IAX_EVENT_REJECT;				e->event.reject.reason = (text ? strdup(text) : NULL);				return schedule_delivery(e, ts);			case IAX_COMMAND_ACK:				if (ntohs(fh->seqno) <= session->iseqno) {					/* We just need to go through and acknowledge the matching					   packet(s) that are planned to be retransmitted */					sch = schedq;					while(sch) {						if (sch->frame && (sch->frame->session == session) &&							(((struct iax_full_hdr *)(sch->frame->data))->seqno ==								fh->seqno))								sch->frame->retries = -1;						sch = sch->next;					}					if (ntohs(fh->seqno) == session->iseqno) 						session->iseqno++;				} else					DEBU(G "Received ACK for %d, expecting %d\n", ntohs(fh->seqno), session->iseqno);				free(e);				return NULL;				break;			case IAX_COMMAND_LAGRQ:				/* Pass this along for later handling */				e->etype = IAX_EVENT_LAGRQ;				e->event.lagrq.ts = ts;				return schedule_delivery(e, ts);			case IAX_COMMAND_PING:				/* Just immediately reply */				e->etype = IAX_EVENT_PING;				e->event.ping.ts = ts;				e->event.ping.seqno = ntohs(fh->seqno);				return schedule_delivery(e, ts);			case IAX_COMMAND_ACCEPT:				e->etype = IAX_EVENT_ACCEPT;				return schedule_delivery(e, ts);			case IAX_COMMAND_REGACK:				e->etype = IAX_EVENT_REGREP;				e->event.regreply.status = IAX_REG_SUCCESS;				e->event.regreply.ourip = extract(text, "yourip=");				s = extract(text, "yourport=");				e->event.regreply.ourport = s ? atoi(s) : 0;				if (s) free(s);				s = extract(text, "refresh=");				e->event.regreply.refresh = s ? atoi(s) : 0;				if (s) free(s);				s = extract(text, "callerid=");				e->event.regreply.callerid = s;				return schedule_delivery(e, ts);			case IAX_COMMAND_REGAUTH:				/* Ooh, don't bother telling the user, just do it */				e->etype = IAX_EVENT_REREQUEST;				s = extract(text, "methods=");				if (!s) {					DEBU(G "No methods specified?\n");					free(e);					return NULL;				}				strncpy(session->methods, s, sizeof(session->methods)-1);				s = extract(text, "challenge=");				if (s) 					strncpy(session->challenge, s, sizeof(session->challenge)-1);				else					strcpy(session->challenge, "");				iax_do_event(session, e);				free(e);				return NULL;			case IAX_COMMAND_REGREJ:				e->etype = IAX_EVENT_REGREP;				e->event.regreply.status = IAX_REG_REJECT;				e->event.regreply.ourip = NULL;				e->event.regreply.ourport = 0;				s = extract(text, "refresh=");				e->event.regreply.refresh = s ? atoi(s) : 0;				return schedule_delivery(e, ts);			case IAX_COMMAND_LAGRP:				e->etype = IAX_EVENT_LAGRP;				nowts = calc_timestamp(session, 0);				e->event.lag.lag = nowts - ts;				e->event.lag.jitter = session->jitter;				/* Can't call schedule_delivery since timestamp is non-normal */				return e;			case IAX_COMMAND_TXREQ:				/* Received transfer request, start the process */				s = extract(text, "remip=");				if (s) {					if (inet_aton(s, &session->transfer.sin_addr)) {						s = extract(text, "remport=");						if (s) {							session->transfer.sin_port = htons(atoi(s));							free(s);							s = extract(text, "remcall=");							if (s) {

⌨️ 快捷键说明

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