coturn/src/apps/uclient/startuclient.c
Michael Jones 0af0fc3ec2
Address various minor clang-tidy warnings (#1513)
No specific methodology other than checking the github CI output for the
`clang-tidy` job, and fixing things one at a time.
2025-05-29 19:12:50 -07:00

1672 lines
50 KiB
C

/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "ns_turn_defs.h"
#include "ns_turn_ioalib.h" // for ioa_engine_handle
#include "ns_turn_msg.h"
#include "ns_turn_utils.h"
#include "apputils.h"
#include "session.h"
#include "startuclient.h"
#include "uclient.h"
#if defined(__MINGW32__)
#ifndef usleep
#define usleep Sleep
#endif
#endif
/////////////////////////////////////////
#define MAX_CONNECT_EFFORTS (77)
#define DTLS_MAX_CONNECT_TIMEOUT (30)
#define MAX_TLS_CYCLES (32)
#define EXTRA_CREATE_PERMS (25)
static uint64_t current_reservation_token = 0;
static int allocate_rtcp = 0;
static const int never_allocate_rtcp = 0;
static const unsigned char kALPNProtos[] = "\x08http/1.1\x09stun.turn\x12stun.nat-discovery";
static const size_t kALPNProtosLen = sizeof(kALPNProtos) - 1;
/////////////////////////////////////////
int rare_event(void) {
if (dos) {
return (((unsigned long)turn_random()) % 1000 == 777);
}
return 0;
}
int not_rare_event(void) {
if (dos) {
return ((((unsigned long)turn_random()) % 1000) < 200);
}
return 0;
}
static int get_allocate_address_family(ioa_addr *relay_addr) {
if (relay_addr->ss.sa_family == AF_INET) {
return STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_DEFAULT;
} else if (relay_addr->ss.sa_family == AF_INET6) {
return STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6;
} else {
return STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_INVALID;
}
}
/////////////////////////////////////////
static SSL *tls_connect(ioa_socket_raw fd, ioa_addr *remote_addr, bool *try_again, int connect_cycle) {
int ctxtype = (int)(((unsigned long)turn_random()) % root_tls_ctx_num);
SSL *ssl;
ssl = SSL_new(root_tls_ctx[ctxtype]);
SSL_set_alpn_protos(ssl, kALPNProtos, kALPNProtosLen);
if (use_tcp) {
SSL_set_fd(ssl, fd);
} else {
#if !DTLS_SUPPORTED
UNUSED_ARG(remote_addr);
fprintf(stderr, "ERROR: DTLS is not supported.\n");
exit(-1);
#else
/* Create BIO, connect and set to already connected */
BIO *bio = BIO_new_dgram(fd, BIO_CLOSE);
// bio = BIO_new_socket(fd, BIO_CLOSE);
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &remote_addr->ss);
SSL_set_bio(ssl, bio, bio);
{
struct timeval timeout;
/* Set and activate timeouts */
timeout.tv_sec = DTLS_MAX_CONNECT_TIMEOUT;
timeout.tv_usec = 0;
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
}
set_mtu_df(ssl, fd, remote_addr->ss.sa_family, SOSO_MTU, !use_tcp, clnet_verbose);
#endif
}
SSL_set_max_cert_list(ssl, 655350);
if (clnet_verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "call SSL_connect...\n");
}
int rc = 0;
do {
do {
rc = SSL_connect(ssl);
} while (rc < 0 && socket_eintr());
int orig_errno = socket_errno();
if (rc > 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: client session connected with cipher %s, method=%s\n", __FUNCTION__,
SSL_get_cipher(ssl), turn_get_ssl_method(ssl, NULL));
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
if (clnet_verbose && SSL_get1_peer_certificate(ssl)) {
#else
if (clnet_verbose && SSL_get_peer_certificate(ssl)) {
#endif
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "------------------------------------------------------------\n");
X509_NAME_print_ex_fp(stdout, X509_get_subject_name(SSL_get_peer_certificate(ssl)), 1, XN_FLAG_MULTILINE);
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n\n Cipher: %s\n", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n------------------------------------------------------------\n\n");
}
break;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot connect: rc=%d, ctx=%d\n", __FUNCTION__, rc, ctxtype);
switch (SSL_get_error(ssl, rc)) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
if (!dos) {
usleep(1000);
}
continue;
default: {
char buf[1025];
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "errno=%d, err=%d, %s (%d)\n", orig_errno, (int)ERR_get_error(),
ERR_error_string(ERR_get_error(), buf), (int)SSL_get_error(ssl, rc));
if (connect_cycle < MAX_TLS_CYCLES) {
if (try_again) {
SSL_free(ssl);
*try_again = true;
return NULL;
}
}
exit(-1);
}
};
}
} while (1);
if (clnet_verbose && SSL_get_peer_certificate(ssl)) {
if (use_tcp) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "------TLS---------------------------------------------------\n");
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "------DTLS---------------------------------------------------\n");
}
X509_NAME_print_ex_fp(stdout, X509_get_subject_name(SSL_get_peer_certificate(ssl)), 1, XN_FLAG_MULTILINE);
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n\n Cipher: %s\n", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n------------------------------------------------------------\n\n");
}
return ssl;
}
int socket_connect(evutil_socket_t clnet_fd, ioa_addr *remote_addr, int *connect_err) {
if (addr_connect(clnet_fd, remote_addr, connect_err) < 0) {
if (*connect_err == EINPROGRESS) {
return 0;
}
if (*connect_err == EADDRINUSE) {
return +1;
}
perror("connect");
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot connect to remote addr: %d\n", __FUNCTION__, *connect_err);
exit(-1);
}
return 0;
}
static int clnet_connect(uint16_t clnet_remote_port, const char *remote_address, const unsigned char *ifname,
const char *local_address, bool verbose, app_ur_conn_info *clnet_info) {
ioa_addr local_addr;
int connect_cycle = 0;
ioa_addr remote_addr;
start_socket:
memset(&remote_addr, 0, sizeof(ioa_addr));
if (make_ioa_addr((const uint8_t *)remote_address, clnet_remote_port, &remote_addr) < 0) {
return -1;
}
memset(&local_addr, 0, sizeof(ioa_addr));
evutil_socket_t clnet_fd = socket(
remote_addr.ss.sa_family,
use_sctp ? SCTP_CLIENT_STREAM_SOCKET_TYPE : (use_tcp ? CLIENT_STREAM_SOCKET_TYPE : CLIENT_DGRAM_SOCKET_TYPE),
use_sctp ? SCTP_CLIENT_STREAM_SOCKET_PROTOCOL
: (use_tcp ? CLIENT_STREAM_SOCKET_PROTOCOL : CLIENT_DGRAM_SOCKET_PROTOCOL));
if (clnet_fd < 0) {
perror("socket");
exit(-1);
}
if (sock_bind_to_device(clnet_fd, ifname) < 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Cannot bind client socket to device %s\n", ifname);
}
set_sock_buf_size(clnet_fd, UR_CLIENT_SOCK_BUF_SIZE);
set_raw_socket_tos(clnet_fd, remote_addr.ss.sa_family, 0x22);
set_raw_socket_ttl(clnet_fd, remote_addr.ss.sa_family, 47);
if (clnet_info->is_peer && (*local_address == 0)) {
if (remote_addr.ss.sa_family == AF_INET6) {
if (make_ioa_addr((const uint8_t *)"::1", 0, &local_addr) < 0) {
socket_closesocket(clnet_fd);
return -1;
}
} else {
if (make_ioa_addr((const uint8_t *)"127.0.0.1", 0, &local_addr) < 0) {
socket_closesocket(clnet_fd);
return -1;
}
}
addr_bind(clnet_fd, &local_addr, 0, 1, get_socket_type());
} else if (strlen(local_address) > 0) {
if (make_ioa_addr((const uint8_t *)local_address, 0, &local_addr) < 0) {
socket_closesocket(clnet_fd);
return -1;
}
addr_bind(clnet_fd, &local_addr, 0, 1, get_socket_type());
}
int connect_err = 0;
if (clnet_info->is_peer) {
;
} else if (socket_connect(clnet_fd, &remote_addr, &connect_err) > 0) {
goto start_socket;
}
if (clnet_info) {
addr_cpy(&(clnet_info->remote_addr), &remote_addr);
addr_cpy(&(clnet_info->local_addr), &local_addr);
clnet_info->fd = clnet_fd;
addr_get_from_sock(clnet_fd, &(clnet_info->local_addr));
STRCPY(clnet_info->lsaddr, local_address);
STRCPY(clnet_info->rsaddr, remote_address);
STRCPY(clnet_info->ifname, (const char *)ifname);
}
if (use_secure) {
bool try_again = false;
clnet_info->ssl = tls_connect(clnet_info->fd, &remote_addr, &try_again, connect_cycle++);
if (!clnet_info->ssl) {
if (try_again) {
goto start_socket;
}
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot SSL connect to remote addr\n", __FUNCTION__);
exit(-1);
}
}
if (verbose && clnet_info) {
addr_debug_print(verbose, &(clnet_info->local_addr), "Connected from");
addr_debug_print(verbose, &remote_addr, "Connected to");
}
if (!dos) {
usleep(500);
}
return 0;
}
int read_mobility_ticket(app_ur_conn_info *clnet_info, stun_buffer *message) {
int ret = 0;
if (clnet_info && message) {
stun_attr_ref s_mobile_id_sar = stun_attr_get_first_by_type(message, STUN_ATTRIBUTE_MOBILITY_TICKET);
if (s_mobile_id_sar) {
int smid_len = stun_attr_get_len(s_mobile_id_sar);
if (smid_len > 0 && (((size_t)smid_len) < sizeof(clnet_info->s_mobile_id))) {
const uint8_t *smid_val = stun_attr_get_value(s_mobile_id_sar);
if (smid_val) {
memcpy(clnet_info->s_mobile_id, smid_val, (size_t)smid_len);
clnet_info->s_mobile_id[smid_len] = 0;
if (clnet_verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: smid=%s\n", __FUNCTION__, clnet_info->s_mobile_id);
}
}
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: smid_len=%d\n", __FUNCTION__, smid_len);
ret = -1;
}
}
}
return ret;
}
void add_origin(stun_buffer *message) {
if (message && origin[0]) {
const char *some_origin = "https://carleon.gov:443";
stun_attr_add(message, STUN_ATTRIBUTE_ORIGIN, some_origin, strlen(some_origin));
stun_attr_add(message, STUN_ATTRIBUTE_ORIGIN, origin, strlen(origin));
some_origin = "ftp://uffrith.net";
stun_attr_add(message, STUN_ATTRIBUTE_ORIGIN, some_origin, strlen(some_origin));
}
}
static int clnet_allocate(bool verbose, app_ur_conn_info *clnet_info, ioa_addr *relay_addr, int af, char *turn_addr,
uint16_t *turn_port) {
int af_cycle = 0;
bool reopen_socket = false;
bool allocate_finished;
stun_buffer request_message, response_message;
beg_allocate:
allocate_finished = false;
while (!allocate_finished && af_cycle++ < 32) {
bool allocate_sent = false;
if (reopen_socket && !use_tcp) {
socket_closesocket(clnet_info->fd);
clnet_info->fd = -1;
if (clnet_connect(addr_get_port(&(clnet_info->remote_addr)), clnet_info->rsaddr, (uint8_t *)clnet_info->ifname,
clnet_info->lsaddr, verbose, clnet_info) < 0) {
exit(-1);
}
reopen_socket = false;
}
int af4 = dual_allocation || (af == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4);
int af6 = dual_allocation || (af == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6);
uint64_t reservation_token = 0;
char *rt = NULL;
// TODO: Not a bool, can hold -1.
// What is this variable representing?
int ep = !no_rtcp && !dual_allocation;
if (!no_rtcp) {
if (!never_allocate_rtcp && allocate_rtcp) {
reservation_token = ioa_ntoh64(current_reservation_token);
rt = (char *)(&reservation_token);
}
}
if (is_TCP_relay()) {
ep = -1;
} else if (rt) {
ep = -1;
} else if (!ep) {
ep = (((uint8_t)turn_random()) % 2);
ep = ep - 1;
}
if (!dos) {
stun_set_allocate_request(&request_message, UCLIENT_SESSION_LIFETIME, af4, af6, relay_transport, mobility, rt,
ep);
} else {
stun_set_allocate_request(&request_message, UCLIENT_SESSION_LIFETIME / 3, af4, af6, relay_transport, mobility, rt,
ep);
}
if (bps) {
stun_attr_add_bandwidth_str(request_message.buf, &(request_message.len), bps);
}
if (dont_fragment) {
stun_attr_add(&request_message, STUN_ATTRIBUTE_DONT_FRAGMENT, NULL, 0);
}
add_origin(&request_message);
if (add_integrity(clnet_info, &request_message) < 0) {
return -1;
}
stun_attr_add_fingerprint_str(request_message.buf, &(request_message.len));
while (!allocate_sent) {
int len = send_buffer(clnet_info, &request_message, 0, 0);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "allocate sent\n");
}
allocate_sent = 1;
} else {
perror("send");
exit(1);
}
}
////////////<<==allocate send
if (not_rare_event()) {
return 0;
}
////////allocate response==>>
{
bool allocate_received = false;
while (!allocate_received) {
int len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "allocate response received: \n");
}
response_message.len = len;
int err_code = 0;
uint8_t err_msg[129];
if (stun_is_success_response(&response_message)) {
allocate_received = true;
allocate_finished = true;
if (clnet_info->nonce[0]) {
if (check_integrity(clnet_info, &response_message) < 0) {
return -1;
}
}
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n");
}
{
bool found = false;
stun_attr_ref sar = stun_attr_get_first(&response_message);
while (sar) {
int attr_type = stun_attr_get_type(sar);
if (attr_type == STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS) {
if (!stun_attr_get_addr(&response_message, sar, relay_addr, NULL)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: !!!: relay addr cannot be received (1)\n", __FUNCTION__);
return -1;
} else {
if (verbose) {
ioa_addr raddr;
memcpy(&raddr, relay_addr, sizeof(ioa_addr));
addr_debug_print(verbose, &raddr, "Received relay addr");
}
if (!addr_any(relay_addr)) {
if (relay_addr->ss.sa_family == AF_INET) {
if (default_address_family != STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6) {
found = true;
addr_cpy(&(clnet_info->relay_addr), relay_addr);
break;
}
}
if (relay_addr->ss.sa_family == AF_INET6) {
if (default_address_family == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6) {
found = true;
addr_cpy(&(clnet_info->relay_addr), relay_addr);
break;
}
}
}
}
}
sar = stun_attr_get_next(&response_message, sar);
}
if (!found) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: !!!: relay addr cannot be received (2)\n", __FUNCTION__);
return -1;
}
}
stun_attr_ref rt_sar = stun_attr_get_first_by_type(&response_message, STUN_ATTRIBUTE_RESERVATION_TOKEN);
uint64_t rtv = stun_attr_get_reservation_token_value(rt_sar);
current_reservation_token = rtv;
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: rtv=%llu\n", __FUNCTION__, (long long unsigned int)rtv);
}
read_mobility_ticket(clnet_info, &response_message);
} else if (stun_is_challenge_response_str(response_message.buf, response_message.len, &err_code, err_msg,
sizeof(err_msg), clnet_info->realm, clnet_info->nonce,
clnet_info->server_name, &(clnet_info->oauth))) {
goto beg_allocate;
} else if (stun_is_error_response(&response_message, &err_code, err_msg, sizeof(err_msg))) {
allocate_received = true;
if (err_code == 300) {
if (clnet_info->nonce[0]) {
if (check_integrity(clnet_info, &response_message) < 0) {
return -1;
}
}
ioa_addr alternate_server;
if (!stun_attr_get_first_addr(&response_message, STUN_ATTRIBUTE_ALTERNATE_SERVER, &alternate_server,
NULL)) {
// error
} else if (turn_addr && turn_port) {
addr_to_string_no_port(&alternate_server, (uint8_t *)turn_addr);
*turn_port = (uint16_t)addr_get_port(&alternate_server);
}
}
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "error %d (%s)\n", err_code, (char *)err_msg);
if (err_code != 437) {
current_reservation_token = 0;
return -1;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "trying allocate again %d...\n", err_code);
sleep(1);
reopen_socket = true;
}
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "unknown allocate response\n");
/* Try again ? */
}
} else {
perror("recv");
exit(-1);
break;
}
}
}
}
////////////<<== allocate response received
if (rare_event()) {
return 0;
}
if (!allocate_finished) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot complete Allocation\n");
exit(-1);
}
allocate_rtcp = !allocate_rtcp;
if (true) {
af_cycle = 0;
if (clnet_info->s_mobile_id[0]) {
int fd = clnet_info->fd;
SSL *ssl = clnet_info->ssl;
bool close_now = turn_random() % 2;
if (close_now) {
bool close_socket = (int)(turn_random() % 2);
if (ssl && !close_socket) {
SSL_shutdown(ssl);
SSL_free(ssl);
fd = -1;
} else if (fd >= 0) {
socket_closesocket(fd);
fd = -1;
ssl = NULL;
}
}
app_ur_conn_info ci;
memcpy(&ci, clnet_info, sizeof(ci));
ci.fd = -1;
ci.ssl = NULL;
clnet_info->fd = -1;
clnet_info->ssl = NULL;
// Reopen:
if (clnet_connect(addr_get_port(&(ci.remote_addr)), ci.rsaddr, (unsigned char *)ci.ifname, ci.lsaddr,
clnet_verbose, clnet_info) < 0) {
exit(-1);
}
if (ssl) {
SSL_shutdown(ssl);
SSL_free(ssl);
} else if (fd >= 0) {
socket_closesocket(fd);
}
}
beg_refresh:
if (af_cycle++ > 32) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot complete Refresh\n");
exit(-1);
}
//==>>refresh request, for an example only:
{
bool refresh_sent = false;
stun_init_request(STUN_METHOD_REFRESH, &request_message);
uint32_t lt = htonl(UCLIENT_SESSION_LIFETIME);
stun_attr_add(&request_message, STUN_ATTRIBUTE_LIFETIME, (const char *)&lt, 4);
if (clnet_info->s_mobile_id[0]) {
stun_attr_add(&request_message, STUN_ATTRIBUTE_MOBILITY_TICKET, (const char *)clnet_info->s_mobile_id,
strlen(clnet_info->s_mobile_id));
}
if (dual_allocation && !mobility) {
// TODO: This could be reworked
// it's using t as a tri-state to determine whether to add the requested address family field
// it should be two seperate bools for readability purposes though.
uint8_t t = ((uint8_t)turn_random()) % 3;
if (t) {
uint8_t field[4];
field[0] = (t == 1) ? (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4
: (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6;
field[1] = 0;
field[2] = 0;
field[3] = 0;
stun_attr_add(&request_message, STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY, (const char *)field, 4);
}
}
add_origin(&request_message);
if (add_integrity(clnet_info, &request_message) < 0) {
return -1;
}
stun_attr_add_fingerprint_str(request_message.buf, &(request_message.len));
while (!refresh_sent) {
int len = send_buffer(clnet_info, &request_message, 0, 0);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "refresh sent\n");
}
refresh_sent = true;
if (clnet_info->s_mobile_id[0]) {
usleep(10000);
send_buffer(clnet_info, &request_message, 0, 0);
}
} else {
perror("send");
exit(1);
}
}
}
if (not_rare_event()) {
return 0;
}
////////refresh response==>>
{
bool refresh_received = false;
while (!refresh_received) {
int len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message);
if (clnet_info->s_mobile_id[0]) {
len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message);
}
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "refresh response received: \n");
}
response_message.len = len;
int err_code = 0;
uint8_t err_msg[129];
if (stun_is_success_response(&response_message)) {
read_mobility_ticket(clnet_info, &response_message);
refresh_received = true;
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n");
}
} else if (stun_is_challenge_response_str(response_message.buf, response_message.len, &err_code, err_msg,
sizeof(err_msg), clnet_info->realm, clnet_info->nonce,
clnet_info->server_name, &(clnet_info->oauth))) {
goto beg_refresh;
} else if (stun_is_error_response(&response_message, &err_code, err_msg, sizeof(err_msg))) {
refresh_received = true;
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "error %d (%s)\n", err_code, (char *)err_msg);
return -1;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "unknown refresh response\n");
/* Try again ? */
}
} else {
perror("recv");
exit(-1);
break;
}
}
}
}
return 0;
}
static int turn_channel_bind(bool verbose, uint16_t *chn, app_ur_conn_info *clnet_info, ioa_addr *peer_addr) {
stun_buffer request_message, response_message;
beg_bind:
if (negative_test) {
*chn = stun_set_channel_bind_request(&request_message, peer_addr, (uint16_t)turn_random());
} else {
*chn = stun_set_channel_bind_request(&request_message, peer_addr, *chn);
}
add_origin(&request_message);
if (add_integrity(clnet_info, &request_message) < 0) {
return -1;
}
stun_attr_add_fingerprint_str(request_message.buf, &(request_message.len));
bool cb_sent = false;
while (!cb_sent) {
int len = send_buffer(clnet_info, &request_message, 0, 0);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "channel bind sent\n");
}
cb_sent = true;
} else {
perror("send");
exit(1);
}
}
////////////<<==channel bind send
if (not_rare_event()) {
return 0;
}
////////channel bind response==>>
{
bool cb_received = false;
while (!cb_received) {
int len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "cb response received: \n");
}
int err_code = 0;
uint8_t err_msg[129];
if (stun_is_success_response(&response_message)) {
cb_received = true;
if (clnet_info->nonce[0]) {
if (check_integrity(clnet_info, &response_message) < 0) {
return -1;
}
}
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success: 0x%x\n", (int)(*chn));
}
} else if (stun_is_challenge_response_str(response_message.buf, response_message.len, &err_code, err_msg,
sizeof(err_msg), clnet_info->realm, clnet_info->nonce,
clnet_info->server_name, &(clnet_info->oauth))) {
goto beg_bind;
} else if (stun_is_error_response(&response_message, &err_code, err_msg, sizeof(err_msg))) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "channel bind: error %d (%s)\n", err_code, (char *)err_msg);
return -1;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "unknown channel bind response\n");
/* Try again ? */
}
} else {
perror("recv");
exit(-1);
break;
}
}
}
return 0;
}
static int turn_create_permission(bool verbose, app_ur_conn_info *clnet_info, ioa_addr *peer_addr, int addrnum) {
if (no_permissions || (addrnum < 1)) {
return 0;
}
char saddr[129] = "\0";
if (verbose) {
addr_to_string(peer_addr, (uint8_t *)saddr);
}
stun_buffer request_message, response_message;
beg_cp:
stun_init_request(STUN_METHOD_CREATE_PERMISSION, &request_message);
for (int addrindex = 0; addrindex < addrnum; ++addrindex) {
stun_attr_add_addr(&request_message, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, peer_addr + addrindex);
}
add_origin(&request_message);
if (add_integrity(clnet_info, &request_message) < 0) {
return -1;
}
stun_attr_add_fingerprint_str(request_message.buf, &(request_message.len));
bool cp_sent = false;
while (!cp_sent) {
int len = send_buffer(clnet_info, &request_message, 0, 0);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "create perm sent: %s\n", saddr);
}
cp_sent = true;
} else {
perror("send");
exit(1);
}
}
////////////<<==create permission send
if (not_rare_event()) {
return 0;
}
////////create permission response==>>
{
bool cp_received = false;
while (!cp_received) {
int len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "cp response received: \n");
}
int err_code = 0;
uint8_t err_msg[129];
if (stun_is_success_response(&response_message)) {
cp_received = true;
if (clnet_info->nonce[0]) {
if (check_integrity(clnet_info, &response_message) < 0) {
return -1;
}
}
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n");
}
} else if (stun_is_challenge_response_str(response_message.buf, response_message.len, &err_code, err_msg,
sizeof(err_msg), clnet_info->realm, clnet_info->nonce,
clnet_info->server_name, &(clnet_info->oauth))) {
goto beg_cp;
} else if (stun_is_error_response(&response_message, &err_code, err_msg, sizeof(err_msg))) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "create permission error %d (%s)\n", err_code, (char *)err_msg);
return -1;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "unknown create permission response\n");
/* Try again ? */
}
} else {
perror("recv");
exit(-1);
}
}
}
return 0;
}
int start_connection(uint16_t clnet_remote_port0, const char *remote_address0, const unsigned char *ifname,
const char *local_address, bool verbose, app_ur_conn_info *clnet_info_probe,
app_ur_conn_info *clnet_info, uint16_t *chn, app_ur_conn_info *clnet_info_rtcp,
uint16_t *chn_rtcp) {
ioa_addr relay_addr;
ioa_addr relay_addr_rtcp;
ioa_addr peer_addr_rtcp;
addr_cpy(&peer_addr_rtcp, &peer_addr);
addr_set_port(&peer_addr_rtcp, addr_get_port(&peer_addr_rtcp) + 1);
/* Probe: */
if (clnet_connect(clnet_remote_port0, remote_address0, ifname, local_address, verbose, clnet_info_probe) < 0) {
exit(-1);
}
uint16_t clnet_remote_port = clnet_remote_port0;
char remote_address[1025];
STRCPY(remote_address, remote_address0);
clnet_allocate(verbose, clnet_info_probe, &relay_addr, default_address_family, remote_address, &clnet_remote_port);
/* Real: */
*chn = 0;
if (chn_rtcp) {
*chn_rtcp = 0;
}
if (clnet_connect(clnet_remote_port, remote_address, ifname, local_address, verbose, clnet_info) < 0) {
exit(-1);
}
if (!no_rtcp) {
if (clnet_connect(clnet_remote_port, remote_address, ifname, local_address, verbose, clnet_info_rtcp) < 0) {
exit(-1);
}
}
int af = default_address_family ? default_address_family : get_allocate_address_family(&peer_addr);
if (clnet_allocate(verbose, clnet_info, &relay_addr, af, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (!no_rtcp) {
af = default_address_family ? default_address_family : get_allocate_address_family(&peer_addr_rtcp);
if (clnet_allocate(verbose, clnet_info_rtcp, &relay_addr_rtcp, af, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
}
if (!dos) {
if (!do_not_use_channel) {
/* These multiple "channel bind" requests are here only because
* we are playing with the TURN server trying to screw it */
if (turn_channel_bind(verbose, chn, clnet_info, &peer_addr_rtcp) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (turn_channel_bind(verbose, chn, clnet_info, &peer_addr_rtcp) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
*chn = 0;
if (turn_channel_bind(verbose, chn, clnet_info, &peer_addr) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (turn_channel_bind(verbose, chn, clnet_info, &peer_addr) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (extra_requests) {
const char *sarbaddr = "164.156.178.190";
if (turn_random() % 2 == 0) {
sarbaddr = "2001::172";
}
ioa_addr arbaddr;
make_ioa_addr((const uint8_t *)sarbaddr, 333, &arbaddr);
int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
for (int i = 0; i < maxi; i++) {
uint16_t chni = 0;
int port = (unsigned short)turn_random();
if (port < 1024) {
port += 1024;
}
addr_set_port(&arbaddr, port);
uint8_t *u = (uint8_t *)&(arbaddr.s4.sin_addr);
u[(unsigned short)turn_random() % 4] = u[(unsigned short)turn_random() % 4] + 1;
// char sss[128];
// addr_to_string(&arbaddr,(uint8_t*)sss);
// printf("%s: 111.111: %s\n",__FUNCTION__,sss);
turn_channel_bind(verbose, &chni, clnet_info, &arbaddr);
}
}
if (!no_rtcp) {
if (turn_channel_bind(verbose, chn_rtcp, clnet_info_rtcp, &peer_addr_rtcp) < 0) {
exit(-1);
}
}
if (rare_event()) {
return 0;
}
if (extra_requests) {
const char *sarbaddr = "64.56.78.90";
if (turn_random() % 2 == 0) {
sarbaddr = "2001::172";
}
ioa_addr arbaddr[EXTRA_CREATE_PERMS];
make_ioa_addr((const uint8_t *)sarbaddr, 333, &arbaddr[0]);
int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
for (int i = 0; i < maxi; i++) {
if (i > 0) {
addr_cpy(&arbaddr[i], &arbaddr[0]);
}
addr_set_port(&arbaddr[i], (unsigned short)turn_random());
uint8_t *u = (uint8_t *)&(arbaddr[i].s4.sin_addr);
u[(unsigned short)turn_random() % 4] = u[(unsigned short)turn_random() % 4] + 1;
// char sss[128];
// addr_to_string(&arbaddr[i],(uint8_t*)sss);
// printf("%s: 111.111: %s\n",__FUNCTION__,sss);
}
turn_create_permission(verbose, clnet_info, arbaddr, maxi);
}
} else {
bool const before = turn_random() % 2;
if (before) {
if (turn_create_permission(verbose, clnet_info, &peer_addr, 1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (turn_create_permission(verbose, clnet_info, &peer_addr_rtcp, 1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
}
if (extra_requests) {
const char *sarbaddr = "64.56.78.90";
if (turn_random() % 2) {
sarbaddr = "2001::172";
}
ioa_addr arbaddr[EXTRA_CREATE_PERMS];
make_ioa_addr((const uint8_t *)sarbaddr, 333, &arbaddr[0]);
int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
for (int i = 0; i < maxi; i++) {
if (i > 0) {
addr_cpy(&arbaddr[i], &arbaddr[0]);
}
addr_set_port(&arbaddr[i], (unsigned short)turn_random());
uint8_t *u = (uint8_t *)&(arbaddr[i].s4.sin_addr);
u[(unsigned short)turn_random() % 4] = u[(unsigned short)turn_random() % 4] + 1;
// char sss[128];
// addr_to_string(&arbaddr,(uint8_t*)sss);
// printf("%s: 111.111: %s\n",__FUNCTION__,sss);
}
turn_create_permission(verbose, clnet_info, arbaddr, maxi);
}
if (!before) {
if (turn_create_permission(verbose, clnet_info, &peer_addr, 1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (turn_create_permission(verbose, clnet_info, &peer_addr_rtcp, 1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
}
if (!no_rtcp) {
if (turn_create_permission(verbose, clnet_info_rtcp, &peer_addr_rtcp, 1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (turn_create_permission(verbose, clnet_info_rtcp, &peer_addr, 1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
}
}
}
addr_cpy(&(clnet_info->peer_addr), &peer_addr);
if (!no_rtcp) {
addr_cpy(&(clnet_info_rtcp->peer_addr), &peer_addr_rtcp);
}
return 0;
}
int start_c2c_connection(uint16_t clnet_remote_port0, const char *remote_address0, const unsigned char *ifname,
const char *local_address, bool verbose, app_ur_conn_info *clnet_info_probe,
app_ur_conn_info *clnet_info1, uint16_t *chn1, app_ur_conn_info *clnet_info1_rtcp,
uint16_t *chn1_rtcp, app_ur_conn_info *clnet_info2, uint16_t *chn2,
app_ur_conn_info *clnet_info2_rtcp, uint16_t *chn2_rtcp) {
ioa_addr relay_addr1;
ioa_addr relay_addr1_rtcp;
ioa_addr relay_addr2;
ioa_addr relay_addr2_rtcp;
*chn1 = 0;
*chn2 = 0;
if (chn1_rtcp) {
*chn1_rtcp = 0;
}
if (chn2_rtcp) {
*chn2_rtcp = 0;
}
/* Probe: */
if (clnet_connect(clnet_remote_port0, remote_address0, ifname, local_address, verbose, clnet_info_probe) < 0) {
exit(-1);
}
uint16_t clnet_remote_port = clnet_remote_port0;
char remote_address[1025];
STRCPY(remote_address, remote_address0);
clnet_allocate(verbose, clnet_info_probe, &relay_addr1, default_address_family, remote_address, &clnet_remote_port);
if (rare_event()) {
return 0;
}
/* Real: */
if (clnet_connect(clnet_remote_port, remote_address, ifname, local_address, verbose, clnet_info1) < 0) {
exit(-1);
}
if (!no_rtcp) {
if (clnet_connect(clnet_remote_port, remote_address, ifname, local_address, verbose, clnet_info1_rtcp) < 0) {
exit(-1);
}
}
if (passive_tcp) {
clnet_info2->is_peer = true;
}
if (clnet_connect(clnet_remote_port, remote_address, ifname, local_address, verbose, clnet_info2) < 0) {
exit(-1);
}
if (!no_rtcp) {
if (clnet_connect(clnet_remote_port, remote_address, ifname, local_address, verbose, clnet_info2_rtcp) < 0) {
exit(-1);
}
}
if (!no_rtcp) {
if (clnet_allocate(verbose, clnet_info1, &relay_addr1, default_address_family, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (clnet_allocate(verbose, clnet_info1_rtcp, &relay_addr1_rtcp, default_address_family, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (clnet_allocate(verbose, clnet_info2, &relay_addr2, default_address_family, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (clnet_allocate(verbose, clnet_info2_rtcp, &relay_addr2_rtcp, default_address_family, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
} else {
if (clnet_allocate(verbose, clnet_info1, &relay_addr1, default_address_family, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (!(clnet_info2->is_peer)) {
if (clnet_allocate(verbose, clnet_info2, &relay_addr2, default_address_family, NULL, NULL) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
} else {
addr_cpy(&(clnet_info2->remote_addr), &relay_addr1);
addr_cpy(&relay_addr2, &(clnet_info2->local_addr));
}
}
if (!do_not_use_channel) {
if (turn_channel_bind(verbose, chn1, clnet_info1, &relay_addr2) < 0) {
exit(-1);
}
if (extra_requests) {
const char *sarbaddr = "164.156.178.190";
if (turn_random() % 2 == 0) {
sarbaddr = "2001::172";
}
ioa_addr arbaddr;
make_ioa_addr((const uint8_t *)sarbaddr, 333, &arbaddr);
int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
for (int i = 0; i < maxi; i++) {
uint16_t chni = 0;
int port = (unsigned short)turn_random();
if (port < 1024) {
port += 1024;
}
addr_set_port(&arbaddr, port);
uint8_t *u = (uint8_t *)&(arbaddr.s4.sin_addr);
u[(unsigned short)turn_random() % 4] = u[(unsigned short)turn_random() % 4] + 1;
// char sss[128];
// addr_to_string(&arbaddr,(uint8_t*)sss);
// printf("%s: 111.111: %s\n",__FUNCTION__,sss);
turn_channel_bind(verbose, &chni, clnet_info1, &arbaddr);
}
}
if (rare_event()) {
return 0;
}
if (extra_requests) {
const char *sarbaddr = "64.56.78.90";
if (turn_random() % 2 == 0) {
sarbaddr = "2001::172";
}
ioa_addr arbaddr[EXTRA_CREATE_PERMS];
make_ioa_addr((const uint8_t *)sarbaddr, 333, &arbaddr[0]);
int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
for (int i = 0; i < maxi; i++) {
if (i > 0) {
addr_cpy(&arbaddr[i], &arbaddr[0]);
}
addr_set_port(&arbaddr[i], (unsigned short)turn_random());
uint8_t *u = (uint8_t *)&(arbaddr[i].s4.sin_addr);
u[(unsigned short)turn_random() % 4] = u[(unsigned short)turn_random() % 4] + 1;
// char sss[128];
// addr_to_string(&arbaddr[i],(uint8_t*)sss);
// printf("%s: 111.111: %s\n",__FUNCTION__,sss);
}
turn_create_permission(verbose, clnet_info1, arbaddr, maxi);
}
if (!no_rtcp) {
if (turn_channel_bind(verbose, chn1_rtcp, clnet_info1_rtcp, &relay_addr2_rtcp) < 0) {
exit(-1);
}
}
if (rare_event()) {
return 0;
}
if (turn_channel_bind(verbose, chn2, clnet_info2, &relay_addr1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
if (!no_rtcp) {
if (turn_channel_bind(verbose, chn2_rtcp, clnet_info2_rtcp, &relay_addr1_rtcp) < 0) {
exit(-1);
}
}
if (rare_event()) {
return 0;
}
} else {
if (turn_create_permission(verbose, clnet_info1, &relay_addr2, 1) < 0) {
exit(-1);
}
if (extra_requests) {
const char *sarbaddr = "64.56.78.90";
if (turn_random() % 2 == 0) {
sarbaddr = "2001::172";
}
ioa_addr arbaddr;
make_ioa_addr((const uint8_t *)sarbaddr, 333, &arbaddr);
int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
for (int i = 0; i < maxi; i++) {
addr_set_port(&arbaddr, (unsigned short)turn_random());
uint8_t *u = (uint8_t *)&(arbaddr.s4.sin_addr);
u[(unsigned short)turn_random() % 4] = u[(unsigned short)turn_random() % 4] + 1;
// char sss[128];
// addr_to_string(&arbaddr,(uint8_t*)sss);
// printf("%s: 111.111: %s\n",__FUNCTION__,sss);
turn_create_permission(verbose, clnet_info1, &arbaddr, 1);
}
}
if (rare_event()) {
return 0;
}
if (!no_rtcp) {
if (turn_create_permission(verbose, clnet_info1_rtcp, &relay_addr2_rtcp, 1) < 0) {
exit(-1);
}
}
if (rare_event()) {
return 0;
}
if (!(clnet_info2->is_peer)) {
if (turn_create_permission(verbose, clnet_info2, &relay_addr1, 1) < 0) {
exit(-1);
}
if (rare_event()) {
return 0;
}
}
if (!no_rtcp) {
if (turn_create_permission(verbose, clnet_info2_rtcp, &relay_addr1_rtcp, 1) < 0) {
exit(-1);
}
}
if (rare_event()) {
return 0;
}
}
addr_cpy(&(clnet_info1->peer_addr), &relay_addr2);
if (!no_rtcp) {
addr_cpy(&(clnet_info1_rtcp->peer_addr), &relay_addr2_rtcp);
}
addr_cpy(&(clnet_info2->peer_addr), &relay_addr1);
if (!no_rtcp) {
addr_cpy(&(clnet_info2_rtcp->peer_addr), &relay_addr1_rtcp);
}
return 0;
}
//////////// RFC 6062 ///////////////
int turn_tcp_connect(bool verbose, app_ur_conn_info *clnet_info, ioa_addr *peer_addr) {
{
bool cp_sent = false;
stun_buffer message;
stun_init_request(STUN_METHOD_CONNECT, &message);
stun_attr_add_addr(&message, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, peer_addr);
add_origin(&message);
if (add_integrity(clnet_info, &message) < 0) {
return -1;
}
stun_attr_add_fingerprint_str(message.buf, (size_t *)&(message.len));
while (!cp_sent) {
int len = send_buffer(clnet_info, &message, 0, 0);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "tcp connect sent\n");
}
cp_sent = true;
} else {
perror("send");
exit(1);
}
}
}
////////////<<==connect send
return 0;
}
static int turn_tcp_connection_bind(int verbose, app_ur_conn_info *clnet_info, app_tcp_conn_info *atc, int errorOK) {
stun_buffer request_message, response_message;
beg_cb:
stun_init_request(STUN_METHOD_CONNECTION_BIND, &request_message);
uint32_t cid = atc->cid;
stun_attr_add(&request_message, STUN_ATTRIBUTE_CONNECTION_ID, (const char *)&cid, 4);
add_origin(&request_message);
if (add_integrity(clnet_info, &request_message) < 0) {
return -1;
}
stun_attr_add_fingerprint_str(request_message.buf, (size_t *)&(request_message.len));
bool cb_sent = false;
while (!cb_sent) {
int len = send_buffer(clnet_info, &request_message, 1, atc);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "connection bind sent\n");
}
cb_sent = true;
} else {
if (errorOK) {
return 0;
}
perror("send");
exit(1);
}
}
////////////<<==connection bind send
if (not_rare_event()) {
return 0;
}
////////connection bind response==>>
{
bool cb_received = false;
while (!cb_received) {
int len = recv_buffer(clnet_info, &response_message, 1, 1, atc, &request_message);
if (len > 0) {
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "connect bind response received: \n");
}
int err_code = 0;
uint8_t err_msg[129];
if (stun_is_success_response(&response_message)) {
if (clnet_info->nonce[0]) {
if (check_integrity(clnet_info, &response_message) < 0) {
return -1;
}
}
if (stun_get_method(&response_message) != STUN_METHOD_CONNECTION_BIND) {
continue;
}
cb_received = true;
if (verbose) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n");
}
atc->tcp_data_bound = true;
} else if (stun_is_challenge_response_str(response_message.buf, response_message.len, &err_code, err_msg,
sizeof(err_msg), clnet_info->realm, clnet_info->nonce,
clnet_info->server_name, &(clnet_info->oauth))) {
goto beg_cb;
} else if (stun_is_error_response(&response_message, &err_code, err_msg, sizeof(err_msg))) {
cb_received = true;
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "connection bind error %d (%s)\n", err_code, (char *)err_msg);
return -1;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "unknown connection bind response\n");
/* Try again ? */
}
} else {
if (errorOK) {
return 0;
}
perror("recv");
exit(-1);
}
}
}
return 0;
}
void tcp_data_connect(app_ur_session *elem, uint32_t cid) {
int clnet_fd;
int connect_cycle = 0;
again:
clnet_fd = socket(elem->pinfo.remote_addr.ss.sa_family, CLIENT_STREAM_SOCKET_TYPE, CLIENT_STREAM_SOCKET_PROTOCOL);
if (clnet_fd < 0) {
perror("socket");
exit(-1);
}
if (sock_bind_to_device(clnet_fd, client_ifname) < 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Cannot bind client socket to device %s\n", client_ifname);
}
set_sock_buf_size(clnet_fd, (UR_CLIENT_SOCK_BUF_SIZE << 2));
++elem->pinfo.tcp_conn_number;
int i = (int)(elem->pinfo.tcp_conn_number - 1);
elem->pinfo.tcp_conn =
(app_tcp_conn_info **)realloc(elem->pinfo.tcp_conn, elem->pinfo.tcp_conn_number * sizeof(app_tcp_conn_info *));
elem->pinfo.tcp_conn[i] = (app_tcp_conn_info *)calloc(sizeof(app_tcp_conn_info), 1);
elem->pinfo.tcp_conn[i]->tcp_data_fd = clnet_fd;
elem->pinfo.tcp_conn[i]->cid = cid;
addr_cpy(&(elem->pinfo.tcp_conn[i]->tcp_data_local_addr), &(elem->pinfo.local_addr));
addr_set_port(&(elem->pinfo.tcp_conn[i]->tcp_data_local_addr), 0);
addr_bind(clnet_fd, &(elem->pinfo.tcp_conn[i]->tcp_data_local_addr), 1, 1, TCP_SOCKET);
addr_get_from_sock(clnet_fd, &(elem->pinfo.tcp_conn[i]->tcp_data_local_addr));
{
int cycle = 0;
while (cycle++ < 1024) {
int err = 0;
if (addr_connect(clnet_fd, &(elem->pinfo.remote_addr), &err) < 0) {
if (err == EADDRINUSE) {
socket_closesocket(clnet_fd);
clnet_fd =
socket(elem->pinfo.remote_addr.ss.sa_family, CLIENT_STREAM_SOCKET_TYPE, CLIENT_STREAM_SOCKET_PROTOCOL);
if (clnet_fd < 0) {
perror("socket");
exit(-1);
}
if (sock_bind_to_device(clnet_fd, client_ifname) < 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Cannot bind client socket to device %s\n", client_ifname);
}
set_sock_buf_size(clnet_fd, UR_CLIENT_SOCK_BUF_SIZE << 2);
elem->pinfo.tcp_conn[i]->tcp_data_fd = clnet_fd;
addr_cpy(&(elem->pinfo.tcp_conn[i]->tcp_data_local_addr), &(elem->pinfo.local_addr));
addr_set_port(&(elem->pinfo.tcp_conn[i]->tcp_data_local_addr), 0);
addr_bind(clnet_fd, &(elem->pinfo.tcp_conn[i]->tcp_data_local_addr), 1, 1, TCP_SOCKET);
addr_get_from_sock(clnet_fd, &(elem->pinfo.tcp_conn[i]->tcp_data_local_addr));
continue;
} else {
perror("connect");
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot connect to remote addr\n", __FUNCTION__);
exit(-1);
}
} else {
break;
}
}
}
if (use_secure) {
bool try_again = false;
elem->pinfo.tcp_conn[i]->tcp_data_ssl =
tls_connect(elem->pinfo.tcp_conn[i]->tcp_data_fd, &(elem->pinfo.remote_addr), &try_again, connect_cycle++);
if (!(elem->pinfo.tcp_conn[i]->tcp_data_ssl)) {
if (try_again) {
--elem->pinfo.tcp_conn_number;
goto again;
}
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot SSL connect to remote addr\n", __FUNCTION__);
exit(-1);
}
}
if (turn_tcp_connection_bind(clnet_verbose, &(elem->pinfo), elem->pinfo.tcp_conn[i], 0) < 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot BIND to tcp connection\n", __FUNCTION__);
} else {
socket_set_nonblocking(clnet_fd);
struct event *ev = event_new(client_event_base, clnet_fd, EV_READ | EV_PERSIST, client_input_handler, elem);
event_add(ev, NULL);
elem->input_tcp_data_ev = ev;
addr_debug_print(clnet_verbose, &(elem->pinfo.remote_addr), "TCP data network connected to");
}
}
/////////////////////////////////////////////////