Browse Source

Imported Upstream version 4.2.3.1

Oleg Moskalenko 11 years ago
parent
commit
ae725add45

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+11/07/2014 Oleg Moskalenko <[email protected]>
+Version 4.2.3.1 'Monza':
+	- Request re-transmission implemented in uclient test program.
+	- TLS connection procedure improved in uclient test program.
+
 10/26/2014 Oleg Moskalenko <[email protected]>
 Version 4.2.2.2 'Monza':
 	- Black- and white- IP lists are divided per realm

+ 1 - 1
INSTALL

@@ -774,7 +774,7 @@ CREATE TABLE turn_realm_option (
 # oAuth key storage table.
 #
 CREATE TABLE oauth_key (
-	kid varchar(128), /* 
+	kid varchar(128), 
 	ikm_key varchar(256) default '',
 	timestamp bigint default 0,
 	lifetime integer default 0,

+ 0 - 7
README.turnutils

@@ -8,13 +8,6 @@ for testing and for setting up the TURN server.
 The compiled binary image of this program is located in bin/ 
 sub-directory.
 
-WARNING: the turnutils_uclient program is a primitive client application. 
-It does not implement the re-transmission pattern that is necessary for 
-a correct TURN client implementation. In TURN, the retransmission burden 
-is lying almost entirely on the client application. We provide the messaging 
-functionality in the client library, but the client must implement 
-the correct Networking IO processing in the client program code.
-
 2.	turnutils_peer: a simple stateless UDP-only "echo" server, 
 to be used as the final server in relay pattern ("peer"). For every incoming 
 UDP packet, it simply echoes it back.

+ 1 - 1
TODO

@@ -105,7 +105,7 @@
 
 ==================================================================
 
-nope
+none
 
 ==================================================================
 

+ 0 - 4
debian/etc/ufw/applications.d/turnserver

@@ -1,4 +0,0 @@
-[Turnserver]
-title=Coturn Turnserver
-description=Free open source implementation of TURN and STUN Server
-ports=3478,3479,5349,5350,49152:65535/tcp|3478,3479,5349,5350,49152:65535/udp

+ 1 - 1
man/man1/turnadmin.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "28 September 2014" "" ""
+.TH TURN 1 "09 November 2014" "" ""
 .SH GENERAL INFORMATION
 
 \fIturnadmin\fP is a TURN administration tool. This tool can be used to manage 

+ 2 - 2
man/man1/turnserver.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "28 September 2014" "" ""
+.TH TURN 1 "09 November 2014" "" ""
 .SH GENERAL INFORMATION
 
 The \fBTURN Server\fP project contains the source code of a TURN server and TURN client 
@@ -277,7 +277,7 @@ it does not make much sense with the short\-term mechanism.
 .TP
 .B
 \fB\-\-oauth\fP
-Support oAuth authentication.
+Support oAuth authentication, as in the third\-party TURN specs document.
 .TP
 .B
 \fB\-\-dh566\fP

+ 1 - 8
man/man1/turnutils.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "28 September 2014" "" ""
+.TH TURN 1 "09 November 2014" "" ""
 .SH GENERAL INFORMATION
 
 A set of turnutils_* programs provides some utility functionality to be used
@@ -11,13 +11,6 @@ for testing and for setting up the TURN server.
 (this program is provided for the testing purposes only !)
 The compiled binary image of this program is located in bin/ 
 sub\-directory.
-.PP
-WARNING: the \fIturnutils_uclient\fP program is a primitive client application. 
-It does not implement the re\-transmission pattern that is necessary for 
-a correct TURN client implementation. In TURN, the retransmission burden 
-is lying almost entirely on the client application. We provide the messaging 
-functionality in the client library, but the client must implement 
-the correct Networking IO processing in the client program code.
 .TP
 .B
 2.

+ 1 - 1
rpm/build.settings.sh

@@ -2,7 +2,7 @@
 
 # Common settings script.
 
-TURNVERSION=4.2.2.2
+TURNVERSION=4.2.3.1
 BUILDDIR=~/rpmbuild
 ARCH=`uname -p`
 TURNSERVER_SVN_URL=http://coturn.googlecode.com/svn

+ 3 - 1
rpm/turnserver.spec

@@ -1,5 +1,5 @@
 Name:		turnserver
-Version:	4.2.2.2
+Version:	4.2.3.1
 Release:	0%{dist}
 Summary:	Coturn TURN Server
 
@@ -294,6 +294,8 @@ fi
 %{_includedir}/turn/client/TurnMsgLib.h
 
 %changelog
+* Thu Nov 07 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 4.2.3.1
 * Sun Oct 26 2014 Oleg Moskalenko <[email protected]>
   - Sync to 4.2.2.2
 * Sun Oct 05 2014 Oleg Moskalenko <[email protected]>

+ 1 - 2
src/apps/uclient/mainuclient.c

@@ -146,7 +146,6 @@ static char Usage[] =
   "	-k	Private key file (for secure connections only).\n"
   "	-E	CA file for server certificate verification, \n"
   "		if the server certificate to be verified.\n"
-  "	-F	Cipher suite for TLS/DTLS. Default value is DEFAULT.\n"
   "	-p	TURN server port (Default: 3478 unsecure, 5349 secure).\n"
   "	-n	Number of messages to send (Default: 5).\n"
   "	-d	Local interface device (optional).\n"
@@ -188,7 +187,7 @@ void recalculate_restapi_hmac(void) {
 					g_upwd[pwd_length] = 0;
 				}
 			}
-			free(pwd);
+			turn_free(pwd,strlen(pwd)+1);
 		}
 	}
 }

+ 125 - 127
src/apps/uclient/startuclient.c

@@ -76,11 +76,12 @@ static int get_allocate_address_family(ioa_addr *relay_addr) {
 
 /////////////////////////////////////////
 
-static SSL* tls_connect(ioa_socket_raw fd, ioa_addr *remote_addr)
+static SSL* tls_connect(ioa_socket_raw fd, ioa_addr *remote_addr, int *try_again)
 {
 	int ctxtype = (int)(((unsigned long)random())%root_tls_ctx_num);
+	SSL *ssl;
 
-	SSL *ssl = SSL_NEW(root_tls_ctx[ctxtype]);
+	ssl = SSL_NEW(root_tls_ctx[ctxtype]);
 
 	if(use_tcp) {
 		SSL_set_fd(ssl, fd);
@@ -133,8 +134,8 @@ static SSL* tls_connect(ioa_socket_raw fd, ioa_addr *remote_addr)
 		  }
 		  break;
 		} else {
-			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot connect\n",
-					__FUNCTION__);
+			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:
@@ -143,8 +144,13 @@ static SSL* tls_connect(ioa_socket_raw fd, ioa_addr *remote_addr)
 			default: {
 				char buf[1025];
 				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s (%d)\n",
-						ERR_error_string(ERR_get_error(), buf), SSL_get_error(
-								ssl, rc));
+						ERR_error_string(ERR_get_error(), buf), SSL_get_error(ssl, rc));
+				if(ctxtype>0) {
+					if(try_again) {
+						*try_again = 1;
+						return NULL;
+					}
+				}
 				exit(-1);
 			}
 			};
@@ -259,8 +265,13 @@ static int clnet_connect(uint16_t clnet_remote_port, const char *remote_address,
 	}
 
 	if (use_secure) {
-		clnet_info->ssl = tls_connect(clnet_info->fd, &remote_addr);
+		int try_again = 0;
+		clnet_info->ssl = tls_connect(clnet_info->fd, &remote_addr,&try_again);
 		if (!clnet_info->ssl) {
+			if(try_again) {
+				close(clnet_fd);
+				goto start_socket;
+			}
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot SSL connect to remote addr\n", __FUNCTION__);
 			exit(-1);
 		}
@@ -317,15 +328,15 @@ static int clnet_allocate(int verbose,
 		app_ur_conn_info *clnet_info,
 		ioa_addr *relay_addr,
 		int af,
-		char *turn_addr, u16bits *turn_port,
-		stun_tid *in_tid,
-		stun_tid *out_tid) {
+		char *turn_addr, u16bits *turn_port) {
 
 	int af_cycle = 0;
 	int reopen_socket = 0;
 
 	int allocate_finished;
 
+	stun_buffer request_message, response_message;
+
 	beg_allocate:
 
 	allocate_finished=0;
@@ -344,15 +355,14 @@ static int clnet_allocate(int verbose,
 			reopen_socket = 0;
 		}
 
-		stun_buffer message;
-		if(!in_tid && current_reservation_token) {
+		if(current_reservation_token) {
 			af = STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_DEFAULT;
 		}
 
 		int af4 = dual_allocation || (af == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4);
 		int af6 = dual_allocation || (af == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6);
 
-		if(!no_rtcp && !in_tid) {
+		if(!no_rtcp) {
 			if (!never_allocate_rtcp && allocate_rtcp) {
 				af4 = 0;
 				af6 = 0;
@@ -360,42 +370,34 @@ static int clnet_allocate(int verbose,
 		}
 
 		if(!dos)
-			stun_set_allocate_request(&message, UCLIENT_SESSION_LIFETIME, af4, af6, relay_transport, mobility);
+			stun_set_allocate_request(&request_message, UCLIENT_SESSION_LIFETIME, af4, af6, relay_transport, mobility);
 		else
-			stun_set_allocate_request(&message, UCLIENT_SESSION_LIFETIME/3, af4, af6, relay_transport, mobility);
+			stun_set_allocate_request(&request_message, UCLIENT_SESSION_LIFETIME/3, af4, af6, relay_transport, mobility);
 
 		if(bps)
-			stun_attr_add_bandwidth_str(message.buf, (size_t*)(&(message.len)), bps);
-
-		if(in_tid) {
-			stun_tid_message_cpy(message.buf, in_tid);
-		}
+			stun_attr_add_bandwidth_str(request_message.buf, (size_t*)(&(request_message.len)), bps);
 
 		if(dont_fragment)
-			stun_attr_add(&message, STUN_ATTRIBUTE_DONT_FRAGMENT, NULL, 0);
-		if(!no_rtcp && !in_tid) {
+			stun_attr_add(&request_message, STUN_ATTRIBUTE_DONT_FRAGMENT, NULL, 0);
+		if(!no_rtcp) {
 		  if (!never_allocate_rtcp && allocate_rtcp) {
 		    uint64_t reservation_token = ioa_ntoh64(current_reservation_token);
-		    stun_attr_add(&message, STUN_ATTRIBUTE_RESERVATION_TOKEN,
+		    stun_attr_add(&request_message, STUN_ATTRIBUTE_RESERVATION_TOKEN,
 				  (char*) (&reservation_token), 8);
 		  } else {
-		    stun_attr_add_even_port(&message, 1);
+		    stun_attr_add_even_port(&request_message, 1);
 		  }
 		}
 
-		add_origin(&message);
-
-		if(add_integrity(clnet_info, &message)<0) return -1;
+		add_origin(&request_message);
 
-		stun_attr_add_fingerprint_str(message.buf,(size_t*)&(message.len));
+		if(add_integrity(clnet_info, &request_message)<0) return -1;
 
-		if(out_tid) {
-			stun_tid_from_message_str(message.buf, (size_t)message.len, out_tid);
-		}
+		stun_attr_add_fingerprint_str(request_message.buf,(size_t*)&(request_message.len));
 
 		while (!allocate_sent) {
 
-			int len = send_buffer(clnet_info, &message,0,0);
+			int len = send_buffer(clnet_info, &request_message,0,0);
 
 			if (len > 0) {
 				if (verbose) {
@@ -415,25 +417,24 @@ static int clnet_allocate(int verbose,
 		////////allocate response==>>
 		{
 			int allocate_received = 0;
-			stun_buffer message;
 			while (!allocate_received) {
 
-				int len = recv_buffer(clnet_info, &message, 1, 0);
+				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");
 					}
-					message.len = len;
+					response_message.len = len;
 					int err_code = 0;
 					u08bits err_msg[129];
-					if (stun_is_success_response(&message)) {
+					if (stun_is_success_response(&response_message)) {
 						allocate_received = 1;
 						allocate_finished = 1;
 
 						if(clnet_info->nonce[0] || use_short_term) {
-							if(check_integrity(clnet_info, &message)<0)
+							if(check_integrity(clnet_info, &response_message)<0)
 								return -1;
 						}
 
@@ -443,13 +444,13 @@ static int clnet_allocate(int verbose,
 						{
 							int found = 0;
 
-							stun_attr_ref sar = stun_attr_get_first(&message);
+							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(&message, sar, relay_addr, NULL) < 0) {
+									if (stun_attr_get_addr(&response_message, sar, relay_addr, NULL) < 0) {
 										TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
 											"%s: !!!: relay addr cannot be received (1)\n",
 											__FUNCTION__);
@@ -480,7 +481,7 @@ static int clnet_allocate(int verbose,
 									}
 								}
 
-								sar = stun_attr_get_next(&message,sar);
+								sar = stun_attr_get_next(&response_message,sar);
 							}
 
 							if(!found) {
@@ -492,16 +493,16 @@ static int clnet_allocate(int verbose,
 						}
 
 						stun_attr_ref rt_sar = stun_attr_get_first_by_type(
-								&message, STUN_ATTRIBUTE_RESERVATION_TOKEN);
+								&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, &message);
+						read_mobility_ticket(clnet_info, &response_message);
 
-					} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
+					} else if (stun_is_challenge_response_str(response_message.buf, (size_t)response_message.len,
 									&err_code,err_msg,sizeof(err_msg),
 									clnet_info->realm,clnet_info->nonce,
 									clnet_info->server_name, &(clnet_info->oauth))) {
@@ -510,7 +511,7 @@ static int clnet_allocate(int verbose,
 							recalculate_restapi_hmac();
 						}
 						goto beg_allocate;
-					} else if (stun_is_error_response(&message, &err_code,err_msg,sizeof(err_msg))) {
+					} else if (stun_is_error_response(&response_message, &err_code,err_msg,sizeof(err_msg))) {
 
 						if(err_code == SHA_TOO_WEAK_ERROR_CODE && (clnet_info->shatype == SHATYPE_SHA1) && use_short_term) {
 							clnet_info->shatype = SHATYPE_SHA256;
@@ -522,12 +523,12 @@ static int clnet_allocate(int verbose,
 						if(err_code == 300) {
 
 							if(clnet_info->nonce[0] || use_short_term) {
-								if(check_integrity(clnet_info, &message)<0)
+								if(check_integrity(clnet_info, &response_message)<0)
 									return -1;
 							}
 
 							ioa_addr alternate_server;
-							if(stun_attr_get_first_addr(&message, STUN_ATTRIBUTE_ALTERNATE_SERVER, &alternate_server, NULL)==-1) {
+							if(stun_attr_get_first_addr(&response_message, STUN_ATTRIBUTE_ALTERNATE_SERVER, &alternate_server, NULL)==-1) {
 								//error
 							} else if(turn_addr && turn_port){
 								addr_to_string_no_port(&alternate_server, (u08bits*)turn_addr);
@@ -571,9 +572,7 @@ static int clnet_allocate(int verbose,
 	  exit(-1);
 	}
 
-	if(!in_tid) {
-		allocate_rtcp = !allocate_rtcp;
-	}
+	allocate_rtcp = !allocate_rtcp;
 
 	if (1) {
 
@@ -632,24 +631,23 @@ static int clnet_allocate(int verbose,
 		{
 			int refresh_sent = 0;
 
-			stun_buffer message;
-			stun_init_request(STUN_METHOD_REFRESH, &message);
+			stun_init_request(STUN_METHOD_REFRESH, &request_message);
 			uint32_t lt = htonl(UCLIENT_SESSION_LIFETIME);
-			stun_attr_add(&message, STUN_ATTRIBUTE_LIFETIME, (const char*) &lt, 4);
+			stun_attr_add(&request_message, STUN_ATTRIBUTE_LIFETIME, (const char*) &lt, 4);
 
 			if(clnet_info->s_mobile_id[0]) {
-				stun_attr_add(&message, STUN_ATTRIBUTE_MOBILITY_TICKET, (const char*)clnet_info->s_mobile_id, strlen(clnet_info->s_mobile_id));
+				stun_attr_add(&request_message, STUN_ATTRIBUTE_MOBILITY_TICKET, (const char*)clnet_info->s_mobile_id, strlen(clnet_info->s_mobile_id));
 			}
 
-			add_origin(&message);
+			add_origin(&request_message);
 
-			if(add_integrity(clnet_info, &message)<0) return -1;
+			if(add_integrity(clnet_info, &request_message)<0) return -1;
 
-			stun_attr_add_fingerprint_str(message.buf,(size_t*)&(message.len));
+			stun_attr_add_fingerprint_str(request_message.buf,(size_t*)&(request_message.len));
 
 			while (!refresh_sent) {
 
-				int len = send_buffer(clnet_info, &message, 0,0);
+				int len = send_buffer(clnet_info, &request_message, 0,0);
 
 				if (len > 0) {
 					if (verbose) {
@@ -659,7 +657,7 @@ static int clnet_allocate(int verbose,
 
 					if(clnet_info->s_mobile_id[0]) {
 						usleep(10000);
-						send_buffer(clnet_info, &message, 0,0);
+						send_buffer(clnet_info, &request_message, 0,0);
 					}
 				} else {
 					perror("send");
@@ -673,13 +671,12 @@ static int clnet_allocate(int verbose,
 		////////refresh response==>>
 		{
 			int refresh_received = 0;
-			stun_buffer message;
 			while (!refresh_received) {
 
-				int len = recv_buffer(clnet_info, &message, 1, 0);
+				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, &message, 1, 0);
+					len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message);
 				}
 
 				if (len > 0) {
@@ -687,16 +684,16 @@ static int clnet_allocate(int verbose,
 						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
 								"refresh response received: \n");
 					}
-					message.len = len;
+					response_message.len = len;
 					int err_code = 0;
 					u08bits err_msg[129];
-					if (stun_is_success_response(&message)) {
-						read_mobility_ticket(clnet_info, &message);
+					if (stun_is_success_response(&response_message)) {
+						read_mobility_ticket(clnet_info, &response_message);
 						refresh_received = 1;
 						if (verbose) {
 							TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n");
 						}
-					} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
+					} else if (stun_is_challenge_response_str(response_message.buf, (size_t)response_message.len,
 										&err_code,err_msg,sizeof(err_msg),
 										clnet_info->realm,clnet_info->nonce,
 										clnet_info->server_name, &(clnet_info->oauth))) {
@@ -705,7 +702,7 @@ static int clnet_allocate(int verbose,
 							recalculate_restapi_hmac();
 						}
 						goto beg_refresh;
-					} else if (stun_is_error_response(&message, &err_code,err_msg,sizeof(err_msg))) {
+					} else if (stun_is_error_response(&response_message, &err_code,err_msg,sizeof(err_msg))) {
 						refresh_received = 1;
 						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "error %d (%s)\n",
 								      err_code,(char*)err_msg);
@@ -729,28 +726,28 @@ static int clnet_allocate(int verbose,
 static int turn_channel_bind(int verbose, uint16_t *chn,
 		app_ur_conn_info *clnet_info, ioa_addr *peer_addr) {
 
+	stun_buffer request_message, response_message;
+
 	beg_bind:
 
 	{
 		int cb_sent = 0;
 
-		stun_buffer message;
-
 		if(negative_test) {
-			*chn = stun_set_channel_bind_request(&message, peer_addr, (u16bits)random());
+			*chn = stun_set_channel_bind_request(&request_message, peer_addr, (u16bits)random());
 		} else {
-			*chn = stun_set_channel_bind_request(&message, peer_addr, *chn);
+			*chn = stun_set_channel_bind_request(&request_message, peer_addr, *chn);
 		}
 
-		add_origin(&message);
+		add_origin(&request_message);
 
-		if(add_integrity(clnet_info, &message)<0) return -1;
+		if(add_integrity(clnet_info, &request_message)<0) return -1;
 
-		stun_attr_add_fingerprint_str(message.buf,(size_t*)&(message.len));
+		stun_attr_add_fingerprint_str(request_message.buf,(size_t*)&(request_message.len));
 
 		while (!cb_sent) {
 
-			int len = send_buffer(clnet_info, &message, 0,0);
+			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");
@@ -771,10 +768,9 @@ static int turn_channel_bind(int verbose, uint16_t *chn,
 
 	{
 		int cb_received = 0;
-		stun_buffer message;
 		while (!cb_received) {
 
-			int len = recv_buffer(clnet_info, &message, 1, 0);
+			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,
@@ -782,12 +778,12 @@ static int turn_channel_bind(int verbose, uint16_t *chn,
 				}
 				int err_code = 0;
 				u08bits err_msg[129];
-				if (stun_is_success_response(&message)) {
+				if (stun_is_success_response(&response_message)) {
 
 					cb_received = 1;
 
 					if(clnet_info->nonce[0] || use_short_term) {
-						if(check_integrity(clnet_info, &message)<0)
+						if(check_integrity(clnet_info, &response_message)<0)
 							return -1;
 					}
 
@@ -795,7 +791,7 @@ static int turn_channel_bind(int verbose, uint16_t *chn,
 						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success: 0x%x\n",
 								(int) (*chn));
 					}
-				} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
+				} else if (stun_is_challenge_response_str(response_message.buf, (size_t)response_message.len,
 										&err_code,err_msg,sizeof(err_msg),
 										clnet_info->realm,clnet_info->nonce,
 										clnet_info->server_name, &(clnet_info->oauth))) {
@@ -804,7 +800,7 @@ static int turn_channel_bind(int verbose, uint16_t *chn,
 						recalculate_restapi_hmac();
 					}
 					goto beg_bind;
-				} else if (stun_is_error_response(&message, &err_code,err_msg,sizeof(err_msg))) {
+				} else if (stun_is_error_response(&response_message, &err_code,err_msg,sizeof(err_msg))) {
 					cb_received = 1;
 					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "channel bind: error %d (%s)\n",
 							      err_code,(char*)err_msg);
@@ -836,30 +832,30 @@ static int turn_create_permission(int verbose, app_ur_conn_info *clnet_info,
 		addr_to_string(peer_addr,(u08bits*)saddr);
 	}
 
+	stun_buffer request_message, response_message;
+
 	beg_cp:
 
 	{
 		int cp_sent = 0;
 
-		stun_buffer message;
-
-		stun_init_request(STUN_METHOD_CREATE_PERMISSION, &message);
+		stun_init_request(STUN_METHOD_CREATE_PERMISSION, &request_message);
 		{
 			int addrindex;
 			for(addrindex=0;addrindex<addrnum;++addrindex) {
-				stun_attr_add_addr(&message, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, peer_addr+addrindex);
+				stun_attr_add_addr(&request_message, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, peer_addr+addrindex);
 			}
 		}
 
-		add_origin(&message);
+		add_origin(&request_message);
 
-		if(add_integrity(clnet_info, &message)<0) return -1;
+		if(add_integrity(clnet_info, &request_message)<0) return -1;
 
-		stun_attr_add_fingerprint_str(message.buf,(size_t*)&(message.len));
+		stun_attr_add_fingerprint_str(request_message.buf,(size_t*)&(request_message.len));
 
 		while (!cp_sent) {
 
-			int len = send_buffer(clnet_info, &message, 0,0);
+			int len = send_buffer(clnet_info, &request_message, 0,0);
 
 			if (len > 0) {
 				if (verbose) {
@@ -881,10 +877,9 @@ static int turn_create_permission(int verbose, app_ur_conn_info *clnet_info,
 
 	{
 		int cp_received = 0;
-		stun_buffer message;
 		while (!cp_received) {
 
-			int len = recv_buffer(clnet_info, &message, 1, 0);
+			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,
@@ -892,19 +887,19 @@ static int turn_create_permission(int verbose, app_ur_conn_info *clnet_info,
 				}
 				int err_code = 0;
 				u08bits err_msg[129];
-				if (stun_is_success_response(&message)) {
+				if (stun_is_success_response(&response_message)) {
 
 					cp_received = 1;
 
 					if(clnet_info->nonce[0] || use_short_term) {
-						if(check_integrity(clnet_info, &message)<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(message.buf, (size_t)message.len,
+				} else if (stun_is_challenge_response_str(response_message.buf, (size_t)response_message.len,
 									&err_code,err_msg,sizeof(err_msg),
 									clnet_info->realm,clnet_info->nonce,
 									clnet_info->server_name, &(clnet_info->oauth))) {
@@ -913,7 +908,7 @@ static int turn_create_permission(int verbose, app_ur_conn_info *clnet_info,
 						recalculate_restapi_hmac();
 					}
 					goto beg_cp;
-				} else if (stun_is_error_response(&message, &err_code,err_msg,sizeof(err_msg))) {
+				} else if (stun_is_error_response(&response_message, &err_code,err_msg,sizeof(err_msg))) {
 					cp_received = 1;
 					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "create permission error %d (%s)\n",
 							      err_code,(char*)err_msg);
@@ -960,9 +955,7 @@ int start_connection(uint16_t clnet_remote_port0,
 	char remote_address[1025];
 	STRCPY(remote_address,remote_address0);
 
-	stun_tid tid;
-
-	clnet_allocate(verbose, clnet_info_probe, &relay_addr, default_address_family, remote_address, &clnet_remote_port,NULL,NULL);
+	clnet_allocate(verbose, clnet_info_probe, &relay_addr, default_address_family, remote_address, &clnet_remote_port);
 
 	/* Real: */
 
@@ -982,20 +975,15 @@ int start_connection(uint16_t clnet_remote_port0,
 	}
 
 	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,NULL,&tid) < 0) {
+	if (clnet_allocate(verbose, clnet_info, &relay_addr, af, NULL,NULL) < 0) {
 	  exit(-1);
 	}
 
-	//strcpy((char*)g_uname,"qqq");
-	//if (clnet_allocate(verbose, clnet_info, &relay_addr, af, NULL,NULL,&tid,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,NULL,NULL) < 0) {
+	  if (clnet_allocate(verbose, clnet_info_rtcp, &relay_addr_rtcp, af,NULL,NULL) < 0) {
 	    exit(-1);
 	  }
 	  if(rare_event()) return 0;
@@ -1182,7 +1170,7 @@ int start_c2c_connection(uint16_t 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,NULL,NULL);
+	clnet_allocate(verbose, clnet_info_probe, &relay_addr1, default_address_family, remote_address, &clnet_remote_port);
 
 	if(rare_event()) return 0;
 
@@ -1215,7 +1203,7 @@ int start_c2c_connection(uint16_t clnet_remote_port0,
 
 	if(!no_rtcp) {
 
-	  if (clnet_allocate(verbose, clnet_info1, &relay_addr1, default_address_family,NULL,NULL,NULL,NULL)
+	  if (clnet_allocate(verbose, clnet_info1, &relay_addr1, default_address_family,NULL,NULL)
 	      < 0) {
 	    exit(-1);
 	  }
@@ -1223,13 +1211,13 @@ int start_c2c_connection(uint16_t clnet_remote_port0,
 	  if(rare_event()) return 0;
 
 	  if (clnet_allocate(verbose, clnet_info1_rtcp,
-			   &relay_addr1_rtcp, default_address_family,NULL,NULL,NULL,NULL) < 0) {
+			   &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,NULL,NULL)
+	  if (clnet_allocate(verbose, clnet_info2, &relay_addr2, default_address_family,NULL,NULL)
 	      < 0) {
 	    exit(-1);
 	  }
@@ -1237,20 +1225,20 @@ int start_c2c_connection(uint16_t clnet_remote_port0,
 	  if(rare_event()) return 0;
 
 	  if (clnet_allocate(verbose, clnet_info2_rtcp,
-			   &relay_addr2_rtcp, default_address_family,NULL,NULL,NULL,NULL) < 0) {
+			   &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,NULL,NULL)
+	  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,NULL,NULL) < 0) {
+		  if (clnet_allocate(verbose, clnet_info2, &relay_addr2, default_address_family,NULL,NULL) < 0) {
 			  exit(-1);
 		  }
 		  if(rare_event()) return 0;
@@ -1421,27 +1409,28 @@ int turn_tcp_connect(int verbose, app_ur_conn_info *clnet_info, ioa_addr *peer_a
 
 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:
 
 	{
 		int cb_sent = 0;
 
-		stun_buffer message;
 		u32bits cid = atc->cid;
 
-		stun_init_request(STUN_METHOD_CONNECTION_BIND, &message);
+		stun_init_request(STUN_METHOD_CONNECTION_BIND, &request_message);
 
-		stun_attr_add(&message, STUN_ATTRIBUTE_CONNECTION_ID, (const s08bits*)&cid,4);
+		stun_attr_add(&request_message, STUN_ATTRIBUTE_CONNECTION_ID, (const s08bits*)&cid,4);
 
-		add_origin(&message);
+		add_origin(&request_message);
 
-		if(add_integrity(clnet_info, &message)<0) return -1;
+		if(add_integrity(clnet_info, &request_message)<0) return -1;
 
-		stun_attr_add_fingerprint_str(message.buf,(size_t*)&(message.len));
+		stun_attr_add_fingerprint_str(request_message.buf,(size_t*)&(request_message.len));
 
 		while (!cb_sent) {
 
-			int len = send_buffer(clnet_info, &message, 1, atc);
+			int len = send_buffer(clnet_info, &request_message, 1, atc);
 
 			if (len > 0) {
 				if (verbose) {
@@ -1465,10 +1454,9 @@ static int turn_tcp_connection_bind(int verbose, app_ur_conn_info *clnet_info, a
 
 	{
 		int cb_received = 0;
-		stun_buffer message;
 		while (!cb_received) {
 
-			int len = recv_buffer(clnet_info, &message, 1, atc);
+			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,
@@ -1476,21 +1464,21 @@ static int turn_tcp_connection_bind(int verbose, app_ur_conn_info *clnet_info, a
 				}
 				int err_code = 0;
 				u08bits err_msg[129];
-				if (stun_is_success_response(&message)) {
+				if (stun_is_success_response(&response_message)) {
 
 					if(clnet_info->nonce[0] || use_short_term) {
-						if(check_integrity(clnet_info, &message)<0)
+						if(check_integrity(clnet_info, &response_message)<0)
 							return -1;
 					}
 
-					if(stun_get_method(&message)!=STUN_METHOD_CONNECTION_BIND)
+					if(stun_get_method(&response_message)!=STUN_METHOD_CONNECTION_BIND)
 						continue;
 					cb_received = 1;
 					if (verbose) {
 						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n");
 					}
 					atc->tcp_data_bound = 1;
-				} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
+				} else if (stun_is_challenge_response_str(response_message.buf, (size_t)response_message.len,
 										&err_code,err_msg,sizeof(err_msg),
 										clnet_info->realm,clnet_info->nonce,
 										clnet_info->server_name, &(clnet_info->oauth))) {
@@ -1499,7 +1487,7 @@ static int turn_tcp_connection_bind(int verbose, app_ur_conn_info *clnet_info, a
 						recalculate_restapi_hmac();
 					}
 					goto beg_cb;
-				} else if (stun_is_error_response(&message, &err_code,err_msg,sizeof(err_msg))) {
+				} else if (stun_is_error_response(&response_message, &err_code,err_msg,sizeof(err_msg))) {
 					cb_received = 1;
 					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "connection bind error %d (%s)\n",
 							      err_code,(char*)err_msg);
@@ -1522,7 +1510,11 @@ static int turn_tcp_connection_bind(int verbose, app_ur_conn_info *clnet_info, a
 
 void tcp_data_connect(app_ur_session *elem, u32bits cid)
 {
-	int clnet_fd = socket(elem->pinfo.remote_addr.ss.sa_family, SOCK_STREAM, 0);
+	int clnet_fd;
+
+	again:
+
+	clnet_fd = socket(elem->pinfo.remote_addr.ss.sa_family, SOCK_STREAM, 0);
 	if (clnet_fd < 0) {
 		perror("socket");
 		exit(-1);
@@ -1594,8 +1586,14 @@ void tcp_data_connect(app_ur_session *elem, u32bits cid)
 	}
 
 	if(use_secure) {
-		elem->pinfo.tcp_conn[i]->tcp_data_ssl = tls_connect(elem->pinfo.tcp_conn[i]->tcp_data_fd, &(elem->pinfo.remote_addr));
+		int try_again = 0;
+		elem->pinfo.tcp_conn[i]->tcp_data_ssl = tls_connect(elem->pinfo.tcp_conn[i]->tcp_data_fd, &(elem->pinfo.remote_addr),&try_again);
 		if(!(elem->pinfo.tcp_conn[i]->tcp_data_ssl)) {
+			if(try_again) {
+				close(clnet_fd);
+				--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);

+ 180 - 12
src/apps/uclient/uclient.c

@@ -40,6 +40,8 @@
 #include <openssl/err.h>
 #include <openssl/rand.h>
 
+#include <sys/select.h>
+
 static int verbose_packets=0;
 
 static size_t current_clients_number = 0;
@@ -69,6 +71,8 @@ static app_ur_session** elems = NULL;
 
 #define SLEEP_INTERVAL (234)
 
+#define MAX_LISTENING_CYCLE_NUMBER (7)
+
 int RTP_PACKET_INTERVAL = 20;
 
 static inline s64bits time_minus(u64bits t1, u64bits t2) {
@@ -302,11 +306,68 @@ int send_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int data_con
 	return ret;
 }
 
-int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync,
-		app_tcp_conn_info *atc) {
+static int wait_fd(int fd, unsigned int cycle) {
+
+	if(fd>=(int)FD_SETSIZE) {
+		return 1;
+	} else {
+		fd_set fds;
+		FD_ZERO(&fds);
+		FD_SET(fd,&fds);
+
+		if(dos && cycle==0)
+			return 0;
+
+		struct timeval start_time;
+		struct timeval ctime;
+		gettimeofday(&start_time,NULL);
+
+		ctime.tv_sec = start_time.tv_sec;
+		ctime.tv_usec = start_time.tv_usec;
+
+		int rc = 0;
+
+		do {
+			struct timeval timeout = {0,0};
+			if(cycle == 0) {
+				timeout.tv_usec = 500000;
+			} else {
+
+				timeout.tv_sec = 1;
+				while(--cycle) timeout.tv_sec = timeout.tv_sec + timeout.tv_sec;
+
+				if(ctime.tv_sec > start_time.tv_sec) {
+					if(ctime.tv_sec >= start_time.tv_sec + timeout.tv_sec) {
+						break;
+					} else {
+						timeout.tv_sec -= (ctime.tv_sec - start_time.tv_sec);
+					}
+				}
+			}
+			rc = select(fd+1,&fds,NULL,NULL,&timeout);
+			if((rc<0) && (errno == EINTR)) {
+				gettimeofday(&ctime,NULL);
+			} else {
+				break;
+			}
+		} while(1);
+
+		return rc;
+	}
+}
+
+int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync, int data_connection, app_tcp_conn_info *atc, stun_buffer* request_message) {
 
 	int rc = 0;
 
+	stun_tid tid;
+	u16bits method = 0;
+
+	if(request_message) {
+		stun_tid_from_message(request_message, &tid);
+		method = stun_get_method(request_message);
+	}
+
 	ioa_socket_raw fd = clnet_info->fd;
 	if (atc)
 		fd = atc->tcp_data_fd;
@@ -315,6 +376,24 @@ int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync,
 	if (atc)
 		ssl = atc->tcp_data_ssl;
 
+	recv_again:
+
+	if(!use_tcp && sync && request_message && (fd>=0)) {
+
+		unsigned int cycle = 0;
+		while(cycle < MAX_LISTENING_CYCLE_NUMBER) {
+			int serc = wait_fd(fd,cycle);
+			if(serc>0)
+				break;
+			if(serc<0) {
+				return -1;
+			}
+			if(send_buffer(clnet_info, request_message, data_connection, atc)<=0)
+				return -1;
+			++cycle;
+		}
+	}
+
 	if (!use_secure && !use_tcp && fd >= 0) {
 
 		/* Plain UDP */
@@ -331,9 +410,9 @@ int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync,
 
 		message->len = rc;
 
-	} else if (use_secure && ssl && !(clnet_info->broken)) {
+	} else if (use_secure && !use_tcp && ssl && !(clnet_info->broken)) {
 
-		/* TLS/DTLS */
+		/* DTLS */
 
 		int message_received = 0;
 		int cycle = 0;
@@ -400,6 +479,74 @@ int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync,
 			}
 		}
 
+	} else if (use_secure && use_tcp && ssl && !(clnet_info->broken)) {
+
+		/* TLS*/
+
+		int message_received = 0;
+		int cycle = 0;
+		while (!message_received && cycle++ < 100) {
+
+			if (SSL_get_shutdown(ssl))
+				return -1;
+				rc = 0;
+			do {
+				rc = SSL_read(ssl, message->buf, sizeof(message->buf) - 1);
+				if (rc < 0 && errno == EAGAIN && sync)
+					continue;
+			} while (rc < 0 && (errno == EINTR));
+
+			if (rc > 0) {
+
+				if (clnet_verbose) {
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+							"response received: size=%d\n", rc);
+				}
+				message->len = rc;
+				message_received = 1;
+
+			} else {
+
+			int sslerr = SSL_get_error(ssl, rc);
+
+				switch (sslerr) {
+				case SSL_ERROR_NONE:
+					/* Try again ? */
+					break;
+				case SSL_ERROR_WANT_WRITE:
+					/* Just try again later */
+					break;
+				case SSL_ERROR_WANT_READ:
+					/* continue with reading */
+					break;
+				case SSL_ERROR_ZERO_RETURN:
+					/* Try again */
+					break;
+				case SSL_ERROR_SYSCALL:
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+							"Socket read error 111.999: \n");
+					if (handle_socket_error())
+						break;
+				case SSL_ERROR_SSL: {
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "SSL write error: \n");
+					char buf[1024];
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s (%d)\n",
+							ERR_error_string(ERR_get_error(), buf),
+							SSL_get_error(ssl, rc));
+				}
+				default:
+					clnet_info->broken = 1;
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+							"Unexpected error while reading: rc=%d, sslerr=%d\n",
+							rc, sslerr);
+					return -1;
+				}
+
+				if (!sync)
+					break;
+			}
+		}
+
 	} else if (!use_secure && use_tcp && fd >= 0) {
 
 		/* Plain TCP */
@@ -465,6 +612,27 @@ int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync,
 		}
 	}
 
+	if(rc>0) {
+		if(request_message) {
+
+			stun_tid recv_tid;
+			u16bits recv_method = 0;
+
+			stun_tid_from_message(message, &recv_tid);
+			recv_method = stun_get_method(message);
+
+			if(method != recv_method) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Received wrong response method: 0x%x, expected 0x%x; trying again...\n",(unsigned int)recv_method,(unsigned int)method);
+				goto recv_again;
+			}
+
+			if(memcmp(tid.tsx_id,recv_tid.tsx_id,STUN_TID_SIZE)) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Received wrong response tid; trying again...\n");
+				goto recv_again;
+			}
+		}
+	}
+
 	return rc;
 }
 
@@ -488,7 +656,7 @@ static int client_read(app_ur_session *elem, int is_tcp_data, app_tcp_conn_info
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "before read ...\n");
 	}
 
-	rc = recv_buffer(clnet_info, &(elem->in_buffer), 0, atc);
+	rc = recv_buffer(clnet_info, &(elem->in_buffer), 0, is_tcp_data, atc, NULL);
 
 	if (clnet_verbose && verbose_packets) {
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "read %d bytes\n", (int) rc);
@@ -792,13 +960,13 @@ void client_input_handler(evutil_socket_t fd, short what, void* arg) {
     if(elem->pinfo.tcp_conn) {
       int i = 0;
       for(i=0;i<(int)(elem->pinfo.tcp_conn_number);++i) {
-	if(elem->pinfo.tcp_conn[i]) {
-	  if((fd==elem->pinfo.tcp_conn[i]->tcp_data_fd) && (elem->pinfo.tcp_conn[i]->tcp_data_bound)) {
-	    is_tcp_data = 1;
-	    atc = elem->pinfo.tcp_conn[i];
-	    break;
-	  }
-	}
+    	  if(elem->pinfo.tcp_conn[i]) {
+    		  if((fd==elem->pinfo.tcp_conn[i]->tcp_data_fd) && (elem->pinfo.tcp_conn[i]->tcp_data_bound)) {
+    			  is_tcp_data = 1;
+    			  atc = elem->pinfo.tcp_conn[i];
+    			  break;
+    		  }
+    	  }
       }
     }
     int rc = client_read(elem, is_tcp_data, atc);

+ 1 - 1
src/apps/uclient/uclient.h

@@ -99,7 +99,7 @@ void start_mclient(const char *remote_address, int port,
 		   int messagenumber, int mclient);
 
 int send_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int data_connection, app_tcp_conn_info *atc);
-int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync, app_tcp_conn_info *atc);
+int recv_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int sync, int data_connection, app_tcp_conn_info *atc, stun_buffer* request_message);
 
 void client_input_handler(evutil_socket_t fd, short what, void* arg);
 

+ 1 - 1
src/ns_turn_defs.h

@@ -31,7 +31,7 @@
 #ifndef __IOADEFS__
 #define __IOADEFS__
 
-#define TURN_SERVER_VERSION "4.2.2.2"
+#define TURN_SERVER_VERSION "4.2.3.1"
 #define TURN_SERVER_VERSION_NAME "Monza"
 #define TURN_SOFTWARE "Coturn-" TURN_SERVER_VERSION " '" TURN_SERVER_VERSION_NAME "'"