📄 chan_iax2.c
字号:
/* 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 + -