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

📄 chan_iax2.c

📁 Asterisk中信道部分的源码 。。。。
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* If no idle thread is available from the regular list, try dynamic */	if (thread == NULL) {		AST_LIST_LOCK(&dynamic_list);		thread = AST_LIST_REMOVE_HEAD(&dynamic_list, list);		/* Make sure we absolutely have a thread... if not, try to make one if allowed */		if (thread == NULL && iaxmaxthreadcount > iaxdynamicthreadcount) {			/* We need to MAKE a thread! */			if ((thread = ast_calloc(1, sizeof(*thread)))) {				thread->threadnum = iaxdynamicthreadnum++;				thread->type = IAX_TYPE_DYNAMIC;				ast_mutex_init(&thread->lock);				ast_cond_init(&thread->cond, NULL);				pthread_attr_init(&attr);				pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);					if (ast_pthread_create(&thread->threadid, &attr, iax2_process_thread, thread)) {					free(thread);					thread = NULL;				} else {					/* All went well and the thread is up, so increment our count */					iaxdynamicthreadcount++;										/* Wait for the thread to be ready before returning it to the caller */					while (!thread->ready_for_signal)						usleep(1);				}			}		}		AST_LIST_UNLOCK(&dynamic_list);	}	/* this thread is not processing a full frame (since it is idle),	   so ensure that the field for the full frame call number is empty */	if (thread)		memset(&thread->ffinfo, 0, sizeof(thread->ffinfo));	return thread;}#ifdef SCHED_MULTITHREADEDstatic int __schedule_action(void (*func)(const void *data), const void *data, const char *funcname){	struct iax2_thread *thread = NULL;	static time_t lasterror;	static time_t t;	thread = find_idle_thread();	if (thread != NULL) {		thread->schedfunc = func;		thread->scheddata = data;		thread->iostate = IAX_IOSTATE_SCHEDREADY;#ifdef DEBUG_SCHED_MULTITHREAD		ast_copy_string(thread->curfunc, funcname, sizeof(thread->curfunc));#endif		signal_condition(&thread->lock, &thread->cond);		return 0;	}	time(&t);	if (t != lasterror && option_debug) 		ast_log(LOG_DEBUG, "Out of idle IAX2 threads for scheduling!\n");	lasterror = t;	return -1;}#define schedule_action(func, data) __schedule_action(func, data, __PRETTY_FUNCTION__)#endifstatic int iax2_sched_add(struct sched_context *con, int when, ast_sched_cb callback, const void *data){	int res;	res = ast_sched_add(con, when, callback, data);	signal_condition(&sched_lock, &sched_cond);	return res;}static int send_ping(const void *data);static void __send_ping(const void *data){	int callno = (long) data;	ast_mutex_lock(&iaxsl[callno]);	if (iaxs[callno]) {		if (iaxs[callno]->peercallno) {			send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);			iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);		} else {			/* I am the schedule, so I'm allowed to do this */			iaxs[callno]->pingid = -1;		}	} else if (option_debug > 0) {		ast_log(LOG_DEBUG, "I was supposed to send a PING with callno %d, but no such call exists (and I cannot remove pingid, either).\n", callno);	}	ast_mutex_unlock(&iaxsl[callno]);}static int send_ping(const void *data){#ifdef SCHED_MULTITHREADED	if (schedule_action(__send_ping, data))#endif				__send_ping(data);	return 0;}static int get_encrypt_methods(const char *s){	int e;	if (!strcasecmp(s, "aes128"))		e = IAX_ENCRYPT_AES128;	else if (ast_true(s))		e = IAX_ENCRYPT_AES128;	else		e = 0;	return e;}static int send_lagrq(const void *data);static void __send_lagrq(const void *data){	int callno = (long) data;	ast_mutex_lock(&iaxsl[callno]);	if (iaxs[callno]) {		if (iaxs[callno]->peercallno) {			send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);			iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);		} else {			/* I am the schedule, so I'm allowed to do this */			iaxs[callno]->lagid = -1;		}	} else {		ast_log(LOG_WARNING, "I was supposed to send a LAGRQ with callno %d, but no such call exists (and I cannot remove lagid, either).\n", callno);	}	ast_mutex_unlock(&iaxsl[callno]);}static int send_lagrq(const void *data){#ifdef SCHED_MULTITHREADED	if (schedule_action(__send_lagrq, data))#endif				__send_lagrq(data);		return 0;}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) {				ast_log(LOG_WARNING, "Can't compress subclass %d\n", subclass);				return 0;			} else				power = x;		}	}	return power | IAX_FLAG_SC_LOG;}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) {		/* special case for 'compressed' -1 */		if (csub == 0xff)			return -1;		else			return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);	}	else		return csub;}/*! * \note The only member of the peer passed here guaranteed to be set is the name field */static int peer_hash_cb(const void *obj, const int flags){	const struct iax2_peer *peer = obj;	return ast_str_hash(peer->name);}/*! * \note The only member of the peer passed here guaranteed to be set is the name field */static int peer_cmp_cb(void *obj, void *arg, int flags){	struct iax2_peer *peer = obj, *peer2 = arg;	return !strcmp(peer->name, peer2->name) ? CMP_MATCH | CMP_STOP : 0;}/*! * \note The only member of the user passed here guaranteed to be set is the name field */static int user_hash_cb(const void *obj, const int flags){	const struct iax2_user *user = obj;	return ast_str_hash(user->name);}/*! * \note The only member of the user passed here guaranteed to be set is the name field */static int user_cmp_cb(void *obj, void *arg, int flags){	struct iax2_user *user = obj, *user2 = arg;	return !strcmp(user->name, user2->name) ? CMP_MATCH | CMP_STOP : 0;}/*! * \note This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno, *       so do not call it with a pvt lock held. */static struct iax2_peer *find_peer(const char *name, int realtime) {	struct iax2_peer *peer = NULL;	struct iax2_peer tmp_peer = {		.name = name,	};	peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);	/* Now go for realtime if applicable */	if(!peer && realtime)		peer = realtime_peer(name, NULL);	return peer;}static struct iax2_peer *peer_ref(struct iax2_peer *peer){	ao2_ref(peer, +1);	return peer;}static inline struct iax2_peer *peer_unref(struct iax2_peer *peer){	ao2_ref(peer, -1);	return NULL;}static inline struct iax2_user *user_ref(struct iax2_user *user){	ao2_ref(user, +1);	return user;}static inline struct iax2_user *user_unref(struct iax2_user *user){	ao2_ref(user, -1);	return NULL;}static int iax2_getpeername(struct sockaddr_in sin, char *host, int len){	struct iax2_peer *peer = NULL;	int res = 0;	struct ao2_iterator i;	i = ao2_iterator_init(peers, 0);	while ((peer = ao2_iterator_next(&i))) {		if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&		    (peer->addr.sin_port == sin.sin_port)) {			ast_copy_string(host, peer->name, len);			peer_unref(peer);			res = 1;			break;		}		peer_unref(peer);	}	if (!peer) {		peer = realtime_peer(NULL, &sin);		if (peer) {			ast_copy_string(host, peer->name, len);			peer_unref(peer);			res = 1;		}	}	return res;}static void iax2_destroy_helper(struct chan_iax2_pvt *pvt){	/* Decrement AUTHREQ count if needed */	if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {		struct iax2_user *user;		struct iax2_user tmp_user = {			.name = pvt->username,		};		user = ao2_find(users, &tmp_user, OBJ_POINTER);		if (user) {			ast_atomic_fetchadd_int(&user->curauthreq, -1);			user = user_unref(user);       		}		ast_clear_flag(pvt, IAX_MAXAUTHREQ);	}	/* No more pings or lagrq's */	AST_SCHED_DEL(sched, pvt->pingid);	AST_SCHED_DEL(sched, pvt->lagid);	AST_SCHED_DEL(sched, pvt->autoid);	AST_SCHED_DEL(sched, pvt->authid);	AST_SCHED_DEL(sched, pvt->initid);	AST_SCHED_DEL(sched, pvt->jbid);}static void store_by_peercallno(struct chan_iax2_pvt *pvt){	if (!pvt->peercallno) {		ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");		return;	}	ao2_link(iax_peercallno_pvts, pvt);}static void remove_by_peercallno(struct chan_iax2_pvt *pvt){	if (!pvt->peercallno) {		ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");		return;	}	ao2_unlink(iax_peercallno_pvts, pvt);}static void update_max_trunk(void){	int max = TRUNK_CALL_START;	int x;	/* XXX Prolly don't need locks here XXX */	for (x = TRUNK_CALL_START; x < ARRAY_LEN(iaxs) - 1; x++) {		if (iaxs[x]) {			max = x + 1;		}	}	maxtrunkcall = max;	if (option_debug && iaxdebug)		ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);}static void iax2_frame_free(struct iax_frame *fr){	AST_SCHED_DEL(sched, fr->retrans);	iax_frame_free(fr);}static void iax2_destroy(int callno){	struct chan_iax2_pvt *pvt;	struct ast_channel *owner;retry:	pvt = iaxs[callno];	gettimeofday(&lastused[callno], NULL);		owner = pvt ? pvt->owner : NULL;	if (owner) {		if (ast_mutex_trylock(&owner->lock)) {			if (option_debug > 2)				ast_log(LOG_DEBUG, "Avoiding IAX destroy deadlock\n");			DEADLOCK_AVOIDANCE(&iaxsl[callno]);			goto retry;		}	}	if (!owner && iaxs[callno]) {		AST_SCHED_DEL_SPINLOCK(sched, iaxs[callno]->lagid, &iaxsl[callno]);		AST_SCHED_DEL_SPINLOCK(sched, iaxs[callno]->pingid, &iaxsl[callno]);		iaxs[callno] = NULL;	}	if (pvt) {		if (!owner) {			pvt->owner = NULL;		} else {			/* If there's an owner, prod it to give up */			/* It is ok to use ast_queue_hangup() here instead of iax2_queue_hangup()			 * because we already hold the owner channel lock. */			ast_queue_hangup(owner);		}		if (pvt->peercallno) {			remove_by_peercallno(pvt);		}		if (!owner) {			ao2_ref(pvt, -1);			pvt = NULL;		}	}	if (owner) {		ast_mutex_unlock(&owner->lock);	}	if (callno & 0x4000) {		update_max_trunk();	}}static void pvt_destructor(void *obj){	struct chan_iax2_pvt *pvt = obj;	struct iax_frame *cur = NULL;	iax2_destroy_helper(pvt);	/* Already gone */	ast_set_flag(pvt, IAX_ALREADYGONE);		AST_LIST_LOCK(&iaxq.queue);	AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {		/* Cancel any pending transmissions */		if (cur->callno == pvt->callno) { 			cur->retries = -1;		}	}	AST_LIST_UNLOCK(&iaxq.queue);	if (pvt->reg) {		pvt->reg->callno = 0;	}	if (!pvt->owner) {		jb_frame frame;		if (pvt->vars) {		    ast_variables_destroy(pvt->vars);		    pvt->vars = NULL;		}		while (jb_getall(pvt->jb, &frame) == JB_OK) {

⌨️ 快捷键说明

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