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

📄 iax.c

📁 IAX client库, 一个VOIP的库. 支持H.323和SIP, PBX就是采用的它
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	return s;}static int iax_session_valid(struct iax_session *session){	/* Return -1 on a valid iax session pointer, 0 on a failure */	struct iax_session *cur = sessions;	while(cur) {		if (session == cur)			return -1;		cur = cur->next;	}	return 0;}int iax_get_netstats(struct iax_session *session, int *rtt, struct iax_netstat *local, struct iax_netstat *remote) {  if(!iax_session_valid(session)) return -1;  *rtt = session->pingtime;  *remote = session->remote_netstats;#ifdef NEWJB  {      jb_info stats;      jb_getinfo(session->jb, &stats);      local->jitter = stats.jitter;      /* XXX: should be short-term loss pct.. */      if(stats.frames_in == 0) stats.frames_in = LONG_MAX;      local->losspct = stats.frames_lost * 100 / stats.frames_in;      local->losscnt = stats.frames_lost;      local->packets = stats.frames_in;      local->delay = stats.current - stats.min;      local->dropped = stats.frames_dropped;      local->ooo = stats.frames_ooo;  }#endif  return 0;}static void add_ms(struct timeval *tv, int ms) {  tv->tv_usec += ms * 1000;  if(tv->tv_usec > 1000000) {      tv->tv_usec -= 1000000;      tv->tv_sec++;  }  if(tv->tv_usec < 0) {      tv->tv_usec += 1000000;      tv->tv_sec--;  }}static int calc_timestamp(struct iax_session *session, unsigned int ts, struct ast_frame *f){	int ms;	struct timeval tv;	int voice = 0;	int genuine = 0;	if (f && f->frametype == AST_FRAME_VOICE) {		voice = 1;	} else if (!f || f->frametype == AST_FRAME_IAX) {		genuine = 1;	}			/* If this is the first packet we're sending, get our	   offset now. */	if (!session->offset.tv_sec && !session->offset.tv_usec)		gettimeofday(&session->offset, NULL);	/* If the timestamp is specified, just use their specified	   timestamp no matter what.  Usually this is done for	   special cases.  */	if (ts)		return ts;		/* Otherwise calculate the timestamp from the current time */	gettimeofday(&tv, NULL);			/* Calculate the number of milliseconds since we sent the first packet */	ms = (tv.tv_sec - session->offset.tv_sec) * 1000 +		 (tv.tv_usec - session->offset.tv_usec) / 1000;	if (ms < 0) 		ms = 0;	if(voice) {#ifdef USE_VOICE_TS_PREDICTION		/* If we haven't most recently sent silence, and we're		 * close in time, use predicted time */		if(session->notsilenttx && abs(ms - session->nextpred) <= 240) {		    /* Adjust our txcore, keeping voice and non-voice		     * synchronized */		    add_ms(&session->offset, (int)(ms - session->nextpred)/10);		    		    if(!session->nextpred)					session->nextpred = ms; 		    ms = session->nextpred; 		} else {		    /* in this case, just use the actual time, since		     * we're either way off (shouldn't happen), or we're		     * ending a silent period -- and seed the next predicted		     * time.  Also, round ms to the next multiple of		     * frame size (so our silent periods are multiples		     * of frame size too) */		    int diff = ms % (f->samples / 8);		    if(diff)			ms += f->samples/8 - diff;		    session->nextpred = ms; 		}#else		if(ms <= session->lastsent)			ms = session->lastsent + 3;#endif		session->notsilenttx = 1;	} else {		/* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) 		   if appropriate unless it's a genuine frame */		if (genuine) {			if (ms <= session->lastsent)				ms = session->lastsent + 3;		} else if (abs(ms - session->lastsent) <= 240) {			ms = session->lastsent + 3;		}	      	}	/* Record the last sent packet for future reference */	/* unless an AST_FRAME_IAX */	if (!genuine)		session->lastsent = ms;#ifdef USE_VOICE_TS_PREDICTION	/* set next predicted ts based on 8khz samples */	if(voice)	    session->nextpred = session->nextpred + f->samples / 8;#endif	return ms;}static int iax_xmit_frame(struct iax_frame *f){	struct ast_iax2_full_hdr *h = (f->data);	/* Send the frame raw */#ifdef DEBUG_SUPPORT	if (ntohs(h->scallno) & IAX_FLAG_FULL)		iax_showframe(f, NULL, 0, f->transfer ? 						&(f->session->transfer) :					&(f->session->peeraddr), f->datalen - sizeof(struct ast_iax2_full_hdr));#endif	return f->session->sendto(netfd, (const char *) f->data, f->datalen,		IAX_SOCKOPTS,					f->transfer ? 						(struct sockaddr *)&(f->session->transfer) :					(struct sockaddr *)&(f->session->peeraddr), sizeof(f->session->peeraddr));}static int iax_reliable_xmit(struct iax_frame *f){	struct iax_frame *fc;	struct ast_iax2_full_hdr *fh;	fh = (struct ast_iax2_full_hdr *) f->data;	if (!fh->type) {		DEBU(G "Asked to reliably transmit a non-packet.  Crashing.\n");		*((char *)0)=0;	}	fc = (struct iax_frame *)malloc(sizeof(struct iax_frame));	if (fc) {		/* Make a copy of the frame */		memcpy(fc, f, sizeof(struct iax_frame));		/* And a copy of the data if applicable */		if (!fc->data || !fc->datalen) {			IAXERROR "No frame data?");			DEBU(G "No frame data?\n");			return -1;		} else {			fc->data = (char *)malloc(fc->datalen);			if (!fc->data) {				DEBU(G "Out of memory\n");				IAXERROR "Out of memory\n");				return -1;			}			memcpy(fc->data, f->data, f->datalen);			iax_sched_add(NULL, fc, NULL, NULL, fc->retrytime);			return iax_xmit_frame(fc);		}	} else		return -1;}void iax_set_networking(sendto_t st, recvfrom_t rf){	iax_sendto = st;	iax_recvfrom = rf;}int iax_init(int preferredportno){	int portno = preferredportno;	struct sockaddr_in sin;	int sinlen;	int flags;	if(iax_recvfrom == recvfrom) {	    if (netfd > -1) {		    /* Sokay, just don't do anything */		    DEBU(G "Already initialized.");		    return 0;	    }	    netfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);	    if (netfd < 0) {		    DEBU(G "Unable to allocate UDP socket\n");		    IAXERROR "Unable to allocate UDP socket\n");		    return -1;	    }	    	    if (preferredportno == 0) 		    preferredportno = IAX_DEFAULT_PORTNO;		    	    if (preferredportno > 0) {		    sin.sin_family = AF_INET;		    sin.sin_addr.s_addr = 0;		    sin.sin_port = htons((short)preferredportno);		    if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {			    DEBU(G "Unable to bind to preferred port.  Using random one instead.");		    }	    }	    sinlen = sizeof(sin);	    if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) {		    close(netfd);		    netfd = -1;		    DEBU(G "Unable to figure out what I'm bound to.");		    IAXERROR "Unable to determine bound port number.");	    }#ifdef	WIN32	    flags = 1;	    if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) {		    _close(netfd);		    netfd = -1;		    DEBU(G "Unable to set non-blocking mode.");		    IAXERROR "Unable to set non-blocking mode.");	    }	    #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);	}	srand(time(NULL));	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;		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);	}	return res;}#if 0static 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;}#endifstatic int __send_command(struct iax_session *i, char type, int command, unsigned int ts, 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 = __FUNCTION__;#else	f.src = __FILE__;#endif	f.data = data;	return iax_send(i, &f, ts, seqno, now, transfer, final);}

⌨️ 快捷键说明

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