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