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

📄 chan_iax2.c

📁 Asterisk中信道部分的源码 。。。。
💻 C
📖 第 1 页 / 共 5 页
字号:
			iax2_frame_free(frame.data);		}		jb_destroy(pvt->jb);		ast_string_field_free_memory(pvt);	}}static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host){	struct chan_iax2_pvt *tmp;	jb_conf jbconf;	if (!(tmp = ao2_alloc(sizeof(*tmp), pvt_destructor))) {		return NULL;	}	if (ast_string_field_init(tmp, 32)) {		ao2_ref(tmp, -1);		tmp = NULL;		return NULL;	}			tmp->prefs = prefs;	tmp->callno = 0;	tmp->peercallno = 0;	tmp->transfercallno = 0;	tmp->bridgecallno = 0;	tmp->pingid = -1;	tmp->lagid = -1;	tmp->autoid = -1;	tmp->authid = -1;	tmp->initid = -1;	ast_string_field_set(tmp,exten, "s");	ast_string_field_set(tmp,host, host);	tmp->jb = jb_new();	tmp->jbid = -1;	jbconf.max_jitterbuf = maxjitterbuffer;	jbconf.resync_threshold = resyncthreshold;	jbconf.max_contig_interp = maxjitterinterps;	jb_setconf(tmp->jb,&jbconf);	return tmp;}static struct iax_frame *iaxfrdup2(struct iax_frame *fr){	struct iax_frame *new = iax_frame_new(DIRECTION_INGRESS, fr->af.datalen, fr->cacheable);	if (new) {		size_t afdatalen = new->afdatalen;		memcpy(new, fr, sizeof(*new));		iax_frame_wrap(new, &fr->af);		new->afdatalen = afdatalen;		new->data = NULL;		new->datalen = 0;		new->direction = DIRECTION_INGRESS;		new->retrans = -1;	}	return new;}#define NEW_PREVENT 	0#define NEW_ALLOW 	1#define NEW_FORCE 	2static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur, int check_dcallno){	if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&		(cur->addr.sin_port == sin->sin_port)) {		/* This is the main host */		if ( (cur->peercallno == 0 || cur->peercallno == callno) &&			 (check_dcallno ? dcallno == cur->callno : 1) ) {			/* That's us.  Be sure we keep track of the peer call number */			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) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))			return 1;	}	return 0;}static void update_max_nontrunk(void){	int max = 1;	int x;	/* XXX Prolly don't need locks here XXX */	for (x=1;x<TRUNK_CALL_START - 1; x++) {		if (iaxs[x])			max = x + 1;	}	maxnontrunkcall = max;	if (option_debug && iaxdebug)		ast_log(LOG_DEBUG, "New max nontrunk callno is %d\n", max);}static int make_trunk(unsigned short callno, int locked){	int x;	int res= 0;	struct timeval now;	if (iaxs[callno]->oseqno) {		ast_log(LOG_WARNING, "Can't make trunk once a call has started!\n");		return -1;	}	if (callno & TRUNK_CALL_START) {		ast_log(LOG_WARNING, "Call %d is already a trunk\n", callno);		return -1;	}	gettimeofday(&now, NULL);	for (x = TRUNK_CALL_START; x < ARRAY_LEN(iaxs) - 1; x++) {		ast_mutex_lock(&iaxsl[x]);		if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {			/* Update the two timers that should have been started */			/*!			 * \note We delete these before switching the slot, because if			 * they fire in the meantime, they will generate a warning.			 */			AST_SCHED_DEL(sched, iaxs[callno]->pingid);			AST_SCHED_DEL(sched, iaxs[callno]->lagid);			iaxs[x] = iaxs[callno];			iaxs[x]->callno = x;			iaxs[callno] = NULL;			iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);			iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);			if (locked)				ast_mutex_unlock(&iaxsl[callno]);			res = x;			if (!locked)				ast_mutex_unlock(&iaxsl[x]);			break;		}		ast_mutex_unlock(&iaxsl[x]);	}	if (x >= ARRAY_LEN(iaxs) - 1) {		ast_log(LOG_WARNING, "Unable to trunk call: Insufficient space\n");		return -1;	}	if (option_debug)		ast_log(LOG_DEBUG, "Made call %d into trunk call %d\n", callno, x);	/* We move this call from a non-trunked to a trunked call */	update_max_trunk();	update_max_nontrunk();	return res;}/*! * \note Calling this function while holding another pvt lock can cause a deadlock. */static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno){	int res = 0;	int x;	struct timeval now;	char host[80];	if (new <= NEW_ALLOW) { 		if (callno) { 			struct chan_iax2_pvt *pvt; 			struct chan_iax2_pvt tmp_pvt = { 				.callno = dcallno, 				.peercallno = callno, 				/* hack!! */ 				.frames_received = check_dcallno, 			};  			memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));  			if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) { 				if (return_locked) { 					ast_mutex_lock(&iaxsl[pvt->callno]); 				} 				res = pvt->callno; 				ao2_ref(pvt, -1); 				pvt = NULL; 				return res; 			} 		}		/* This will occur on the first response to a message that we initiated,		 * such as a PING. */		if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(sin, callno, dcallno, iaxs[dcallno], check_dcallno)) {			iaxs[dcallno]->peercallno = callno;			res = dcallno;			store_by_peercallno(iaxs[dcallno]);			return res;		}#ifdef IAX_OLD_FIND		/* If we get here, we SHOULD NOT find a call structure for this		   callno; if we do, it means that there is a call structure that		   has a peer callno but did NOT get entered into the hash table,		   which is bad.		   If we find a call structure using this old, slow method, output a log		   message so we'll know about it. After a few months of leaving this in		   place, if we don't hear about people seeing these messages, we can		   remove this code for good.		*/		for (x = 1; !res && x < maxnontrunkcall; x++) {			ast_mutex_lock(&iaxsl[x]);			if (iaxs[x]) {				/* Look for an exact match */				if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {					res = x;				}			}			if (!res || !return_locked)				ast_mutex_unlock(&iaxsl[x]);		}		for (x = TRUNK_CALL_START; !res && x < maxtrunkcall; x++) {			ast_mutex_lock(&iaxsl[x]);			if (iaxs[x]) {				/* Look for an exact match */				if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {					res = x;				}			}			if (!res || !return_locked)				ast_mutex_unlock(&iaxsl[x]);		}		if (res) {			ast_log(LOG_WARNING, "Old call search code found call number %d that was not in hash table!\n", res);		}#endif	}	if (!res && (new >= NEW_ALLOW)) {		int start, found = 0;		/* It may seem odd that we look through the peer list for a name for		 * this *incoming* call.  Well, it is weird.  However, users don't		 * have an IP address/port number that we can match against.  So,		 * this is just checking for a peer that has that IP/port and		 * assuming that we have a user of the same name.  This isn't always		 * correct, but it will be changed if needed after authentication. */		if (!iax2_getpeername(*sin, host, sizeof(host)))			snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));		now = ast_tvnow();		start = 2 + (ast_random() % (TRUNK_CALL_START - 1));		for (x = start; 1; x++) {			if (x == TRUNK_CALL_START) {				x = 1;				continue;			}			/* Find first unused call number that hasn't been used in a while */			ast_mutex_lock(&iaxsl[x]);			if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {				found = 1;				break;			}			ast_mutex_unlock(&iaxsl[x]);						if (x == start - 1) {				break;			}		}		/* We've still got lock held if we found a spot */		if (x == start - 1 && !found) {			ast_log(LOG_WARNING, "No more space\n");			return 0;		}		iaxs[x] = new_iax(sin, host);		update_max_nontrunk();		if (iaxs[x]) {			if (option_debug && iaxdebug)				ast_log(LOG_DEBUG, "Creating new call structure %d\n", x);			iaxs[x]->sockfd = sockfd;			iaxs[x]->addr.sin_port = sin->sin_port;			iaxs[x]->addr.sin_family = sin->sin_family;			iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;			iaxs[x]->peercallno = callno;			iaxs[x]->callno = x;			iaxs[x]->pingtime = DEFAULT_RETRY_TIME;			iaxs[x]->expiry = min_reg_expire;			iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);			iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);			iaxs[x]->amaflags = amaflags;			ast_copy_flags(iaxs[x], (&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);						ast_string_field_set(iaxs[x], accountcode, accountcode);			ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);			ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);			if (iaxs[x]->peercallno) {				store_by_peercallno(iaxs[x]);			}		} else {			ast_log(LOG_WARNING, "Out of resources\n");			ast_mutex_unlock(&iaxsl[x]);			return 0;		}		if (!return_locked)			ast_mutex_unlock(&iaxsl[x]);		res = x;	}	return res;}static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {	return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);}static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {	return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);}/*! * \brief Queue a frame to a call's owning asterisk channel * * \pre This function assumes that iaxsl[callno] is locked when called. * * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] * was valid before calling it, it may no longer be valid after calling it. * This function may unlock and lock the mutex associated with this callno, * meaning that another thread may grab it and destroy the call. */static int iax2_queue_frame(int callno, struct ast_frame *f){	for (;;) {		if (iaxs[callno] && iaxs[callno]->owner) {			if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {				/* Avoid deadlock by pausing and trying again */				DEADLOCK_AVOIDANCE(&iaxsl[callno]);			} else {				ast_queue_frame(iaxs[callno]->owner, f);				ast_mutex_unlock(&iaxs[callno]->owner->lock);				break;			}		} else			break;	}	return 0;}/*! * \brief Queue a hangup frame on the ast_channel owner * * This function queues a hangup frame on the owner of the IAX2 pvt struct that * is active for the given call number. * * \pre Assumes lock for callno is already held. * * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] * was valid before calling it, it may no longer be valid after calling it. * This function may unlock and lock the mutex associated with this callno, * meaning that another thread may grab it and destroy the call. */static int iax2_queue_hangup(int callno){	for (;;) {		if (iaxs[callno] && iaxs[callno]->owner) {			if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {				/* Avoid deadlock by pausing and trying again */				DEADLOCK_AVOIDANCE(&iaxsl[callno]);			} else {				ast_queue_hangup(iaxs[callno]->owner);				ast_mutex_unlock(&iaxs[callno]->owner->lock);				break;			}		} else			break;	}	return 0;}/*! * \brief Queue a control frame on the ast_channel owner * * This function queues a control frame on the owner of the IAX2 pvt struct that * is active for the given call number. * * \pre Assumes lock for callno is already held. * * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] * was valid before calling it, it may no longer be valid after calling it. * This function may unlock and lock the mutex associated with this callno, * meaning that another thread may grab it and destroy the call. */static int iax2_queue_control_data(int callno, 	enum ast_control_frame_type control, const void *data, size_t datalen){	for (;;) {		if (iaxs[callno] && iaxs[callno]->owner) {			if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {				/* Avoid deadlock by pausing and trying again */				DEADLOCK_AVOIDANCE(&iaxsl[callno]);			} else {				ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);				ast_mutex_unlock(&iaxs[callno]->owner->lock);				break;			}		} else			break;	}	return 0;}static void destroy_firmware(struct iax_firmware *cur){	/* Close firmware */	if (cur->fwh) {		munmap((void*)cur->fwh, ntohl(cur->fwh->datalen) + sizeof(*(cur->fwh)));	}	close(cur->fd);	free(cur);}static int try_firmware(char *s){	struct stat stbuf;	struct iax_firmware *cur;	int ifd;	int fd;	int res;		struct ast_iax2_firmware_header *fwh, fwh2;	struct MD5Context md5;	unsigned char sum[16];	unsigned char buf[1024];	int len, chunk;	char *s2;	char *last;	s2 = alloca(strlen(s) + 100);	if (!s2) {		ast_log(LOG_WARNING, "Alloca failed!\n");		return -1;	}	last = strrchr(s, '/');	if (last)		last++;	else		last = s;	snprintf(s2, strlen(s) + 100, "/var/tmp/%s-%ld", last, (unsigned long)ast_random());	res = stat(s, &stbuf);	if (res < 0) {		ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno));		return -1;	}	/* Make sure it's not a directory */	if (S_ISDIR(stbuf.st_mode))		return -1;	ifd = open(s, O_RDONLY);	if (ifd < 0) {		ast_log(LOG_WARNING, "Cannot open '%s': %s\n", s, strerror(errno));		return -1;	}	fd = open(s2, O_RDWR | O_CREAT | O_EXCL, 0600);

⌨️ 快捷键说明

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