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