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

📄 nathelper.c

📁 性能优秀的SIP Proxy
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (rtpproxy_disable_tout >= 0)		node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout;	return 1;}static char *send_rtpp_command(struct rtpp_node *node, struct iovec *v, int vcnt){	struct sockaddr_un addr;	int fd, len, i;	char *cp;	static char buf[256];	struct pollfd fds[1];	len = 0;	cp = buf;	if (node->rn_umode == 0) {		memset(&addr, 0, sizeof(addr));		addr.sun_family = AF_LOCAL;		strncpy(addr.sun_path, node->rn_address,		    sizeof(addr.sun_path) - 1);#ifdef HAVE_SOCKADDR_SA_LEN		addr.sun_len = strlen(addr.sun_path);#endif		fd = socket(AF_LOCAL, SOCK_STREAM, 0);		if (fd < 0) {			LOG(L_ERR, "ERROR: send_rtpp_command: can't create socket\n");			goto badproxy;		}		if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {			close(fd);			LOG(L_ERR, "ERROR: send_rtpp_command: can't connect to RTP proxy\n");			goto badproxy;		}		do {			len = writev(fd, v + 1, vcnt - 1);		} while (len == -1 && errno == EINTR);		if (len <= 0) {			close(fd);			LOG(L_ERR, "ERROR: send_rtpp_command: can't send command to a RTP proxy\n");			goto badproxy;		}		do {			len = read(fd, buf, sizeof(buf) - 1);		} while (len == -1 && errno == EINTR);		close(fd);		if (len <= 0) {			LOG(L_ERR, "ERROR: send_rtpp_command: can't read reply from a RTP proxy\n");			goto badproxy;		}	} else {		fds[0].fd = node->rn_fd;		fds[0].events = POLLIN;		fds[0].revents = 0;		/* Drain input buffer */		while ((poll(fds, 1, 0) == 1) &&		    ((fds[0].revents & POLLIN) != 0)) {			recv(node->rn_fd, buf, sizeof(buf) - 1, 0);			fds[0].revents = 0;		}		v[0].iov_base = gencookie();		v[0].iov_len = strlen(v[0].iov_base);		for (i = 0; i < rtpproxy_retr; i++) {			do {				len = writev(node->rn_fd, v, vcnt);			} while (len == -1 && (errno == EINTR || errno == ENOBUFS));			if (len <= 0) {				LOG(L_ERR, "ERROR: send_rtpp_command: "				    "can't send command to a RTP proxy\n");				goto badproxy;			}			while ((poll(fds, 1, rtpproxy_tout * 1000) == 1) &&			    (fds[0].revents & POLLIN) != 0) {				do {					len = recv(node->rn_fd, buf, sizeof(buf) - 1, 0);				} while (len == -1 && errno == EINTR);				if (len <= 0) {					LOG(L_ERR, "ERROR: send_rtpp_command: "					    "can't read reply from a RTP proxy\n");					goto badproxy;				}				if (len >= (v[0].iov_len - 1) &&				    memcmp(buf, v[0].iov_base, (v[0].iov_len - 1)) == 0) {					len -= (v[0].iov_len - 1);					cp += (v[0].iov_len - 1);					if (len != 0) {						len--;						cp++;					}					goto out;				}				fds[0].revents = 0;			}		}		if (i == rtpproxy_retr) {			LOG(L_ERR, "ERROR: send_rtpp_command: "			    "timeout waiting reply from a RTP proxy\n");			goto badproxy;		}	}out:	cp[len] = '\0';	return cp;badproxy:	LOG(L_ERR, "send_rtpp_command(): proxy <%s> does not responding, disable it\n", node->rn_url);	node->rn_disabled = 1;	node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout;	return NULL;}/* * Main balancing routine. This does not try to keep the same proxy for * the call if some proxies were disabled or enabled; proxy death considered * too rare. Otherwise we should implement "mature" HA clustering, which is * too expensive here. */static struct rtpp_node *select_rtpp_node(str callid, int do_test){	unsigned sum, sumcut, weight_sum;	struct rtpp_node* node;	int was_forced;	/* Most popular case: 1 proxy, nothing to calculate */	if (rtpp_node_count == 1) {		node = rtpp_list.rn_first;		return node->rn_disabled ? NULL : node;	}	/* XXX Use quick-and-dirty hashing algo */	for(sum = 0; callid.len > 0; callid.len--)		sum += callid.s[callid.len - 1];	sum &= 0xff;	was_forced = 0;retry:	weight_sum = 0;	for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {		if (node->rn_disabled) {			/* Try to enable if it's time to try. */			if (node->rn_recheck_ticks <= get_ticks())				node->rn_disabled = rtpp_test(node, 1, 0);		}		if (!node->rn_disabled)			weight_sum += node->rn_weight;	}	if (weight_sum == 0) {		/* No proxies? Force all to be redetected, if not yet */		if (was_forced)			return NULL;		was_forced = 1;		for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {			node->rn_disabled = rtpp_test(node, 1, 1);		}		goto retry;	}	sumcut = sum % weight_sum;	/*	 * sumcut here lays from 0 to weight_sum-1.	 * Scan proxy list and decrease until appropriate proxy is found.	 */	for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {		if (node->rn_disabled)			continue;		if (sumcut < node->rn_weight)			goto found;		sumcut -= node->rn_weight;	}	/* No node list */	return NULL;found:	if (do_test) {		node->rn_disabled = rtpp_test(node, node->rn_disabled, 0);		if (node->rn_disabled)			goto retry;	}	return node;}static intunforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2){	str callid, from_tag, to_tag;	struct rtpp_node *node;	struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}};						/* 1 */   /* 2 */   /* 3 */    /* 4 */   /* 5 */    /* 6 */   /* 1 */	if (get_callid(msg, &callid) == -1 || callid.len == 0) {		LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get Call-Id field\n");		return -1;	}	to_tag.s = 0;	if (get_to_tag(msg, &to_tag) == -1) {		LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get To tag\n");		return -1;	}	if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {		LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get From tag\n");		return -1;	}	STR2IOVEC(callid, v[3]);	STR2IOVEC(from_tag, v[5]);	STR2IOVEC(to_tag, v[7]);	node = select_rtpp_node(callid, 1);	if (!node) {		LOG(L_ERR, "ERROR: unforce_rtp_proxy: no available proxies\n");		return -1;	}	send_rtpp_command(node, v, (to_tag.len > 0) ? 8 : 6);	return 1;}/* * Auxiliary for some functions. * Returns pointer to first character of found line, or NULL if no such line. */static char *find_sdp_line(char* p, char* plimit, char linechar){	static char linehead[3] = "x=";	char *cp, *cp1;	linehead[0] = linechar;	/* Iterate thru body */	cp = p;	for (;;) {		if (cp >= plimit)			return NULL;		cp1 = ser_memmem(cp, linehead, plimit-cp, 2);		if (cp1 == NULL)			return NULL;		/*		 * As it is body, we assume it has previous line and we can		 * lookup previous character.		 */		if (cp1[-1] == '\n' || cp1[-1] == '\r')			return cp1;		/*		 * Having such data, but not at line beginning.		 * Skip them and reiterate. ser_memmem() will find next		 * occurence.		 */		if (plimit - cp1 < 2)			return NULL;		cp = cp1 + 2;	}	/*UNREACHED*/	return NULL;}/* This function assumes p points to a line of requested type. */static char *find_next_sdp_line(char* p, char* plimit, char linechar, char* defptr){	char *t;	if (p >= plimit || plimit - p < 3)		return defptr;	t = find_sdp_line(p + 2, plimit, linechar);	return t ? t : defptr;}static intforce_rtp_proxy2_f(struct sip_msg* msg, char* str1, char* str2){	str body, body1, oldport, oldip, newport, newip;	str callid, from_tag, to_tag, tmp;	int create, port, len, asymmetric, flookup, argc, proxied, real;	int orgip, commip;	int oidx, pf, pf1, force, swap;	char opts[16];	char *cp, *cp1;	char  *cpend, *next;	char **ap, *argv[10];	struct lump* anchor;	struct rtpp_node *node;	struct iovec v[16] = {		{NULL, 0},	/* command */		{NULL, 0},	/* options */		{" ", 1},	/* separator */		{NULL, 0},	/* callid */		{" ", 1},	/* separator */		{NULL, 7},	/* newip */		{" ", 1},	/* separator */		{NULL, 1},	/* oldport */		{" ", 1},	/* separator */		{NULL, 0},	/* from_tag */		{";", 1},	/* separator */		{NULL, 0},	/* medianum */		{" ", 1},	/* separator */		{NULL, 0},	/* to_tag */		{";", 1},	/* separator */		{NULL, 0}	/* medianum */	};	char *v1p, *v2p, *c1p, *c2p, *m1p, *m2p, *bodylimit, *o1p;	char medianum_buf[20];	int medianum, media_multi;	str medianum_str, tmpstr1;	int c1p_altered;	v[1].iov_base=opts;	asymmetric = flookup = force = real = orgip = commip = swap = 0;	oidx = 1;	for (cp = str1; *cp != '\0'; cp++) {		switch (*cp) {		case 'a':		case 'A':			opts[oidx++] = 'A';			asymmetric = 1;			real = 1;			break;		case 'i':		case 'I':			opts[oidx++] = 'I';			break;		case 'e':		case 'E':			opts[oidx++] = 'E';			break;		case 'l':		case 'L':			flookup = 1;			break;		case 'f':		case 'F':			force = 1;			break;		case 'r':		case 'R':			real = 1;			break;		case 'c':		case 'C':			commip = 1;			break;		case 'o':		case 'O':			orgip = 1;			break;		case 's':		case 'S':			swap = 1;			break;		default:			LOG(L_ERR, "ERROR: force_rtp_proxy2: unknown option `%c'\n", *cp);			return -1;		}	}	if (msg->first_line.type == SIP_REQUEST) {		create = swap?0:1;	} else if (msg->first_line.type == SIP_REPLY) {		create = swap?1:0;	} else {		return -1;	}	/* extract_body will also parse all the headers in the message as	 * a side effect => don't move get_callid/get_to_tag in front of it	 * -- andrei */	if (extract_body(msg, &body) == -1) {		LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract body "		    "from the message\n");		return -1;	}	if (get_callid(msg, &callid) == -1 || callid.len == 0) {		LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get Call-Id field\n");		return -1;	}	to_tag.s = 0;	if (get_to_tag(msg, &to_tag) == -1) {		LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get To tag\n");		return -1;	}	if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {		LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get From tag\n");		return -1;	}	if (flookup != 0) {		if (create == 0 || to_tag.len == 0)			return -1;		create = 0;		tmp = from_tag;		from_tag = to_tag;		to_tag = tmp;	}	proxied = 0;	for (cp = body.s; (len = body.s + body.len - cp) >= ANORTPPROXY_LEN;) {		cp1 = ser_memmem(cp, ANORTPPROXY, len, ANORTPPROXY_LEN);		if (cp1 == NULL)			break;		if (cp1[-1] == '\n' || cp1[-1] == '\r') {			proxied = 1;			break;		}		cp = cp1 + ANORTPPROXY_LEN;	}	if (proxied != 0 && force == 0)		return -1;	/*	 * Parsing of SDP body.	 * It can contain a few session descriptions (each starts with	 * v-line), and each session may contain a few media descriptions	 * (each starts with m-line).	 * We have to change ports in m-lines, and also change IP addresses in	 * c-lines which can be placed either in session header (fallback for	 * all medias) or media description.	 * Ports should be allocated for any media. IPs all should be changed	 * to the same value (RTP proxy IP), so we can change all c-lines	 * unconditionally.	 */	bodylimit = body.s + body.len;	v1p = find_sdp_line(body.s, bodylimit, 'v');	if (v1p == NULL) {		LOG(L_ERR, "ERROR: force_rtp_proxy2: no sessions in SDP\n");		return -1;	}	v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);	media_multi = (v2p != bodylimit);	v2p = v1p;	medianum = 0;	for(;;) {		/* Per-session iteration. */		v1p = v2p;		if (v1p == NULL || v1p >= bodylimit)			break; /* No sessions left */		v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);		/* v2p is text limit for session parsing. */		/* get session origin */		o1p = find_sdp_line(v1p, v2p, 'o');		if (o1p==0) {			LOG(L_ERR, "ERROR: force_rtp_proxy2: no o= in session\n");			return -1;		}		/* Have this session media description? */		m1p = find_sdp_line(o1p, v2p, 'm');		if (m1p == NULL) {			LOG(L_ERR, "ERROR: force_rtp_proxy2: no m= in session\n");			return -1;		}		/*		 * Find c1p only between session begin and first media.		 * c1p will give common c= for all medias.		 */		c1p = find_sdp_line(o1p, m1p, 'c');		c1p_altered = 0;		if (orgip==0)			o1p = 0;		/* Have session. Iterate media descriptions in session */		m2p = m1p;		for (;;) {			m1p = m2p;			if (m1p == NULL || m1p >= v2p)				break;			m2p = find_next_sdp_line(m1p, v2p, 'm', v2p);			/* c2p will point to per-media "c=" */			c2p = find_sdp_line(m1p, m2p, 'c');			/* Extract address and port */

⌨️ 快捷键说明

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