</settings>
<profiles>
- <profile name="mine">
- <param name="bind-local" value="0.0.0.0:8081"/>
- <param name="bind-local" value="0.0.0.0:8082" secure="true"/>
+ <profile name="default-v4">
+ <param name="bind-local" value="$${local_ip_v4}:8081"/>
+ <param name="bind-local" value="$${local_ip_v4}:8082" secure="true"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="secure-combined" value="$${certs_dir}/wss.pem"/>
<param name="secure-chain" value="$${certs_dir}/wss.pem"/>
<param name="local-network" value="localnet.auto"/>
<param name="outbound-codec-string" value="opus,vp8"/>
<param name="inbound-codec-string" value="opus,vp8"/>
- <param name="apply-candidate-acl" value="wan.auto"/>
+ <param name="apply-candidate-acl" value="wan_v4.auto"/>
+ <param name="timer-name" value="soft"/>
+
+ </profile>
+
+ <profile name="default-v6">
+ <param name="bind-local" value="[$${local_ip_v6}]:8081"/>
+ <param name="bind-local" value="[$${local_ip_v6}]:8082" secure="true"/>
+ <param name="force-register-domain" value="$${domain}"/>
+ <param name="secure-combined" value="$${certs_dir}/wss.pem"/>
+ <param name="secure-chain" value="$${certs_dir}/wss.pem"/>
+ <param name="userauth" value="true"/>
+ <!-- setting this to true will allow anyone to register even with no account so use with care -->
+ <param name="blind-reg" value="false"/>
+ <param name="mcast-ip" value="ff02::1"/>
+ <param name="mcast-port" value="1337"/>
+ <param name="rtp-ip" value="$${local_ip_v6}"/>
+ <!-- <param name="ext-rtp-ip" value=""/> -->
+ <param name="local-network" value="localnet.auto"/>
+ <param name="outbound-codec-string" value="opus,vp8"/>
+ <param name="inbound-codec-string" value="opus,vp8"/>
+ <param name="apply-candidate-acl" value="wan_v6.auto"/>
<param name="timer-name" value="soft"/>
</profile>
char *extrtpip;
char *rtpip;
+ char *rtpip4;
+ char *rtpip6;
+
char *remote_ip;
int remote_port;
icand_t cands[MAX_CAND][2];
int cand_idx;
int chosen[2];
+ int is_chosen[2];
char *ufrag;
char *pwd;
char *options;
int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags)
{
uint32_t one = 1;
+ int family = AF_INET;
memset(handle, 0, sizeof(*handle));
- if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0 ) {
- return -1;
+ if (strchr(host, ':')) {
+ family = AF_INET6;
}
- handle->send_addr.sin_family = AF_INET;
- handle->send_addr.sin_addr.s_addr = inet_addr(host);
- handle->send_addr.sin_port = htons(port);
+ if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(family, SOCK_DGRAM, 0)) <= 0 ) {
+ return -1;
+ }
+
+ if (family == AF_INET6) {
+ handle->send_addr6.sin6_family = AF_INET6;
+ handle->send_addr6.sin6_port = htons(port);
+ inet_pton(AF_INET6, host, &(handle->send_addr6.sin6_addr));
+ handle->family = AF_INET6;
+ } else {
+ handle->send_addr.sin_family = AF_INET;
+ handle->send_addr.sin_addr.s_addr = inet_addr(host);
+ handle->send_addr.sin_port = htons(port);
+ handle->family = AF_INET;
+ }
if ( setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0 ) {
close(handle->sock);
if ((flags & MCAST_RECV)) {
- struct ip_mreq mreq;
-
- handle->recv_addr.sin_family = AF_INET;
- handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- handle->recv_addr.sin_port = htons(port);
-
- mreq.imr_multiaddr.s_addr = inet_addr(host);
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
-
- if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
- close(handle->sock);
- handle->sock = -1;
- return -1;
- }
-
- if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) {
- close(handle->sock);
- handle->sock = -1;
- return -1;
+ if (handle->family == AF_INET) {
+ struct ip_mreq mreq;
+
+ handle->recv_addr.sin_family = AF_INET;
+ handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ handle->recv_addr.sin_port = htons(port);
+
+ mreq.imr_multiaddr.s_addr = inet_addr(host);
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
+ close(handle->sock);
+ handle->sock = -1;
+ return -1;
+ }
+
+ if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) {
+ close(handle->sock);
+ handle->sock = -1;
+ return -1;
+ }
+
+ } else {
+ struct ipv6_mreq mreq;
+ struct addrinfo addr_criteria;
+ struct addrinfo *mcast_addr;
+ char service[80] = "";
+
+ memset(&addr_criteria, 0, sizeof(addr_criteria));
+ addr_criteria.ai_family = AF_UNSPEC;
+ addr_criteria.ai_socktype = SOCK_DGRAM;
+ addr_criteria.ai_protocol = IPPROTO_UDP;
+ addr_criteria.ai_flags |= AI_NUMERICHOST;
+
+ snprintf(service, sizeof(service), "%d", port);
+ getaddrinfo(host, service, &addr_criteria, &mcast_addr);
+
+
+ memset(&handle->recv_addr6, 0, sizeof(handle->recv_addr6));
+ handle->recv_addr6.sin6_family = AF_INET6;
+ handle->recv_addr6.sin6_port = htons(port);
+ inet_pton(AF_INET6, "::0", &(handle->recv_addr6.sin6_addr));
+
+ memcpy(&mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *)mcast_addr->ai_addr)->sin6_addr, sizeof(struct in6_addr));
+
+ mreq.ipv6mr_interface = 0;
+ setsockopt(handle->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+
+ if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr6, sizeof(handle->recv_addr6)) < 0) {
+ printf("FUCK (%s) %s\n", host, strerror(errno));
+ close(handle->sock);
+ handle->sock = -1;
+ return -1;
+ }
}
-
-
}
handle->ttl = 1;
datalen = sizeof(handle->buffer);
}
- return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr));
+ if (handle->family == AF_INET6) {
+ return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr6, sizeof(handle->send_addr6));
+ } else {
+ return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr));
+ }
}
ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, int ms)
}
}
-
- return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen);
+ if (handle->family == AF_INET6) {
+ return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr6, &addrlen);
+ } else {
+ return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen);
+ }
}
unsigned char ttl;
struct sockaddr_in send_addr;
struct sockaddr_in recv_addr;
+ struct sockaddr_in6 send_addr6;
+ struct sockaddr_in6 recv_addr6;
+ int family;
unsigned char buffer[65536];
int ready;
} mcast_handle_t;
static void client_run(jsock_t *jsock)
{
-
- jsock->local_addr.sin_family = AF_INET;
- jsock->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- jsock->local_addr.sin_port = 0;
-
-
if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->vhosts) < 0) {
if (jsock->profile->vhosts) {
http_run(jsock);
{
uint32_t i;
- tech_pvt->mparams->rtpip = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]);
+ if (!zstr(profile->rtpip[profile->rtpip_cur])) {
+ tech_pvt->mparams->rtpip4 = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]);
+ tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip4;
+ if (profile->rtpip_cur == profile->rtpip_index) {
+ profile->rtpip_cur = 0;
+ }
+ }
- if (profile->rtpip_cur == profile->rtpip_index) {
- profile->rtpip_cur = 0;
+ if (!zstr(profile->rtpip6[profile->rtpip_cur6])) {
+ tech_pvt->mparams->rtpip6 = switch_core_session_strdup(tech_pvt->session, profile->rtpip6[profile->rtpip_cur6++]);
+
+ if (zstr(tech_pvt->mparams->rtpip)) {
+ tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip6;
+ }
+
+ if (profile->rtpip_cur6 == profile->rtpip_index6) {
+ profile->rtpip_cur6 = 0;
+ }
+ }
+
+ if (zstr(tech_pvt->mparams->rtpip)) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "%s has no media ip, check your configuration\n",
+ switch_channel_get_name(tech_pvt->channel));
+ switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
}
tech_pvt->mparams->extrtpip = tech_pvt->mparams->extsipip = profile->extrtpip;
switch_either(jsock->dialplan, jsock->profile->dialplan),
caller_id_name,
caller_id_number,
- inet_ntoa(jsock->remote_addr.sin_addr),
+ jsock->remote_host,
cJSON_GetObjectCstr(dialog, "ani"),
cJSON_GetObjectCstr(dialog, "aniii"),
cJSON_GetObjectCstr(dialog, "rdnis"),
-static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
+static int start_jsock(verto_profile_t *profile, ws_socket_t sock, int family)
{
jsock_t *jsock = NULL;
int flag = 1;
jsock = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock));
jsock->pool = pool;
+ jsock->family = family;
+
+ if (family == PF_INET) {
+ len = sizeof(jsock->remote_addr);
- len = sizeof(jsock->remote_addr);
+ if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
+ die("ACCEPT FAILED\n");
+ }
+ } else {
+ len = sizeof(jsock->remote_addr6);
- if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
- die("ACCEPT FAILED\n");
+ if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr6, &len)) < 0) {
+ die("ACCEPT FAILED\n");
+ }
}
for (i = 0; i < profile->i; i++) {
jsock->profile = profile;
if (zstr(jsock->name)) {
- jsock->name = switch_core_sprintf(pool, "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port));
+ if (family == PF_INET) {
+ jsock->remote_port = ntohs(jsock->remote_addr.sin_port);
+ inet_ntop(AF_INET, &jsock->remote_addr.sin_addr, jsock->remote_host, sizeof(jsock->remote_host));
+ jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port);
+ } else {
+ jsock->remote_port = ntohs(jsock->remote_addr6.sin6_port);
+ inet_ntop(AF_INET6, &jsock->remote_addr6.sin6_addr, jsock->remote_host, sizeof(jsock->remote_host));
+ jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port);
+ }
}
jsock->ptype = ptype;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Client Connect.\n", jsock->name);
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_CLIENT_CONNECT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_profile_name", profile->name);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port));
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", jsock->remote_host, jsock->remote_port);
switch_event_fire(&s_event);
}
return -1;
}
-static ws_socket_t prepare_socket(int ip, uint16_t port)
+static ws_socket_t prepare_socket(ips_t *ips)
{
ws_socket_t sock = ws_sock_invalid;
#ifndef WIN32
#else
char reuse_addr = 1;
#endif
+ int family;
struct sockaddr_in addr;
+ struct sockaddr_in6 addr6;
+
+ if (strchr(ips->local_ip, ':')) {
+ family = PF_INET6;
+ } else {
+ family = PF_INET;
+ }
- if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ if ((sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
die("Socket Error!\n");
}
if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) {
die("Socket setsockopt Error!\n");
}
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = ip;
- addr.sin_port = htons(port);
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- die("Bind Error!\n");
- }
+ if (family == PF_INET) {
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(ips->local_ip);
+ addr.sin_port = htons(ips->local_port);
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ die("Bind Error!\n");
+ }
+ } else {
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(ips->local_port);
+ inet_pton(AF_INET6, ips->local_ip, &(addr6.sin6_addr));
+ if (bind(sock, (struct sockaddr *) &addr6, sizeof(addr6)) < 0) {
+ die("Bind Error!\n");
+ }
+ }
+
if (listen(sock, MAXPENDING) < 0) {
die("Listen error\n");
}
+ ips->family = family;
+
return sock;
error:
if (profile->mcast_ip && pfds[x].sock == (switch_os_socket_t)profile->mcast_sub.sock) {
handle_mcast_sub(profile);
} else {
- start_jsock(profile, pfds[x].sock);
+ start_jsock(profile, pfds[x].sock, profile->ip[x].family);
}
}
}
}
-static int runtime(verto_profile_t *profile)
-{
- int i;
-
- for (i = 0; i < profile->i; i++) {
- if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
- die("Client Socket Error!\n");
- }
- }
-
- if (profile->mcast_ip) {
- if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) {
- die("mcast recv socket create");
- }
-
- if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) {
- mcast_socket_close(&profile->mcast_sub);
- die("mcast send socket create");
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1);
- }
-
-
- while(profile->running) {
- if (profile_one_loop(profile) < 0) {
- goto error;
- }
- }
-
- if (profile->mcast_sub.sock > -1) {
- mcast_socket_close(&profile->mcast_sub);
- }
-
- if (profile->mcast_pub.sock > -1) {
- mcast_socket_close(&profile->mcast_pub);
- }
-
- return 0;
-
- error:
-
- return -1;
-
-}
-
static void kill_profile(verto_profile_t *profile)
{
jsock_t *p;
}
+static int runtime(verto_profile_t *profile)
+{
+ int i;
+ int r = 0;
+
+ for (i = 0; i < profile->i; i++) {
+ //if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
+ if ((profile->server_socket[i] = prepare_socket(&profile->ip[i])) < 0) {
+ die("Client Socket Error!\n");
+ }
+ }
+
+ if (profile->mcast_ip) {
+ if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) {
+ r = -1;
+ die("mcast recv socket create\n");
+ }
+
+ if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) {
+ mcast_socket_close(&profile->mcast_sub);
+ r = -1;
+ die("mcast send socket create\n");
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1);
+ }
+
+
+ while(profile->running) {
+ if (profile_one_loop(profile) < 0) {
+ goto error;
+ }
+ }
+
+ error:
+
+ if (profile->mcast_sub.sock > -1) {
+ mcast_socket_close(&profile->mcast_sub);
+ }
+
+ if (profile->mcast_pub.sock > -1) {
+ mcast_socket_close(&profile->mcast_pub);
+ }
+
+ if (r) {
+ kill_profile(profile);
+ }
+
+ return r;
+
+}
+
static void do_shutdown(void)
{
globals.running = 0;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Done\n");
}
-static void parse_ip(char *host, uint16_t *port, in_addr_t *addr, char *input)
+
+static void parse_ip(char *host, switch_size_t host_len, uint16_t *port, char *input)
{
char *p;
- struct hostent *hent;
-
- strncpy(host, input, 255);
-
- host[255] = 0;
-
- if ((p = strchr(host, ':')) != NULL) {
- *p++ = '\0';
- *port = (uint16_t)atoi(p);
+ //struct hostent *hent;
+
+ if ((p = strchr(input, '['))) {
+ char *end = switch_find_end_paren(p, '[', ']');
+ if (end) {
+ p++;
+ strncpy(host, p, end - p);
+ if (*(end+1) == ':' && end + 2 < end_of_p(input)) {
+ end += 2;
+ if (end) {
+ *port = (uint16_t)atoi(end);
+ }
+ }
+ } else {
+ strncpy(host, "::", host_len);
+ }
+ } else {
+ strncpy(host, input, host_len);
+ if ((p = strrchr(host, ':')) != NULL) {
+ *p++ = '\0';
+ *port = (uint16_t)atoi(p);
+ }
}
+#if 0
if ( host[0] < '0' || host[0] > '9' ) {
// Non-numeric host (at least it doesn't start with one). Convert it to ip addr first
if ((hent = gethostbyname(host)) != NULL) {
} else {
*addr = inet_addr(host);
}
+#endif
}
+
static verto_profile_t *find_profile(const char *name)
{
verto_profile_t *p, *r = NULL;
if (!strcasecmp(var, "bind-local")) {
const char *secure = switch_xml_attr_soft(param, "secure");
if (i < MAX_BIND) {
- parse_ip(profile->ip[profile->i].local_ip, &profile->ip[profile->i].local_port, &profile->ip[profile->i].local_ip_addr, val);
+ parse_ip(profile->ip[profile->i].local_ip, sizeof(profile->ip[profile->i].local_ip), &profile->ip[profile->i].local_port, val);
if (switch_true(secure)) {
profile->ip[profile->i].secure = 1;
}
if (zstr(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n");
} else {
- if (profile->rtpip_index < MAX_RTPIP -1) {
- profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val);
+ if (strchr(val, ':')) {
+ if (profile->rtpip_index6 < MAX_RTPIP -1) {
+ profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, val);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
+ }
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
+ if (profile->rtpip_index < MAX_RTPIP -1) {
+ profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
+ }
}
}
} else if (!strcasecmp(var, "ext-rtp-ip")) {
unsigned char buf[65535];
char *name;
jsock_type_t ptype;
- struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
- struct sockaddr_in send_addr;
+ struct sockaddr_in6 remote_addr6;
#ifndef WIN32
struct passwd pw;
#endif
char *dialplan;
char *context;
+
+ char remote_host[256];
+ int remote_port;
+ int family;
+
struct verto_profile_s *profile;
switch_thread_rwlock_t *rwlock;
#define MAX_BIND 25
#define MAX_RTPIP 25
-struct ips {
+typedef struct ips {
char local_ip[256];
- in_addr_t local_ip_addr;
uint16_t local_port;
int secure;
-};
+ int family;
+} ips_t;
typedef enum {
TFLAG_SENT_MEDIA = (1 << 0),
int rtpip_index;
int rtpip_cur;
+ char *rtpip6[MAX_RTPIP];
+ int rtpip_index6;
+ int rtpip_cur6;
+
char *cand_acl[SWITCH_MAX_CAND_ACL];
uint32_t cand_acl_count;
ssize_t need = 2;
char *maskp;
int ll = 0;
+ int frag = 0;
again:
need = 2;
case WSOC_PING:
case WSOC_PONG:
{
- //int fin = (wsh->buffer[0] >> 7) & 1;
+ int fin = (wsh->buffer[0] >> 7) & 1;
int mask = (wsh->buffer[1] >> 7) & 1;
+
+ if (fin) {
+ if (*oc == WSOC_CONTINUATION) {
+ frag = 1;
+ } else {
+ frag = 0;
+ }
+ }
if (mask) {
need += 4;
ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
goto again;
}
+
+ if (frag) {
+ goto again;
+ }
*(wsh->payload+wsh->rplen) = '\0';
free(list_name_dup);
} else {
switch_parse_cidr(list_name, &net, &mask, &bits);
- ok = switch_test_subnet(ip.v4, net.v4, mask.v4);
+
+ if (ipv6) {
+ ok = switch_testv6_subnet(ip, net, mask);
+ } else {
+ ok = switch_test_subnet(ip.v4, net.v4, mask.v4);
+ }
}
}
switch_mutex_unlock(runtime.global_mutex);
switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE);
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
+ tmp_name = "wan_v6.auto";
+ switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
+ switch_network_list_add_cidr(rfc_list, "0.0.0.0/0", SWITCH_FALSE);
+ switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE);
+ switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
+
+
+ tmp_name = "wan_v4.auto";
+ switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
+ switch_network_list_add_cidr(rfc_list, "0.0.0.0/8", SWITCH_FALSE);
+ switch_network_list_add_cidr(rfc_list, "10.0.0.0/8", SWITCH_FALSE);
+ switch_network_list_add_cidr(rfc_list, "172.16.0.0/12", SWITCH_FALSE);
+ switch_network_list_add_cidr(rfc_list, "192.168.0.0/16", SWITCH_FALSE);
+ switch_network_list_add_cidr(rfc_list, "169.254.0.0/16", SWITCH_FALSE);
+ switch_network_list_add_cidr(rfc_list, "::/0", SWITCH_FALSE);
+ switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
+
+
tmp_name = "nat.auto";
switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name);
engine->ice_in.chosen[0] = 0;
engine->ice_in.chosen[1] = 0;
+ engine->ice_in.is_chosen[0] = 0;
+ engine->ice_in.is_chosen[1] = 0;
engine->ice_in.cand_idx = 0;
memset(&engine->ice_in, 0, sizeof(engine->ice_in));
engine->remote_rtcp_port = 0;
return r;
}
+//?
+static switch_status_t ip_choose_family(switch_media_handle_t *smh, const char *ip)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (zstr(ip)) {
+ return status;
+ }
+
+ if (strchr(ip, ':')) {
+ if (!zstr(smh->mparams->rtpip6)) {
+ smh->mparams->rtpip = smh->mparams->rtpip6;
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v6\n",
+ switch_channel_get_name(smh->session->channel));
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ } else {
+ if (!zstr(smh->mparams->rtpip4)) {
+ smh->mparams->rtpip = smh->mparams->rtpip4;
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v4\n",
+ switch_channel_get_name(smh->session->channel));
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+//?
+static switch_bool_t ip_possible(switch_media_handle_t *smh, const char *ip)
+{
+ switch_bool_t r = SWITCH_FALSE;
+
+ if (zstr(ip)) {
+ return r;
+ }
+
+ if (strchr(ip, ':')) {
+ r = (switch_bool_t) !zstr(smh->mparams->rtpip6);
+ } else {
+ r = (switch_bool_t) !zstr(smh->mparams->rtpip4);
+ }
+
+ return r;
+}
+
//?
static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m)
{
int i = 0, got_rtcp_mux = 0;
const char *val;
- if (engine->ice_in.chosen[0] && engine->ice_in.chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
+ if (engine->ice_in.is_chosen[0] && engine->ice_in.is_chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
return;
}
engine->ice_in.chosen[0] = 0;
engine->ice_in.chosen[1] = 0;
+ engine->ice_in.is_chosen[0] = 0;
+ engine->ice_in.is_chosen[1] = 0;
engine->ice_in.cand_idx = 0;
if (m) {
char *fields[15];
int argc = 0, j = 0;
int cid = 0;
+ int pass_acl = 0;
if (zstr(attr->a_name)) {
continue;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Checking Candidate cid: %d proto: %s type: %s addr: %s:%s\n", cid+1, fields[2], fields[7], fields[4], fields[5]);
-
-
- engine->ice_in.cand_idx++;
+
+ pass_acl = 0;
for (i = 0; i < engine->cand_acl_count; i++) {
- if (!engine->ice_in.chosen[cid] && !strchr(fields[4], ':') && switch_check_network_list_ip(fields[4], engine->cand_acl[i])) {
- engine->ice_in.chosen[cid] = engine->ice_in.cand_idx;
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
- "Choose %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
- type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
- cid+1, fields[2], fields[7], fields[4], fields[5]);
- } else {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
- "Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
- type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
- cid+1, fields[2], fields[7], fields[4], fields[5]);
- }
-
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].component_id = atoi(fields[1]);
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].transport = switch_core_session_strdup(smh->session, fields[2]);
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].priority = atol(fields[3]);
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_port = (switch_port_t)atoi(fields[5]);
-
-
- j = 6;
-
- while(j < argc && fields[j+1]) {
- if (!strcasecmp(fields[j], "typ")) {
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]);
- } else if (!strcasecmp(fields[j], "raddr")) {
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
- } else if (!strcasecmp(fields[j], "rport")) {
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].rport = (switch_port_t)atoi(fields[j+1]);
- } else if (!strcasecmp(fields[j], "generation")) {
- engine->ice_in.cands[engine->ice_in.cand_idx][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
- }
-
- j += 2;
- }
-
+ if (switch_check_network_list_ip(fields[4], engine->cand_acl[i])) {
+ pass_acl = 1;
+ break;
+ }
+ }
- if (engine->ice_in.chosen[cid]) {
- engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++;
+ if (!engine->ice_in.is_chosen[cid] && ip_possible(smh, fields[4]) && pass_acl) {
+ engine->ice_in.chosen[cid] = engine->ice_in.cand_idx;
+ engine->ice_in.is_chosen[cid] = 1;
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
+ "Choose %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
+ type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
+ cid+1, fields[2], fields[7], fields[4], fields[5]);
+ ip_choose_family(smh, fields[4]);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
+ "Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
+ type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
+ cid+1, fields[2], fields[7], fields[4], fields[5]);
+ }
+
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].component_id = atoi(fields[1]);
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].transport = switch_core_session_strdup(smh->session, fields[2]);
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].priority = atol(fields[3]);
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_port = (switch_port_t)atoi(fields[5]);
+
+ j = 6;
+
+ while(j < argc && fields[j+1]) {
+ if (!strcasecmp(fields[j], "typ")) {
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]);
+ } else if (!strcasecmp(fields[j], "raddr")) {
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
+ } else if (!strcasecmp(fields[j], "rport")) {
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].rport = (switch_port_t)atoi(fields[j+1]);
+ } else if (!strcasecmp(fields[j], "generation")) {
+ engine->ice_in.cands[engine->ice_in.cand_idx][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
}
+
+ j += 2;
+ }
- break;
+
+ if (engine->ice_in.is_chosen[cid]) {
+ engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++;
}
+
+ engine->ice_in.cand_idx++;
}
}
/* still no candidates, so start searching for some based on sane deduction */
/* look for candidates on the same network */
- if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
- for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
- if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 &&
- !engine->ice_in.cands[i][0].rport && switch_check_network_list_ip(engine->ice_in.cands[i][0].con_addr, "localnet.auto")) {
+ if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
+ for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]); i++) {
+ if (!engine->ice_in.is_chosen[0] && engine->ice_in.cands[i][0].component_id == 1 &&
+ !engine->ice_in.cands[i][0].rport && ip_possible(smh, engine->ice_in.cands[i][0].con_addr) &&
+ switch_check_network_list_ip(engine->ice_in.cands[i][0].con_addr, "localnet.auto")) {
engine->ice_in.chosen[0] = i;
+ engine->ice_in.is_chosen[0] = 1;
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
+ ip_choose_family(smh, engine->ice_in.cands[i][0].con_addr);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTP candidate found; defaulting to the first local one.\n", type2str(type));
}
- if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 &&
- !engine->ice_in.cands[i][1].rport && switch_check_network_list_ip(engine->ice_in.cands[i][1].con_addr, "localnet.auto")) {
+ if (!engine->ice_in.is_chosen[1] && engine->ice_in.cands[i][1].component_id == 2 &&
+ !engine->ice_in.cands[i][1].rport && ip_possible(smh, engine->ice_in.cands[i][1].con_addr) &&
+ switch_check_network_list_ip(engine->ice_in.cands[i][1].con_addr, "localnet.auto")) {
engine->ice_in.chosen[1] = i;
+ engine->ice_in.is_chosen[1] = 1;
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE,
"No %s RTCP candidate found; defaulting to the first local one.\n", type2str(type));
}
/* look for candidates with srflx */
- if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
- for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
- if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && engine->ice_in.cands[i][0].rport) {
+ if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
+ for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]); i++) {
+ if (!engine->ice_in.is_chosen[0] &&
+ engine->ice_in.cands[i][0].component_id == 1 && engine->ice_in.cands[i][0].rport && ip_possible(smh, engine->ice_in.cands[i][0].con_addr)) {
engine->ice_in.chosen[0] = i;
+ engine->ice_in.chosen[1] = 1;
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
+ ip_choose_family(smh, engine->ice_in.cands[i][0].con_addr);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTP candidate found; defaulting to the first srflx one.\n", type2str(type));
}
- if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && engine->ice_in.cands[i][1].rport) {
+ if (!engine->ice_in.is_chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && engine->ice_in.cands[i][1].rport &&
+ ip_possible(smh, engine->ice_in.cands[i][1].con_addr)) {
engine->ice_in.chosen[1] = i;
+ engine->ice_in.is_chosen[1] = 1;
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE,
"No %s RTCP candidate found; defaulting to the first srflx one.\n", type2str(type));
}
/* Got RTP but not RTCP, probably mux */
- if (engine->ice_in.chosen[0] && !engine->ice_in.chosen[1] && got_rtcp_mux) {
+ if (engine->ice_in.is_chosen[0] && !engine->ice_in.is_chosen[1] && got_rtcp_mux) {
engine->ice_in.chosen[1] = engine->ice_in.chosen[0];
+ engine->ice_in.is_chosen[1] = 1;
memcpy(&engine->ice_in.cands[engine->ice_in.chosen[1]][1], &engine->ice_in.cands[engine->ice_in.chosen[0]][0],
sizeof(engine->ice_in.cands[engine->ice_in.chosen[0]][0]));
}
/* look for any candidates and hope for auto-adjust */
- if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
- for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
- if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1) {
+ if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
+ for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]); i++) {
+ if (!engine->ice_in.is_chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && ip_possible(smh, engine->ice_in.cands[i][0].con_addr)) {
engine->ice_in.chosen[0] = i;
+ engine->ice_in.is_chosen[0] = 1;
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
+ ip_choose_family(smh, engine->ice_in.cands[i][0].con_addr);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTP candidate found; defaulting to the first one.\n", type2str(type));
}
- if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2) {
+ if (!engine->ice_in.is_chosen[1] && engine->ice_in.cands[i][1].component_id == 2) {
engine->ice_in.chosen[1] = i;
+ engine->ice_in.is_chosen[1] = 1;
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTCP candidate found; defaulting to the first one.\n", type2str(type));
}
}
+ if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
+ /* PUNT */
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s no suitable candidates found.\n",
+ switch_channel_get_name(smh->session->channel));
+ return;
+ }
+
for (i = 0; i < 2; i++) {
if (engine->ice_in.cands[engine->ice_in.chosen[i]][i].ready) {
if (zstr(engine->ice_in.ufrag) || zstr(engine->ice_in.pwd)) {
SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_session_t *session, switch_bool_t audio, switch_bool_t video)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
+ switch_media_handle_t *smh;
+
+ if (!(smh = session->media_handle)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (zstr(smh->mparams->rtpip)) {
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no media ip\n",
+ switch_channel_get_name(smh->session->channel));
+ switch_channel_hangup(smh->session->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+
+ return SWITCH_STATUS_FALSE;
+ }
if (audio && (status = switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0)) == SWITCH_STATUS_SUCCESS) {
if (video) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
switch_channel_get_name(session->channel),
- a_engine->cur_payload_map->remote_sdp_ip,
+ a_engine->local_sdp_ip,
v_engine->local_sdp_port,
v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt,
for (node = list->node_head; node; node = node->next) {
if (node->family == AF_INET) continue;
- if (node->bits > bits && switch_testv6_subnet(ip, node->ip, node->mask)) {
+
+ if (node->bits >= bits && switch_testv6_subnet(ip, node->ip, node->mask)) {
if (node->ok) {
ok = SWITCH_TRUE;
} else {
for (node = list->node_head; node; node = node->next) {
if (node->family == AF_INET6) continue; /* want AF_INET */
- if (node->bits > bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) {
+ if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) {
if (node->ok) {
ok = SWITCH_TRUE;
} else {