iax.c

来自「IAX client库, 一个VOIP的库. 支持H.323和SIP, PBX就」· C语言 代码 · 共 2,416 行 · 第 1/5 页

C
2,416
字号
		"LAGRP  ",		"REGREQ ",		"REGAUTH",		"REGACK ",		"REGREJ ",		"REGREL ",		"VNAK   ",		"DPREQ  ",		"DPREP  ",		"DIAL   ",		"TXREQ  ",		"TXCNT  ",		"TXACC  ",		"TXREADY",		"TXREL  ",		"TXREJ  "	};	char *cmds[] = {		"(0?)",		"HANGUP ",		"RING   ",		"RINGING",		"ANSWER ",		"BUSY   ",		"TKOFFHK ",		"OFFHOOK" };	struct iax_full_hdr *fh;	char retries[20];	char class2[20];	char subclass2[20];	char *class;	char *subclass;	if (f) {		fh = f->data;		snprintf(retries, sizeof(retries), "%03d", f->retries);	} else {		strcpy(retries, "N/A");		fh = fhi;	}	if (!(ntohs(fh->callno) & IAX_FLAG_FULL)) {		/* Don't mess with mini-frames */		return;	}	if ((fh->type >= sizeof(frames)/sizeof(char *)) || (fh->type < 0)) {		snprintf(class2, sizeof(class2), "(%d?)", fh->type);		class = class2;	} else {		class = frames[(int)fh->type];	}	if (fh->type == AST_FRAME_DTMF) {		sprintf(subclass2, "%c", fh->csub);		subclass = subclass2;	} else if (fh->type == AST_FRAME_IAX) {		if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {			snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);			subclass = subclass2;		} else {			subclass = iaxs[(int)fh->csub];		}	} else if (fh->type == AST_FRAME_CONTROL) {		if (fh->csub > sizeof(cmds)/sizeof(char *)) {			snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);			subclass = subclass2;		} else {			subclass = cmds[(int)fh->csub];		}	} else {		snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);		subclass = subclass2;	}	if (debug) {		fprintf(stderr, "%s-Frame Retry[%s] -- Seqno: %2.2d  Type: %s Subclass: %s\n", 	(rx ? "Rx" : "Tx"),	retries, ntohs(fh->seqno), class, subclass);		fprintf(stderr, "   Timestamp: %05dms  Callno: %4.4d  DCall: %4.4d\n", 	ntohl(fh->ts),	ntohs(fh->callno) & ~IAX_FLAG_FULL, (short) ntohs(fh->dcallno));	}}#endifstatic int iax_xmit_frame(struct iax_frame *f){	/* Send the frame raw */#ifdef DEBUG_SUPPORT	showframe(f, NULL, 0);#endif	return sendto(netfd, (const char *) f->data, f->datalen,		SENDSOCKOPTS, f->transferpacket ? 				(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 iax_full_hdr *fh;	fh = (struct iax_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_event(NULL, fc, fc->retrytime);			return iax_xmit_frame(fc);		}	} else		return -1;}int iax_init(int preferredportno){#ifdef WIN32	WSADATA foop;#endif	int portno = preferredportno;	struct sockaddr_in sin;	int sinlen;	int flags;		if (netfd > -1) {		/* Sokay, just don't do anything */		DEBU(G "Already initialized.");		return 0;	}#ifdef WIN32	/* start up the windoze-socket layer stuff */	if (WSAStartup(0x0101,&foop)) {		fprintf(stderr,"Fatal error: Falied to startup windows sockets\n");		return -1;	}#endif	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;	DEBU(G "Started on port %d\n", portno);	return portno;	}void iax_shutdown() {#ifdef WIN32	closesocket(netfd);	WSACleanup();#endif}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;}int iax_do_event(struct iax_session *session, struct iax_event *event){	struct iax_frame f;	int left;	struct hostent *hp;	unsigned int ts;	char buf[32768];	struct iax_full_hdr *fh = (struct iax_full_hdr *)buf;	struct iax_mini_hdr *mh = (struct iax_mini_hdr *)buf;	struct MD5Context md5;	char reply[32];	char realreply[80];	char *requeststr = fh->data;#define MYSNPRINTF snprintf(requeststr + strlen(requeststr), sizeof(buf) - sizeof(struct iax_full_hdr) - strlen(requeststr), 	bzero(buf, sizeof(buf));	/* Default some things in the frame */	f.session = session;	f.data = buf;	f.datalen = sizeof(struct iax_full_hdr);	left = sizeof(buf) - f.datalen;	f.retries = maxretries;	f.transferpacket = 0;		/* Assume a full header and default some things */	fh->callno = htons((short)(session->callno | IAX_FLAG_FULL));	fh->dcallno = htons((short)session->peercallno);	/* Calculate timestamp */	fh->ts = htonl(calc_timestamp(session, 0));		/* Start by using twice the pingtime */	f.retrytime = session->pingtime * 2;	if (f.retrytime > MAX_RETRY_TIME)		f.retrytime = MAX_RETRY_TIME;	if (f.retrytime < MIN_RETRY_TIME)		f.retrytime = MIN_RETRY_TIME;		f.next = NULL;	/* Some sanity checks */	if (!event) {		DEBU(G "Event is null?\n");		IAXERROR "Null event");		return -1;	}	if (!session)		session = event->session;	if (!iax_session_valid(session)) {		DEBU(G "Session invalid for sending event\n");		IAXERROR "Invalid session for transmitting event");	}	/* Send (possibly reliably) the correct frame given the kind	   of event requested */	switch(event->etype) {	case IAX_EVENT_CONNECT:		/* Connect first */		hp = gethostbyname(event->event.connect.hostname);		if (!hp) {			snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", event->event.connect.hostname);			return -1;		}		memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));		session->peeraddr.sin_port = htons(event->event.connect.portno);		session->peeraddr.sin_family = AF_INET;		fh->type = AST_FRAME_IAX;		fh->csub = IAX_COMMAND_NEW;		fh->seqno = htons(session->oseqno++);		if (event->event.connect.exten)			MYSNPRINTF "exten=%s;", event->event.connect.exten);		if (event->event.connect.callerid)			MYSNPRINTF "callerid=%s;", event->event.connect.callerid);				if (event->event.connect.dnid)			MYSNPRINTF "dnid=%s;", event->event.connect.dnid);		if (event->event.connect.context)			MYSNPRINTF "context=%s;", event->event.connect.context);		if (event->event.connect.username)			MYSNPRINTF "username=%s;", event->event.connect.username);		if (event->event.connect.language)			MYSNPRINTF "language=%s;", event->event.connect.language);		MYSNPRINTF "formats=%d;", sformats);		MYSNPRINTF "version=%d;", IAX_PROTO_VERSION);		f.datalen += strlen(requeststr);		if (event->event.connect.username)			strncpy(session->username, event->event.connect.username, sizeof(session->username) - 1);		else			strcpy(session->username, "");		if (event->event.connect.secret)			strncpy(session->secret, event->event.connect.secret, sizeof(session->secret) - 1);		else			strcpy(session->secret, "");		iax_reliable_xmit(&f);		break;	case IAX_EVENT_REREQUEST:		fh->type = AST_FRAME_IAX;		fh->csub = IAX_COMMAND_REGREQ;		fh->seqno = htons(session->oseqno++);		MYSNPRINTF "peer=%s;refresh=%d;", session->peer, session->refresh);		if (strstr(session->methods, "md5")) {			MD5Init(&md5);			MD5Update(&md5, (const unsigned char *) &session->challenge[0], strlen(session->challenge));			MD5Update(&md5, (const unsigned char *) &session->secret[0], strlen(session->secret));			MD5Final((unsigned char *) reply, &md5);			memset(realreply, 0, sizeof(realreply));			convert_reply(realreply, (unsigned char *) &reply[0]);			MYSNPRINTF "md5secret=%s;", realreply);		} else {			MYSNPRINTF "secret=%s;", session->secret);		}		f.datalen += strlen(requeststr);		iax_reliable_xmit(&f);		break;	case IAX_EVENT_REGREQ:		/* Connect first */		hp = gethostbyname(event->event.regrequest.server);		if (!hp) {			snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", event->event.regrequest.server);			return -1;		}		memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));		session->peeraddr.sin_port = htons(event->event.regrequest.portno);		session->peeraddr.sin_family = AF_INET;		fh->type = AST_FRAME_IAX;		fh->csub = IAX_COMMAND_REGREQ;		fh->seqno = htons(session->oseqno++);		if (event->event.regrequest.secret)			strncpy(session->secret, event->event.regrequest.secret, sizeof(session->secret)-1);		else			strcpy(session->secret, "");		if (event->event.regrequest.peer) {			MYSNPRINTF "peer=%s;", event->event.regrequest.peer);			strncpy(session->peer, event->event.regrequest.peer, sizeof(session->peer)-1);		} else			strcpy(session->peer, "");		if (event->event.regrequest.refresh) {			MYSNPRINTF "refresh=%d;", event->event.regrequest.refresh);					session->refresh = event->event.regrequest.refresh;		} else			session->refresh = 0;		f.datalen += strlen(requeststr);		iax_reliable_xmit(&f);		break;	case IAX_EVENT_AUTHRP:		fh->type = AST_FRAME_IAX;		fh->csub = IAX_COMMAND_AUTHREP;		fh->seqno = htons(session->oseqno++);		if (event->event.authreply.authmethod == IAX_AUTHMETHOD_MD5) {			snprintf(requeststr, left, "md5secret=%s;", event->event.authreply.reply);		} else if (event->event.authreply.authmethod == IAX_AUTHMETHOD_PLAINTEXT) {			snprintf(requeststr, left, "secret=%s;", event->event.authreply.reply);		} else {			DEBU(G "Unknown auth method: %d\n", event->event.authreply.authmethod);			IAXERROR "Invalid authentication method %d\n", event->event.authreply.authmethod);			return -1;		}		f.datalen += strlen(requeststr);		iax_reliable_xmit(&f);		break;	case IAX_EVENT_LAGRP:		/* Special case -- return the original timestamp in the message instead of our		   own. */		fh->type = AST_FRAME_IAX;		fh->csub = IAX_COMMAND_LAGRP;		fh->ts = htonl(event->event.lagrq.ts);		fh->seqno = htons(session->oseqno++);		iax_reliable_xmit(&f);		break;	case IAX_EVENT_DTMF:		/* Send a DTMF tone as a reliable transmission -- easy */		fh->type = AST_FRAME_DTMF;		fh->seqno = htons(session->oseqno++);		fh->csub = event->event.dtmf.digit;		iax_reliable_xmit(&f);		break;	case IAX_EVENT_RINGA:		/* Announce that we are ringing */		fh->type = AST_FRAME_CONTROL;		fh->seqno = htons(session->oseqno++);		fh->csub = AST_CONTROL_RINGING;		iax_reliable_xmit(&f);		break;	case IAX_EVENT_HANGUP:		fh->type = AST_FRAME_IAX;		fh->seqno = htons(session->oseqno++);		fh->csub = IAX_COMMAND_HANGUP;		if (event->event.hangup.byemsg) {			strncpy(fh->data, event->event.hangup.byemsg, left-1);			f.datalen += strlen(fh->data);		}		/* XXX Not really reliable since we turn right around and kill it XXX */		iax_reliable_xmit(&f);		destroy_session(session);		break;	case IAX_EVENT_REJECT:		fh->type = AST_FRAME_IAX;		fh->seqno = htons(session->oseqno++);		fh->csub = IAX_COMMAND_REJECT;		strncpy(fh->data, event->event.reject.reason, left-1);		f.datalen += strlen(fh->data);		/* XXX Not really reliable since we turn right around and kill it XXX */		iax_reliable_xmit(&f);		destroy_session(session);		break;	case IAX_EVENT_BUSY:		fh->type = AST_FRAME_CONTROL;		fh->seqno = htons(session->oseqno++);		fh->csub = AST_CONTROL_BUSY;		/* XXX Not really reliable since we turn right around and kill it XXX */		iax_reliable_xmit(&f);		destroy_session(session);		break;	case IAX_EVENT_ACCEPT:		fh->type = AST_FRAME_IAX;		fh->seqno = htons(session->oseqno++);		fh->csub = IAX_COMMAND_ACCEPT;		f.datalen += snprintf((char *)(fh->data), left, "formats=%d;", sformats);		f.datalen++;		iax_reliable_xmit(&f);		break;	case IAX_EVENT_LAGRQ:		fh->type = AST_FRAME_IAX;		fh->seqno = htons(session->oseqno++);		fh->csub = IAX_COMMAND_LAGRQ;		iax_reliable_xmit(&f);		break;	case IAX_EVENT_ANSWER:		fh->type = AST_FRAME_CONTROL;		fh->seqno = htons(session->oseqno++);		fh->csub = AST_CONTROL_ANSWER;		iax_reliable_xmit(&f);		break;	case IAX_EVENT_PONG:		fh->type = AST_FRAME_IAX;

⌨️ 快捷键说明

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