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

📄 chan_iax2.c

📁 Asterisk中信道部分的源码 。。。。
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (fd < 0) {		ast_log(LOG_WARNING, "Cannot open '%s' for writing: %s\n", s2, strerror(errno));		close(ifd);		return -1;	}	/* Unlink our newly created file */	unlink(s2);		/* Now copy the firmware into it */	len = stbuf.st_size;	while(len) {		chunk = len;		if (chunk > sizeof(buf))			chunk = sizeof(buf);		res = read(ifd, buf, chunk);		if (res != chunk) {			ast_log(LOG_WARNING, "Only read %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));			close(ifd);			close(fd);			return -1;		}		res = write(fd, buf, chunk);		if (res != chunk) {			ast_log(LOG_WARNING, "Only write %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));			close(ifd);			close(fd);			return -1;		}		len -= chunk;	}	close(ifd);	/* Return to the beginning */	lseek(fd, 0, SEEK_SET);	if ((res = read(fd, &fwh2, sizeof(fwh2))) != sizeof(fwh2)) {		ast_log(LOG_WARNING, "Unable to read firmware header in '%s'\n", s);		close(fd);		return -1;	}	if (ntohl(fwh2.magic) != IAX_FIRMWARE_MAGIC) {		ast_log(LOG_WARNING, "'%s' is not a valid firmware file\n", s);		close(fd);		return -1;	}	if (ntohl(fwh2.datalen) != (stbuf.st_size - sizeof(fwh2))) {		ast_log(LOG_WARNING, "Invalid data length in firmware '%s'\n", s);		close(fd);		return -1;	}	if (fwh2.devname[sizeof(fwh2.devname) - 1] || ast_strlen_zero((char *)fwh2.devname)) {		ast_log(LOG_WARNING, "No or invalid device type specified for '%s'\n", s);		close(fd);		return -1;	}	fwh = (struct ast_iax2_firmware_header*)mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 	if (fwh == (void *) -1) {		ast_log(LOG_WARNING, "mmap failed: %s\n", strerror(errno));		close(fd);		return -1;	}	MD5Init(&md5);	MD5Update(&md5, fwh->data, ntohl(fwh->datalen));	MD5Final(sum, &md5);	if (memcmp(sum, fwh->chksum, sizeof(sum))) {		ast_log(LOG_WARNING, "Firmware file '%s' fails checksum\n", s);		munmap((void*)fwh, stbuf.st_size);		close(fd);		return -1;	}	cur = waresl.wares;	while(cur) {		if (!strcmp((char *)cur->fwh->devname, (char *)fwh->devname)) {			/* Found a candidate */			if (cur->dead || (ntohs(cur->fwh->version) < ntohs(fwh->version)))				/* The version we have on loaded is older, load this one instead */				break;			/* This version is no newer than what we have.  Don't worry about it.			   We'll consider it a proper load anyhow though */			munmap((void*)fwh, stbuf.st_size);			close(fd);			return 0;		}		cur = cur->next;	}	if (!cur) {		/* Allocate a new one and link it */		if ((cur = ast_calloc(1, sizeof(*cur)))) {			cur->fd = -1;			cur->next = waresl.wares;			waresl.wares = cur;		}	}	if (cur) {		if (cur->fwh) {			munmap((void*)cur->fwh, cur->mmaplen);		}		if (cur->fd > -1)			close(cur->fd);		cur->fwh = fwh;		cur->fd = fd;		cur->mmaplen = stbuf.st_size;		cur->dead = 0;	}	return 0;}static int iax_check_version(char *dev){	int res = 0;	struct iax_firmware *cur;	if (!ast_strlen_zero(dev)) {		ast_mutex_lock(&waresl.lock);		cur = waresl.wares;		while(cur) {			if (!strcmp(dev, (char *)cur->fwh->devname)) {				res = ntohs(cur->fwh->version);				break;			}			cur = cur->next;		}		ast_mutex_unlock(&waresl.lock);	}	return res;}static int iax_firmware_append(struct iax_ie_data *ied, const unsigned char *dev, unsigned int desc){	int res = -1;	unsigned int bs = desc & 0xff;	unsigned int start = (desc >> 8) & 0xffffff;	unsigned int bytes;	struct iax_firmware *cur;	if (!ast_strlen_zero((char *)dev) && bs) {		start *= bs;		ast_mutex_lock(&waresl.lock);		cur = waresl.wares;		while(cur) {			if (!strcmp((char *)dev, (char *)cur->fwh->devname)) {				iax_ie_append_int(ied, IAX_IE_FWBLOCKDESC, desc);				if (start < ntohl(cur->fwh->datalen)) {					bytes = ntohl(cur->fwh->datalen) - start;					if (bytes > bs)						bytes = bs;					iax_ie_append_raw(ied, IAX_IE_FWBLOCKDATA, cur->fwh->data + start, bytes);				} else {					bytes = 0;					iax_ie_append(ied, IAX_IE_FWBLOCKDATA);				}				if (bytes == bs)					res = 0;				else					res = 1;				break;			}			cur = cur->next;		}		ast_mutex_unlock(&waresl.lock);	}	return res;}static void reload_firmware(int unload){	struct iax_firmware *cur, *curl, *curp;	DIR *fwd;	struct dirent *de;	char dir[256];	char fn[256];	/* Mark all as dead */	ast_mutex_lock(&waresl.lock);	cur = waresl.wares;	while(cur) {		cur->dead = 1;		cur = cur->next;	}	/* Now that we've freed them, load the new ones */	if (!unload) {		snprintf(dir, sizeof(dir), "%s/firmware/iax", (char *)ast_config_AST_DATA_DIR);		fwd = opendir(dir);		if (fwd) {			while((de = readdir(fwd))) {				if (de->d_name[0] != '.') {					snprintf(fn, sizeof(fn), "%s/%s", dir, de->d_name);					if (!try_firmware(fn)) {						if (option_verbose > 1)							ast_verbose(VERBOSE_PREFIX_2 "Loaded firmware '%s'\n", de->d_name);					}				}			}			closedir(fwd);		} else 			ast_log(LOG_WARNING, "Error opening firmware directory '%s': %s\n", dir, strerror(errno));	}	/* Clean up leftovers */	cur = waresl.wares;	curp = NULL;	while(cur) {		curl = cur;		cur = cur->next;		if (curl->dead) {			if (curp) {				curp->next = cur;			} else {				waresl.wares = cur;			}			destroy_firmware(curl);		} else {			curp = cur;		}	}	ast_mutex_unlock(&waresl.lock);}/*! * \note 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 calls iax2_queue_frame(), which may unlock and lock the mutex  * associated with this callno, meaning that another thread may grab it and destroy the call. */static int __do_deliver(void *data){	/* Just deliver the packet by using queueing.  This is called by	  the IAX thread with the iaxsl lock held. */	struct iax_frame *fr = data;	fr->retrans = -1;	ast_clear_flag(&fr->af, AST_FRFLAG_HAS_TIMING_INFO);	if (iaxs[fr->callno] && !ast_test_flag(iaxs[fr->callno], IAX_ALREADYGONE))		iax2_queue_frame(fr->callno, &fr->af);	/* Free our iax frame */	iax2_frame_free(fr);	/* And don't run again */	return 0;}static int handle_error(void){	/* XXX Ideally we should figure out why an error occured and then abort those	   rather than continuing to try.  Unfortunately, the published interface does	   not seem to work XXX */#if 0	struct sockaddr_in *sin;	int res;	struct msghdr m;	struct sock_extended_err e;	m.msg_name = NULL;	m.msg_namelen = 0;	m.msg_iov = NULL;	m.msg_control = &e;	m.msg_controllen = sizeof(e);	m.msg_flags = 0;	res = recvmsg(netsocket, &m, MSG_ERRQUEUE);	if (res < 0)		ast_log(LOG_WARNING, "Error detected, but unable to read error: %s\n", strerror(errno));	else {		if (m.msg_controllen) {			sin = (struct sockaddr_in *)SO_EE_OFFENDER(&e);			if (sin) 				ast_log(LOG_WARNING, "Receive error from %s\n", ast_inet_ntoa(sin->sin_addr));			else				ast_log(LOG_WARNING, "No address detected??\n");		} else {			ast_log(LOG_WARNING, "Local error: %s\n", strerror(e.ee_errno));		}	}#endif	return 0;}static int transmit_trunk(struct iax_frame *f, struct sockaddr_in *sin, int sockfd){	int res;	res = sendto(sockfd, f->data, f->datalen, 0,(struct sockaddr *)sin,					sizeof(*sin));	if (res < 0) {		if (option_debug)			ast_log(LOG_DEBUG, "Received error: %s\n", strerror(errno));		handle_error();	} else		res = 0;	return res;}static int send_packet(struct iax_frame *f){	int res;	int callno = f->callno;	/* Don't send if there was an error, but return error instead */	if (!callno || !iaxs[callno] || iaxs[callno]->error)	    return -1;		/* Called with iaxsl held */	if (option_debug > 2 && iaxdebug)		ast_log(LOG_DEBUG, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));	if (f->transfer) {		if (iaxdebug)			iax_showframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));		res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer,					sizeof(iaxs[callno]->transfer));	} else {		if (iaxdebug)			iax_showframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr));		res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr,					sizeof(iaxs[callno]->addr));	}	if (res < 0) {		if (option_debug && iaxdebug)			ast_log(LOG_DEBUG, "Received error: %s\n", strerror(errno));		handle_error();	} else		res = 0;	return res;}/*! * \note Since this function calls iax2_queue_hangup(), the pvt struct *       for the given call number may disappear during its execution. */static int iax2_predestroy(int callno){	struct ast_channel *c;	struct chan_iax2_pvt *pvt = iaxs[callno];	if (!pvt)		return -1;	if (!ast_test_flag(pvt, IAX_ALREADYGONE)) {		iax2_destroy_helper(pvt);		ast_set_flag(pvt, IAX_ALREADYGONE);		}	c = pvt->owner;	if (c) {		c->tech_pvt = NULL;		iax2_queue_hangup(callno);		pvt->owner = NULL;		ast_module_unref(ast_module_info->self);	}	return 0;}static int update_packet(struct iax_frame *f){	/* Called with iaxsl lock held, and iaxs[callno] non-NULL */	struct ast_iax2_full_hdr *fh = f->data;	/* Mark this as a retransmission */	fh->dcallno = ntohs(IAX_FLAG_RETRANS | f->dcallno);	/* Update iseqno */	f->iseqno = iaxs[f->callno]->iseqno;	fh->iseqno = f->iseqno;	return 0;}static int attempt_transmit(const void *data);static void __attempt_transmit(const void *data){	/* Attempt to transmit the frame to the remote peer...	   Called without iaxsl held. */	struct iax_frame *f = (struct iax_frame *)data;	int freeme=0;	int callno = f->callno;	/* Make sure this call is still active */	if (callno) 		ast_mutex_lock(&iaxsl[callno]);	if (callno && iaxs[callno]) {		if ((f->retries < 0) /* Already ACK'd */ ||		    (f->retries >= max_retries) /* Too many attempts */) {				/* Record an error if we've transmitted too many times */				if (f->retries >= max_retries) {					if (f->transfer) {						/* Transfer timeout */						send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);					} else if (f->final) {						if (f->final) 							iax2_destroy(callno);					} else {						if (iaxs[callno]->owner)							ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->af.frametype, f->af.subclass, f->ts, f->oseqno);						iaxs[callno]->error = ETIMEDOUT;						if (iaxs[callno]->owner) {							struct ast_frame fr = { 0, };							/* Hangup the fd */							fr.frametype = AST_FRAME_CONTROL;							fr.subclass = AST_CONTROL_HANGUP;							iax2_queue_frame(callno, &fr); // XXX							/* Remember, owner could disappear */							if (iaxs[callno] && iaxs[callno]->owner)								iaxs[callno]->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;						} else {							if (iaxs[callno]->reg) {								memset(&iaxs[callno]->reg->us, 0, sizeof(iaxs[callno]->reg->us));								iaxs[callno]->reg->regstate = REG_STATE_TIMEOUT;								iaxs[callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;							}							iax2_destroy(callno);						}					}				}				freeme++;		} else {			/* Update it if it needs it */			update_packet(f);			/* Attempt transmission */			send_packet(f);			f->retries++;			/* Try again later after 10 times as long */			f->retrytime *= 10;			if (f->retrytime > MAX_RETRY_TIME)				f->retrytime = MAX_RETRY_TIME;			/* Transfer messages max out at one second */			if (f->transfer && (f->retrytime > 1000))				f->retrytime = 1000;			f->retrans = iax2_sched_add(sched, f->retrytime, attempt_transmit, f);		}	} else {		/* Make sure it gets freed */		f->retries = -1;		freeme++;	}	if (callno)		ast_mutex_unlock(&iaxsl[callno]);	/* Do not try again */	if (freeme) {		/* Don't attempt delivery, just remove it from the queue */		AST_LIST_LOCK(&iaxq.queue);		AST_LIST_REMOVE(&iaxq.queue, f, list);		iaxq.count--;		AST_LIST_UNLOCK(&iaxq.queue);		f->retrans = -1;		/* Free the IAX frame */		iax2_frame_free(f);	}}static int attempt_transmit(const void *data){#ifdef SCHED_MULTITHREADED	if (schedule_action(__attempt_transmit, data))#endif				__attempt_transmit(data);	return 0;}static int iax2_prune_realtime(int fd, int argc, char *argv[]){	struct iax2_peer *peer;	if (argc != 4)        return RESULT_SHOWUSAGE;	if (!strcmp(argv[3],"all")) {		reload_config();		ast_cli(fd, "OK cache is flushed.\n");	} else if ((peer = fin

⌨️ 快捷键说明

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