Просмотр исходного кода

Imported Upstream version 4.0.1.2

Oleg Moskalenko 11 лет назад
Родитель
Сommit
358203dd0e

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+06/06/2014 Oleg Moskalenko <[email protected]>
+Version 4.0.1.2 'Severard':
+	- Bandwidth draft implemented.
+	- Issues 126, 127 and 128 fixes merged from rfc5766-turn-server.
+
 05/18/2014 Oleg Moskalenko <[email protected]>
 Version 4.0.0.2 'Threetrees':
 	- Code cleaning.

+ 1 - 0
INSTALL

@@ -34,6 +34,7 @@ Read the INSTALl file:
  
 Install the *.deb file:
 
+  $ sudo apt-get update
   $ sudo apt-get install gdebi-core
   $ sudo gdebi coturn*.deb
 

+ 5 - 0
README.turnserver

@@ -377,6 +377,11 @@ Options with required values:
 			that limit will be dropped or temporary suppressed (within the
 			available buffer limits). This option can also be set through the 
 			database, for a particular realm.
+			
+-B, --bps-capacity	Maximum server capacity.
+			Total bytes-per-second bandwidth the TURN server is allowed to allocate
+			for the sessions, combined (input and output network streams are treated
+			separately).
 
 --static-auth-secret	Static authentication secret value (a string) for TURN REST API only.
 			If not set, then the turn server will try to use the dynamic value 

+ 6 - 2
README.turnutils

@@ -113,7 +113,7 @@ Flags:
 		
 -G	Generate extra requests (create permissions, channel bind).
 
--B  Random disconnect after a few initial packets.
+-B  	Random disconnect after a few initial packets.
 
 Options with required values:  
 
@@ -148,11 +148,15 @@ Options with required values:
 
 -W      TURN REST API authentication secret. Is not compatible with -A flag.
 
--C	This is the timestamp/username separator symbol (character) in 
+-C  	This is the timestamp/username separator symbol (character) in 
 	TURN REST API. The default value is :.
 
 -F	Cipher suite for TLS/DTLS. Default value is DEFAULT.
 
+-o	the ORIGIN STUN attribute value.
+
+-a	Bandwidth for the bandwidth request in ALLOCATE. The default value is zero.
+
 See the examples in the "examples/scripts" directory.
 
 ======================================

+ 1 - 1
TODO

@@ -64,7 +64,7 @@ when necessary:
 
 3) MS TURN, MS STUN extensions.
 
-4) Bandwidth draft.
+4) Multiple origins.
 
 5) ALPN with TLS and DTLS (when OpenSSL 1.0.2 is available).
 

+ 7 - 0
examples/etc/turnserver.conf

@@ -312,6 +312,13 @@
 #
 #max-bps=0
 
+#
+# Maximum server capacity.
+# Total bytes-per-second bandwidth the TURN server is allowed to allocate
+# for the sessions, combined (input and output network streams are treated separately).
+#
+# bps-capacity=0
+
 # Uncomment if no UDP client listener is desired.
 # By default UDP client listener is always started.
 #

+ 1 - 1
man/man1/turnadmin.1

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

+ 8 - 1
man/man1/turnserver.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "23 April 2014" "" ""
+.TH TURN 1 "29 May 2014" "" ""
 .SH GENERAL INFORMATION
 
 The \fBTURN Server\fP project contains the source code of a TURN server and TURN client 
@@ -559,6 +559,13 @@ available buffer limits). This option can also be set through the
 database, for a particular realm.
 .TP
 .B
+\fB\-B\fP, \fB\-\-bps\-capacity\fP
+Maximum server capacity.
+Total bytes\-per\-second bandwidth the TURN server is allowed to allocate
+for the sessions, combined (input and output network streams are treated
+separately).
+.TP
+.B
 \fB\-\-static\-auth\-secret\fP
 Static authentication secret value (a string) for TURN REST API only.
 If not set, then the turn server will try to use the dynamic value 

+ 9 - 1
man/man1/turnutils.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "23 April 2014" "" ""
+.TH TURN 1 "29 May 2014" "" ""
 .SH GENERAL INFORMATION
 
 A set of turnutils_* programs provides some utility functionality to be used
@@ -244,6 +244,14 @@ TURN REST API. The default value is :.
 .B
 \fB\-F\fP
 Cipher suite for TLS/DTLS. Default value is DEFAULT.
+.TP
+.B
+\fB\-o\fP
+the ORIGIN STUN attribute value.
+.TP
+.B
+\fB\-a\fP
+Bandwidth for the bandwidth request in ALLOCATE. The default value is zero.
 .PP
 See the examples in the "examples/scripts" directory.
 .PP

+ 1 - 1
rpm/build.settings.sh

@@ -2,7 +2,7 @@
 
 # Common settings script.
 
-TURNVERSION=4.0.0.2
+TURNVERSION=4.0.1.2
 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.0.0.2
+Version:	4.0.1.2
 Release:	0%{dist}
 Summary:	Coturn TURN Server
 
@@ -289,6 +289,8 @@ fi
 %{_includedir}/turn/client/TurnMsgLib.h
 
 %changelog
+* Fri Jun 06 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 4.0.1.2
 * Sun May 18 2014 Oleg Moskalenko <[email protected]>
   - Sync to 4.0.0.2
 * Wed May 07 2014 Oleg Moskalenko <[email protected]>

+ 2 - 1
src/apps/relay/dtls_listener.c

@@ -348,7 +348,7 @@ static int handle_udp_packet(dtls_listener_relay_server_type *server,
 
 		if (s && s->read_cb && sm->m.sm.nd.nbh) {
 			s->e = ioa_eng;
-			s->read_cb(s, IOA_EV_READ, &(sm->m.sm.nd), s->read_ctx);
+			s->read_cb(s, IOA_EV_READ, &(sm->m.sm.nd), s->read_ctx, 1);
 			ioa_network_buffer_delete(ioa_eng, sm->m.sm.nd.nbh);
 			sm->m.sm.nd.nbh = NULL;
 
@@ -604,6 +604,7 @@ static void udp_server_input_handler(evutil_socket_t fd, short what, void* arg)
 	server->sm.m.sm.nd.nbh = elem;
 	server->sm.m.sm.nd.recv_ttl = TTL_IGNORE;
 	server->sm.m.sm.nd.recv_tos = TOS_IGNORE;
+	server->sm.m.sm.can_resume = 1;
 
 	addr_set_any(&(server->sm.m.sm.nd.src_addr));
 

+ 17 - 4
src/apps/relay/mainrelay.c

@@ -92,7 +92,7 @@ LOW_DEFAULT_PORTS_BOUNDARY,HIGH_DEFAULT_PORTS_BOUNDARY,0,0,"",
 /////////////// stop server ////////////////
 0,
 /////////////// MISC PARAMS ////////////////
-0,0,0,0,0,SHATYPE_SHA1,':',0,0,TURN_CREDENTIALS_NONE,0,0,0,0,
+0,0,0,0,0,SHATYPE_SHA1,':',0,0,TURN_CREDENTIALS_NONE,0,0,0,0,0,0,
 ///////////// Users DB //////////////
 { TURN_USERDB_TYPE_FILE, {"\0",NULL}, {0,NULL,NULL, {NULL,0}} }
 
@@ -400,11 +400,14 @@ static char Usage[] = "Usage: turnserver [options]\n"
 "						This option can also be set through the database, for a particular realm.\n"
 " -Q, --total-quota		<number>	Total allocations quota: global limit on concurrent allocations.\n"
 "						This option can also be set through the database, for a particular realm.\n"
-" -s, --max-bps			<number>	Max bytes-per-second bandwidth a TURN session is allowed to handle\n"
+" -s, --max-bps			<number>	Default max bytes-per-second bandwidth a TURN session is allowed to handle\n"
 "						(input and output network streams are treated separately). Anything above\n"
 "						that limit will be dropped or temporary suppressed\n"
 "						(within the available buffer limits).\n"
 "						This option can also be set through the database, for a particular realm.\n"
+" -B, --bps-capacity		<number>	Maximum server capacity.\n"
+"						Total bytes-per-second bandwidth the TURN server is allowed to allocate\n"
+"						for the sessions, combined (input and output network streams are treated separately).\n"
 " -c				<filename>	Configuration file name (default - turnserver.conf).\n"
 " -b, --userdb			<filename>	User database file name (default - turnuserdb.conf) for long-term credentials only.\n"
 #if !defined(TURN_NO_PQ)
@@ -592,7 +595,7 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
 	"					Setting to zero value means removal of the option.\n"
 	"	-h, --help			Help\n";
 
-#define OPTIONS "c:d:p:L:E:X:i:m:l:r:u:b:e:M:N:O:q:Q:s:C:vVofhznaAS"
+#define OPTIONS "c:d:p:L:E:X:i:m:l:r:u:b:B:e:M:N:O:q:Q:s:C:vVofhznaAS"
 
 #define ADMIN_OPTIONS "gGORIHlLkaADSdb:e:M:N:u:r:p:s:X:o:h"
 
@@ -694,6 +697,7 @@ static struct option long_options[] = {
 				{ "user-quota", required_argument, NULL, 'q' },
 				{ "total-quota", required_argument, NULL, 'Q' },
 				{ "max-bps", required_argument, NULL, 's' },
+				{ "bps-capacity", required_argument, NULL, 'B' },
 				{ "verbose", optional_argument, NULL, 'v' },
 				{ "Verbose", optional_argument, NULL, 'V' },
 				{ "daemon", optional_argument, NULL, 'o' },
@@ -1103,6 +1107,10 @@ static void set_option(int c, char *value)
 		get_realm(NULL)->options.perf_options.max_bps = atoi(value);
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%lu bytes per second allowed per session\n",(unsigned long)turn_params.max_bps);
 		break;
+	case 'B':
+		turn_params.bps_capacity = (band_limit_t)atoi(value);
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%lu bytes per second allowed, combined server capacity\n",(unsigned long)turn_params.bps_capacity);
+		break;
 	case NO_UDP_OPT:
 		turn_params.no_udp = get_bool_value(value);
 		break;
@@ -1330,7 +1338,7 @@ static int adminmain(int argc, char **argv)
 	u08bits pwd[STUN_MAX_PWD_SIZE+1]="";
 	u08bits secret[AUTH_SECRET_SIZE+1]="";
 	u08bits origin[STUN_MAX_ORIGIN_SIZE+1]="";
-	perf_options_t po = {-1,-1,-1};
+	perf_options_t po = {(band_limit_t)-1,-1,-1};
 
 	while (((c = getopt_long(argc, argv, ADMIN_OPTIONS, admin_long_options, NULL)) != -1)) {
 		switch (c){
@@ -1707,6 +1715,11 @@ int main(int argc, char **argv)
 	  }
 	}
 
+	if(turn_params.bps_capacity && !(turn_params.max_bps)) {
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "\nCONFIG ERROR: If you set the --bps-capacity option, then you must set --max-bps options, too.\n");
+		exit(-1);
+	}
+
 	if(turn_params.no_udp_relay && turn_params.no_tcp_relay) {
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "\nCONFIG ERROR: --no-udp-relay and --no-tcp-relay options cannot be used together.\n");
 		exit(-1);

+ 10 - 0
src/apps/relay/mainrelay.h

@@ -299,6 +299,8 @@ typedef struct _turn_params_ {
   turn_credential_type ct;
   int use_auth_secret_with_timestamp;
   band_limit_t max_bps;
+  band_limit_t bps_capacity;
+  band_limit_t bps_capacity_allocated;
   vint total_quota;
   vint user_quota;
 
@@ -346,6 +348,14 @@ void init_listener(void);
 void setup_server(void);
 void run_listener_server(struct listener_server *ls);
 
+////////// BPS ////////////////
+
+band_limit_t get_bps_capacity_allocated(void);
+band_limit_t get_bps_capacity(void);
+void set_bps_capacity(band_limit_t value);
+band_limit_t get_max_bps(void);
+void set_max_bps(band_limit_t value);
+
 ///////////////////////////////
 
 #ifdef __cplusplus

+ 115 - 11
src/apps/relay/netengine.c

@@ -77,6 +77,88 @@ static void barrier_wait_func(const char* func, int line)
 
 #define barrier_wait() barrier_wait_func(__FUNCTION__,__LINE__)
 
+/////////////// Bandwidth //////////////////
+
+static pthread_mutex_t mutex_bps;
+
+static band_limit_t allocate_bps(band_limit_t bps, int positive)
+{
+	band_limit_t ret = 0;
+	if(bps>0) {
+		pthread_mutex_lock(&mutex_bps);
+
+		if(positive) {
+
+			if(!(turn_params.bps_capacity)) {
+				ret = bps;
+				turn_params.bps_capacity_allocated += ret;
+			} else if(turn_params.bps_capacity_allocated < turn_params.bps_capacity) {
+				band_limit_t reserve = turn_params.bps_capacity - turn_params.bps_capacity_allocated;
+				if(reserve <= bps) {
+					ret = reserve;
+					turn_params.bps_capacity_allocated = turn_params.bps_capacity;
+				} else {
+					ret = bps;
+					turn_params.bps_capacity_allocated += ret;
+				}
+			}
+
+		} else {
+
+			if(turn_params.bps_capacity_allocated >= bps) {
+				turn_params.bps_capacity_allocated -= bps;
+				ret = turn_params.bps_capacity_allocated;
+			} else {
+				turn_params.bps_capacity_allocated = 0;
+			}
+		}
+
+		pthread_mutex_unlock(&mutex_bps);
+	}
+	return ret;
+}
+
+band_limit_t get_bps_capacity_allocated(void)
+{
+	band_limit_t ret = 0;
+	pthread_mutex_lock(&mutex_bps);
+	ret = turn_params.bps_capacity_allocated;
+	pthread_mutex_unlock(&mutex_bps);
+	return ret;
+}
+
+band_limit_t get_bps_capacity(void)
+{
+	band_limit_t ret = 0;
+	pthread_mutex_lock(&mutex_bps);
+	ret = turn_params.bps_capacity;
+	pthread_mutex_unlock(&mutex_bps);
+	return ret;
+}
+
+void set_bps_capacity(band_limit_t value)
+{
+	pthread_mutex_lock(&mutex_bps);
+	turn_params.bps_capacity = value;
+	pthread_mutex_unlock(&mutex_bps);
+}
+
+band_limit_t get_max_bps(void)
+{
+	band_limit_t ret = 0;
+	pthread_mutex_lock(&mutex_bps);
+	ret = turn_params.max_bps;
+	pthread_mutex_unlock(&mutex_bps);
+	return ret;
+}
+
+void set_max_bps(band_limit_t value)
+{
+	pthread_mutex_lock(&mutex_bps);
+	turn_params.max_bps = value;
+	pthread_mutex_unlock(&mutex_bps);
+}
+
 /////////////// AUX SERVERS ////////////////
 
 static void add_aux_server_list(const char *saddr, turn_server_addrs_list_t *list)
@@ -390,7 +472,8 @@ static int send_socket_to_general_relay(ioa_engine_handle e, struct message_to_r
 }
 
 static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, ioa_socket_handle s, 
-				int message_integrity, MESSAGE_TO_RELAY_TYPE rmt, ioa_net_data *nd)
+				int message_integrity, MESSAGE_TO_RELAY_TYPE rmt, ioa_net_data *nd,
+				int can_resume)
 {
 	int ret = 0;
 
@@ -426,11 +509,21 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
 	switch (rmt) {
 	case(RMT_CB_SOCKET): {
 
-		sm.m.cb_sm.id = id;
-		sm.m.cb_sm.connection_id = (tcp_connection_id)cid;
-		stun_tid_cpy(&(sm.m.cb_sm.tid),tid);
-		sm.m.cb_sm.s = s;
-		sm.m.cb_sm.message_integrity = message_integrity;
+		if(nd && nd->nbh) {
+			sm.m.cb_sm.id = id;
+			sm.m.cb_sm.connection_id = (tcp_connection_id)cid;
+			stun_tid_cpy(&(sm.m.cb_sm.tid),tid);
+			sm.m.cb_sm.s = s;
+			sm.m.cb_sm.message_integrity = message_integrity;
+
+			addr_cpy(&(sm.m.cb_sm.nd.src_addr),&(nd->src_addr));
+			sm.m.cb_sm.nd.recv_tos = nd->recv_tos;
+			sm.m.cb_sm.nd.recv_ttl = nd->recv_ttl;
+			sm.m.cb_sm.nd.nbh = nd->nbh;
+			sm.m.cb_sm.can_resume = can_resume;
+
+			nd->nbh = NULL;
+		}
 
 		break;
 	}
@@ -442,6 +535,7 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
 			sm.m.sm.nd.recv_tos = nd->recv_tos;
 			sm.m.sm.nd.recv_ttl = nd->recv_ttl;
 			sm.m.sm.nd.nbh = nd->nbh;
+			sm.m.sm.can_resume = can_resume;
 			nd->nbh = NULL;
 		} else {
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Empty buffer with mobile socket\n",__FUNCTION__);
@@ -480,6 +574,9 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
 	  if(rmt == RMT_MOBILE_SOCKET) {
 	    ioa_network_buffer_delete(NULL, sm.m.sm.nd.nbh);
 	    sm.m.sm.nd.nbh = NULL;
+	  } else if(rmt == RMT_CB_SOCKET) {
+		  ioa_network_buffer_delete(NULL, sm.m.cb_sm.nd.nbh);
+		  sm.m.cb_sm.nd.nbh = NULL;
 	  }
 	}
 
@@ -526,7 +623,11 @@ static int handle_relay_message(relay_server_handle rs, struct message_to_relay
 		case RMT_CB_SOCKET:
 
 			turnserver_accept_tcp_client_data_connection(&(rs->server), sm->m.cb_sm.connection_id,
-				&(sm->m.cb_sm.tid), sm->m.cb_sm.s, sm->m.cb_sm.message_integrity);
+				&(sm->m.cb_sm.tid), sm->m.cb_sm.s, sm->m.cb_sm.message_integrity, &(sm->m.cb_sm.nd),
+				sm->m.cb_sm.can_resume);
+
+			ioa_network_buffer_delete(rs->ioa_eng, sm->m.cb_sm.nd.nbh);
+			sm->m.cb_sm.nd.nbh = NULL;
 
 			break;
 		case RMT_MOBILE_SOCKET: {
@@ -709,7 +810,7 @@ static ioa_engine_handle create_new_listener_engine(void)
 	TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"IO method (udp listener/relay thread): %s\n",event_base_get_method(eb));
 	super_memory_t* sm = new_super_memory_region();
 	ioa_engine_handle e = create_ioa_engine(sm, eb, turn_params.listener.tp, turn_params.relay_ifname, turn_params.relays_number, turn_params.relay_addrs,
-			turn_params.default_relays, turn_params.verbose, turn_params.max_bps
+			turn_params.default_relays, turn_params.verbose
 #if !defined(TURN_NO_HIREDIS)
 			,turn_params.redis_statsdb
 #endif
@@ -755,7 +856,7 @@ static void setup_listener(void)
 
 	turn_params.listener.ioa_eng = create_ioa_engine(sm, turn_params.listener.event_base, turn_params.listener.tp,
 			turn_params.relay_ifname, turn_params.relays_number, turn_params.relay_addrs,
-			turn_params.default_relays, turn_params.verbose, turn_params.max_bps
+			turn_params.default_relays, turn_params.verbose
 #if !defined(TURN_NO_HIREDIS)
 			,turn_params.redis_statsdb
 #endif
@@ -1329,7 +1430,7 @@ static void setup_relay_server(struct relay_server *rs, ioa_engine_handle e, int
 		rs->event_base = turn_event_base_new();
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"IO method (general relay thread): %s\n",event_base_get_method(rs->event_base));
 		rs->ioa_eng = create_ioa_engine(rs->sm, rs->event_base, turn_params.listener.tp, turn_params.relay_ifname,
-			turn_params.relays_number, turn_params.relay_addrs, turn_params.default_relays, turn_params.verbose, turn_params.max_bps
+			turn_params.relays_number, turn_params.relay_addrs, turn_params.default_relays, turn_params.verbose
 #if !defined(TURN_NO_HIREDIS)
 			,turn_params.redis_statsdb
 #endif
@@ -1381,7 +1482,8 @@ static void setup_relay_server(struct relay_server *rs, ioa_engine_handle e, int
 			 send_socket_to_relay,
 			 &turn_params.secure_stun, turn_params.shatype, &turn_params.mobility,
 			 turn_params.server_relay,
-			 send_turn_session_info);
+			 send_turn_session_info,
+			 allocate_bps);
 	
 	if(to_set_rfc5780) {
 		set_rfc5780(&(rs->server), get_alt_addr, send_message_from_listener_to_client);
@@ -1526,6 +1628,8 @@ void setup_server(void)
 {
 	evthread_use_pthreads();
 
+	pthread_mutex_init(&mutex_bps, NULL);
+
 #if !defined(TURN_NO_THREAD_BARRIERS)
 
 	/* relay threads plus auth thread plus main listener thread */

+ 12 - 12
src/apps/relay/ns_ioalib_engine_impl.c

@@ -108,11 +108,13 @@ static int bufferevent_enabled(struct bufferevent *bufev, short flags)
 
 static int is_socket_writeable(ioa_socket_handle s, size_t sz, const char *msg, int option) 
 {
-  UNUSED_ARG(s);
   UNUSED_ARG(sz);
   UNUSED_ARG(msg);
   UNUSED_ARG(option);
 
+  if(!s)
+	  return 0;
+
   if(!(s->done) && !(s->broken) && !(s->tobeclosed)) {
 
     switch(s->st) {
@@ -335,7 +337,7 @@ static void timer_handler(ioa_engine_handle e, void* arg) {
 ioa_engine_handle create_ioa_engine(super_memory_t *sm,
 				struct event_base *eb, turnipports *tp, const s08bits* relay_ifname,
 				size_t relays_number, s08bits **relay_addrs, int default_relays,
-				int verbose, band_limit_t max_bps
+				int verbose
 #if !defined(TURN_NO_HIREDIS)
 				,const char* redis_report_connection_string
 #endif
@@ -370,7 +372,6 @@ ioa_engine_handle create_ioa_engine(super_memory_t *sm,
 
 		e->sm = sm;
 		e->default_relays = default_relays;
-		e->max_bpj = max_bps;
 		e->verbose = verbose;
 		e->tp = tp;
 		if (eb) {
@@ -625,12 +626,11 @@ void delete_ioa_timer(ioa_timer_handle th)
 
 static int ioa_socket_check_bandwidth(ioa_socket_handle s, size_t sz, int read)
 {
-	if(s && (s->e) && sz && (s->sat == CLIENT_SOCKET) && (s->session)) {
+	if(read && s && (s->e) && sz &&
+			((s->sat == CLIENT_SOCKET) || (s->sat == RELAY_SOCKET) || (s->sat == RELAY_RTCP_SOCKET)) &&
+			(s->session)) {
 
-		band_limit_t max_bps = s->e->max_bpj;
-		band_limit_t s_max_bps = s->session->realm_options.perf_options.max_bps;
-		if(s_max_bps>0)
-			max_bps = s_max_bps;
+		band_limit_t max_bps = s->session->bps;
 
 		if(max_bps<1)
 			return 1;
@@ -2275,13 +2275,13 @@ static int socket_input_worker(ioa_socket_handle s)
 		addr_cpy(&remote_addr,&(s->remote_addr));
 
 	if(tcp_congestion_control && s->sub_session && s->bev) {
-	  if(s == s->sub_session->client_s) {
+	  if(s == s->sub_session->client_s && (s->sub_session->peer_s)) {
 	    if(!is_socket_writeable(s->sub_session->peer_s, STUN_BUFFER_SIZE,__FUNCTION__,0)) {
 	      if(bufferevent_enabled(s->bev,EV_READ)) {
 	    	  bufferevent_disable(s->bev,EV_READ);
 	      }
 	    }
-	  } else if(s == s->sub_session->peer_s) {
+	  } else if(s == s->sub_session->peer_s && (s->sub_session->client_s)) {
 	    if(!is_socket_writeable(s->sub_session->client_s, STUN_BUFFER_SIZE,__FUNCTION__,1)) {
 	      if(bufferevent_enabled(s->bev,EV_READ)) {
 	    	  bufferevent_disable(s->bev,EV_READ);
@@ -2486,7 +2486,7 @@ static int socket_input_worker(ioa_socket_handle s)
 				nd.recv_ttl = ttl;
 				nd.recv_tos = tos;
 
-				s->read_cb(s, IOA_EV_READ, &nd, s->read_ctx);
+				s->read_cb(s, IOA_EV_READ, &nd, s->read_ctx, 1);
 
 				if(nd.nbh)
 					free_blist_elem(s->e,buf_elem);
@@ -3432,7 +3432,7 @@ void turn_report_allocation_set(void *a, turn_time_t lifetime, int refresh)
 			turn_turnserver *server = (turn_turnserver*)ss->server;
 			if(server) {
 				ioa_engine_handle e = turn_server_get_engine(server);
-				if(e && e->verbose) {
+				if(e && e->verbose && ss->client_session.s) {
 					if(ss->client_session.s->ssl) {
 						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"session %018llu: %s, realm=<%s>, username=<%s>, lifetime=%lu, cipher=%s, method=%s (%s)\n", (unsigned long long)ss->id, status, (char*)ss->realm_options.name, (char*)ss->username, (unsigned long)lifetime, SSL_get_cipher(ss->client_session.s->ssl),
 							turn_get_ssl_method(ss->client_session.s->ssl, ss->client_session.s->orig_ctx_type),ss->client_session.s->orig_ctx_type);

+ 3 - 4
src/apps/relay/ns_ioalib_impl.h

@@ -80,8 +80,6 @@ typedef struct _stun_buffer_list {
 	size_t tsz;
 } stun_buffer_list;
 
-typedef vint band_limit_t;
-
 /*
  * New connection callback
  */
@@ -92,6 +90,8 @@ struct cb_socket_message {
 	stun_tid tid;
 	ioa_socket_handle s;
 	int message_integrity;
+	ioa_net_data nd;
+	int can_resume;
 };
 
 struct relay_server {
@@ -146,7 +146,6 @@ struct _ioa_engine
 #endif
   SSL_CTX *dtls_ctx;
   turn_time_t jiffie; /* bandwidth check interval */
-  band_limit_t max_bpj;
   ioa_timer_handle timer_ev;
   s08bits cmsg[TURN_CMSG_SZ+1];
   int predef_timer_intervals[PREDEF_TIMERS_NUM];
@@ -240,7 +239,7 @@ ioa_engine_handle create_ioa_engine(super_memory_t *sm,
 				struct event_base *eb, turnipports* tp,
 				const s08bits* relay_if,
 				size_t relays_number, s08bits **relay_addrs, int default_relays,
-				int verbose, band_limit_t max_bps
+				int verbose
 #if !defined(TURN_NO_HIREDIS)
 				,const char* redis_report_connection_string
 #endif

+ 1 - 0
src/apps/relay/tls_listener.c

@@ -104,6 +104,7 @@ static void server_input_handler(struct evconnlistener *l, evutil_socket_t fd,
 		server->sm.m.sm.nd.recv_tos = TOS_IGNORE;
 		server->sm.m.sm.nd.nbh = NULL;
 		server->sm.m.sm.s = ioas;
+		server->sm.m.sm.can_resume = 1;
 		server->sm.relay_server = server->relay_server;
 
 		int rc = server->connect_cb(server->e, &(server->sm));

+ 27 - 7
src/apps/relay/turncli.c

@@ -350,12 +350,20 @@ static void change_cli_param(struct cli_session* cs, const char* pn)
 	if(cs && cs->ts && pn) {
 
 		if(strstr(pn,"total-quota")==pn) {
-			int new_quota = change_total_quota(cs->realm, atoi(pn+strlen("total-quota")));
-			cli_print_uint(cs,(unsigned long)new_quota,"total-quota",2);
+			turn_params.total_quota = atoi(pn+strlen("total-quota"));
+			cli_print_uint(cs,(unsigned long)turn_params.total_quota,"total-quota",2);
 			return;
 		} else if(strstr(pn,"user-quota")==pn) {
-			int new_quota = change_user_quota(cs->realm, atoi(pn+strlen("user-quota")));
-			cli_print_uint(cs,(unsigned long)new_quota,"user-quota",2);
+			turn_params.user_quota = atoi(pn+strlen("user-quota"));
+			cli_print_uint(cs,(unsigned long)turn_params.user_quota,"user-quota",2);
+			return;
+		} else if(strstr(pn,"max-bps")==pn) {
+			set_max_bps((band_limit_t)atol(pn+strlen("max-bps")));
+			cli_print_uint(cs,(unsigned long)get_max_bps(),"max-bps",2);
+			return;
+		} else if(strstr(pn,"bps-capacity")==pn) {
+			set_bps_capacity((band_limit_t)atol(pn+strlen("bps-capacity")));
+			cli_print_uint(cs,(unsigned long)get_bps_capacity(),"bps-capacity",2);
 			return;
 		} else if(strstr(pn,"cli-max-output-sessions")==pn) {
 			cli_max_output_sessions = atoi(pn+strlen("cli-max-output-sessions"));
@@ -498,6 +506,8 @@ static int print_session(ur_map_key_type key, ur_map_value_type value, void *arg
 					myprintf(cs,"      TLS method: %s\n",tsi->tls_method);
 					myprintf(cs,"      TLS cipher: %s\n",tsi->tls_cipher);
 				}
+				if(tsi->bps)
+					myprintf(cs,"      Max throughput: %lu bytes per second\n",(unsigned long)tsi->bps);
 				myprintf(cs,"      usage: rp=%lu, rb=%lu, sp=%lu, sb=%lu\n",(unsigned long)(tsi->received_packets), (unsigned long)(tsi->received_bytes),(unsigned long)(tsi->sent_packets),(unsigned long)(tsi->sent_bytes));
 				myprintf(cs,"       rate: r=%lu, s=%lu, total=%lu (bytes per sec)\n",(unsigned long)(tsi->received_rate), (unsigned long)(tsi->sent_rate),(unsigned long)(tsi->total_rate));
 				if(tsi->main_peers_size) {
@@ -785,9 +795,19 @@ static void cli_print_configuration(struct cli_session* cs)
 
 		cli_print_uint(cs,(unsigned long)cs->rp->status.total_current_allocs,"total-current-allocs",0);
 
-		cli_print_uint(cs,(unsigned long)cs->rp->options.perf_options.total_quota,"total-quota",2);
-		cli_print_uint(cs,(unsigned long)cs->rp->options.perf_options.user_quota,"user-quota",2);
-		cli_print_uint(cs,(unsigned long)cs->rp->options.perf_options.max_bps,"max-bps",0);
+		myprintf(cs,"\n");
+
+		cli_print_uint(cs,(unsigned long)turn_params.total_quota,"Default total-quota",2);
+		cli_print_uint(cs,(unsigned long)turn_params.user_quota,"Default user-quota",2);
+		cli_print_uint(cs,(unsigned long)get_bps_capacity(),"Total server bps-capacity",2);
+		cli_print_uint(cs,(unsigned long)get_bps_capacity_allocated(),"Allocated bps-capacity",0);
+		cli_print_uint(cs,(unsigned long)get_max_bps(),"Default max-bps",2);
+
+		myprintf(cs,"\n");
+
+		cli_print_uint(cs,(unsigned long)cs->rp->options.perf_options.total_quota,"current realm total-quota",0);
+		cli_print_uint(cs,(unsigned long)cs->rp->options.perf_options.user_quota,"current realm user-quota",0);
+		cli_print_uint(cs,(unsigned long)cs->rp->options.perf_options.max_bps,"current realm max-bps",0);
 
 		myprintf(cs,"\n");
 

+ 29 - 16
src/apps/relay/userdb.c

@@ -2343,12 +2343,12 @@ static int list_origins(u08bits *realm)
 	return 0;
 }
 
-static int set_realm_option_one(u08bits *realm, vint value, const char* opt)
+static int set_realm_option_one(u08bits *realm, unsigned long value, const char* opt)
 {
 	UNUSED_ARG(realm);
 	UNUSED_ARG(value);
 	UNUSED_ARG(opt);
-	if(value<0)
+	if(value == (unsigned long)-1)
 		return 0;
 #if !defined(TURN_NO_PQ)
 	if(is_pqsql_userdb()) {
@@ -2363,7 +2363,7 @@ static int set_realm_option_one(u08bits *realm, vint value, const char* opt)
 				}
 			}
 			if(value>0) {
-				snprintf(statement,sizeof(statement),"insert into turn_realm_option (realm,opt,value) values('%s','%s','%d')",realm,opt,(int)value);
+				snprintf(statement,sizeof(statement),"insert into turn_realm_option (realm,opt,value) values('%s','%s','%lu')",realm,opt,(unsigned long)value);
 				PGresult *res = PQexec(pqc, statement);
 				if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
 					TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting realm option information: %s\n",PQerrorMessage(pqc));
@@ -2386,7 +2386,7 @@ static int set_realm_option_one(u08bits *realm, vint value, const char* opt)
 				mysql_query(myc, statement);
 			}
 			if(value>0) {
-				snprintf(statement,sizeof(statement),"insert into turn_realm_option (realm,opt,value) values('%s','%s','%d')",realm,opt,(int)value);
+				snprintf(statement,sizeof(statement),"insert into turn_realm_option (realm,opt,value) values('%s','%s','%lu')",realm,opt,(unsigned long)value);
 				int res = mysql_query(myc, statement);
 				if (res) {
 					TURN_LOG_FUNC(
@@ -2406,7 +2406,7 @@ static int set_realm_option_one(u08bits *realm, vint value, const char* opt)
 			char s[LONG_STRING_SIZE];
 
 			if(value>0)
-				snprintf(s,sizeof(s),"set turn/realm/%s/%s %d", (char*)realm, opt, (int)value);
+				snprintf(s,sizeof(s),"set turn/realm/%s/%s %lu", (char*)realm, opt, (unsigned long)value);
 			else
 				snprintf(s,sizeof(s),"del turn/realm/%s/%s", (char*)realm, opt);
 
@@ -2420,9 +2420,9 @@ static int set_realm_option_one(u08bits *realm, vint value, const char* opt)
 
 static int set_realm_option(u08bits *realm, perf_options_t *po)
 {
-	set_realm_option_one(realm,po->max_bps,"max-bps");
-	set_realm_option_one(realm,po->user_quota,"user-quota");
-	set_realm_option_one(realm,po->total_quota,"total-quota");
+	set_realm_option_one(realm,(unsigned long)po->max_bps,"max-bps");
+	set_realm_option_one(realm,(unsigned long)po->user_quota,"user-quota");
+	set_realm_option_one(realm,(unsigned long)po->total_quota,"total-quota");
 	return 0;
 }
 
@@ -2612,7 +2612,7 @@ int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08b
 
 	if(ct == TA_SET_REALM_OPTION) {
 		must_set_admin_realm(realm);
-		if(!(po && (po->max_bps>=0 || po->total_quota>=0 || po->user_quota>=0))) {
+		if(!(po && (po->max_bps!=((band_limit_t)-1) || po->total_quota>=0 || po->user_quota>=0))) {
 			fprintf(stderr, "The operation cannot be completed: a realm option must be set.\n");
 			exit(-1);
 		}
@@ -3246,7 +3246,7 @@ int add_ip_list_range(char* range, ip_range_list_t * list)
 /////////// REALM //////////////
 
 #if !defined(TURN_NO_HIREDIS)
-static int set_redis_realm_opt(char *realm, const char* key, vint *value)
+static int set_redis_realm_opt(char *realm, const char* key, unsigned long *value)
 {
 	int found = 0;
 
@@ -3268,7 +3268,7 @@ static int set_redis_realm_opt(char *realm, const char* key, vint *value)
 					TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unexpected type: %d\n", rget->type);
 			} else {
 				ur_string_map_lock(realms);
-				*value = atoi(rget->str);
+				*value = (unsigned long)atol(rget->str);
 				ur_string_map_unlock(realms);
 				found = 1;
 			}
@@ -3282,6 +3282,15 @@ static int set_redis_realm_opt(char *realm, const char* key, vint *value)
 
 void reread_realms(void)
 {
+	{
+		realm_params_t* defrp = get_realm(NULL);
+		ur_string_map_lock(realms);
+		defrp->options.perf_options.max_bps = turn_params.max_bps;
+		defrp->options.perf_options.total_quota = turn_params.total_quota;
+		defrp->options.perf_options.user_quota = turn_params.user_quota;
+		ur_string_map_unlock(realms);
+	}
+
 #if !defined(TURN_NO_PQ)
 	PGconn * pqc = get_pqdb_connection();
 	if(pqc) {
@@ -3362,7 +3371,7 @@ void reread_realms(void)
 					if(rval && oval && vval) {
 						realm_params_t* rp = get_realm(rval);
 						if(!strcmp(oval,"max-bps"))
-							rp->options.perf_options.max_bps = (vint)atoi(vval);
+							rp->options.perf_options.max_bps = (band_limit_t)atol(vval);
 						else if(!strcmp(oval,"total-quota"))
 							rp->options.perf_options.total_quota = (vint)atoi(vval);
 						else if(!strcmp(oval,"user-quota"))
@@ -3482,7 +3491,7 @@ void reread_realms(void)
 								vval[sz]=0;
 								realm_params_t* rp = get_realm(rval);
 								if(!strcmp(oval,"max-bps"))
-									rp->options.perf_options.max_bps = (vint)atoi(vval);
+									rp->options.perf_options.max_bps = (band_limit_t)atol(vval);
 								else if(!strcmp(oval,"total-quota"))
 									rp->options.perf_options.total_quota = (vint)atoi(vval);
 								else if(!strcmp(oval,"user-quota"))
@@ -3574,21 +3583,25 @@ void reread_realms(void)
 				for (i = 0; i<rlsz; ++i) {
 					char *realm = realms_list.secrets[i];
 					realm_params_t* rp = get_realm(realm);
-					if(!set_redis_realm_opt(realm,"max-bps",&(rp->options.perf_options.max_bps))) {
+					unsigned long value = 0;
+					if(!set_redis_realm_opt(realm,"max-bps",&value)) {
 						ur_string_map_lock(realms);
 						rp->options.perf_options.max_bps = turn_params.max_bps;
 						ur_string_map_unlock(realms);
 					}
-					if(!set_redis_realm_opt(realm,"total-quota",&(rp->options.perf_options.total_quota))) {
+					rp->options.perf_options.max_bps = (band_limit_t)value;
+					if(!set_redis_realm_opt(realm,"total-quota",&value)) {
 						ur_string_map_lock(realms);
 						rp->options.perf_options.total_quota = turn_params.total_quota;
 						ur_string_map_unlock(realms);
 					}
-					if(!set_redis_realm_opt(realm,"user-quota",&(rp->options.perf_options.user_quota))) {
+					rp->options.perf_options.total_quota = (vint)value;
+					if(!set_redis_realm_opt(realm,"user-quota",&value)) {
 						ur_string_map_lock(realms);
 						rp->options.perf_options.user_quota = turn_params.user_quota;
 						ur_string_map_unlock(realms);
 					}
+					rp->options.perf_options.user_quota = (vint)value;
 				}
 			}
 		}

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

@@ -93,6 +93,8 @@ int extra_requests = 0;
 
 char origin[STUN_MAX_ORIGIN_SIZE+1] = "\0";
 
+band_limit_t bps = 0;
+
 //////////////// local definitions /////////////////
 
 static char Usage[] =
@@ -145,7 +147,8 @@ static char Usage[] =
   "	-W	TURN REST API authentication secret. Is not compatible with -A option.\n"
   "	-C	TURN REST API timestamp/username separator symbol (character). The default value is ':'.\n"
   "	-F	<cipher-suite> Cipher suite for TLS/DTLS. Default value is DEFAULT.\n"
-  "	-o	<origin> - the ORIGIN STUN attribute value.\n";
+  "	-o	<origin> - the ORIGIN STUN attribute value.\n"
+  "	-a	<bytes-per-second> Bandwidth for the bandwidth request in ALLOCATE. The default value is zero.\n";
 
 //////////////////////////////////////////////////
 
@@ -198,8 +201,11 @@ int main(int argc, char **argv)
 
 	ns_bzero(local_addr, sizeof(local_addr));
 
-	while ((c = getopt(argc, argv, "d:p:l:n:L:m:e:r:u:w:i:k:z:W:C:E:F:o:vsyhcxXgtTSAPDNOUHMRIGB")) != -1) {
+	while ((c = getopt(argc, argv, "a:d:p:l:n:L:m:e:r:u:w:i:k:z:W:C:E:F:o:vsyhcxXgtTSAPDNOUHMRIGB")) != -1) {
 		switch (c){
+		case 'a':
+			bps = (band_limit_t)atol(optarg);
+			break;
 		case 'o':
 			STRCPY(origin,optarg);
 			break;

+ 4 - 0
src/apps/uclient/startuclient.c

@@ -339,6 +339,10 @@ static int clnet_allocate(int verbose,
 			stun_set_allocate_request(&message, 800, af, relay_transport, mobility);
 		else
 			stun_set_allocate_request(&message, 300, af, relay_transport, mobility);
+
+		if(bps)
+			stun_attr_add_bandwidth_str(message.buf, (size_t*)(&(message.len)), bps);
+
 		if(dont_fragment)
 			stun_attr_add(&message, STUN_ATTRIBUTE_DONT_FRAGMENT, NULL, 0);
 		if(!no_rtcp) {

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

@@ -81,6 +81,7 @@ extern SHATYPE shatype;
 extern int mobility;
 extern int no_permissions;
 extern int extra_requests;
+extern band_limit_t bps;
 
 extern char origin[STUN_MAX_ORIGIN_SIZE+1];
 

+ 20 - 0
src/client/ns_turn_msg.c

@@ -944,6 +944,17 @@ u16bits stun_attr_get_channel_number(stun_attr_ref attr) {
   return 0;
 }
 
+band_limit_t stun_attr_get_bandwidth(stun_attr_ref attr) {
+  if(attr) {
+    const u08bits* value = stun_attr_get_value(attr);
+    if(value && (stun_attr_get_len(attr) >= 4)) {
+      u32bits bps=nswap32(((const u32bits*)value)[0]);
+      return (band_limit_t)(bps << 7);
+    }
+  }
+  return 0;
+}
+
 u64bits stun_attr_get_reservation_token_value(stun_attr_ref attr)  {
   if(attr) {
     const u08bits* value = stun_attr_get_value(attr);
@@ -1150,6 +1161,15 @@ int stun_attr_add_channel_number_str(u08bits* buf, size_t *len, u16bits chnumber
   return stun_attr_add_str(buf,len,STUN_ATTRIBUTE_CHANNEL_NUMBER,(u08bits*)(field),sizeof(field));
 }
 
+int stun_attr_add_bandwidth_str(u08bits* buf, size_t *len, band_limit_t bps0) {
+
+	u32bits bps = (band_limit_t)(bps0 >> 7);
+
+	u32bits field=nswap32(bps);
+
+	return stun_attr_add_str(buf,len,STUN_ATTRIBUTE_NEW_BANDWIDTH,(u08bits*)(&field),sizeof(field));
+}
+
 u16bits stun_attr_get_first_channel_number_str(const u08bits *buf, size_t len) {
 
   stun_attr_ref attr=stun_attr_get_first_str(buf,len);

+ 3 - 0
src/client/ns_turn_msg.h

@@ -68,6 +68,7 @@ typedef u08bits hmackey_t[64];
  */
 #define SHORT_TERM_PASSWORD_SIZE (512)
 typedef u08bits st_password_t[SHORT_TERM_PASSWORD_SIZE+1];
+typedef unsigned int band_limit_t;
 
 ///////////////////////////////////
 
@@ -140,6 +141,7 @@ int stun_attr_get_type(stun_attr_ref attr);
 int stun_attr_get_len(stun_attr_ref attr);
 const u08bits* stun_attr_get_value(stun_attr_ref attr);
 u16bits stun_attr_get_channel_number(stun_attr_ref attr);
+band_limit_t stun_attr_get_bandwidth(stun_attr_ref attr);
 u08bits stun_attr_get_even_port(stun_attr_ref attr);
 u64bits stun_attr_get_reservation_token_value(stun_attr_ref attr);
 stun_attr_ref stun_attr_get_first_by_type_str(const u08bits* buf, size_t len, u16bits attr_type);
@@ -150,6 +152,7 @@ int stun_attr_add_addr_str(u08bits *buf, size_t *len, u16bits attr_type, const i
 int stun_attr_get_addr_str(const u08bits *buf, size_t len, stun_attr_ref attr, ioa_addr* ca, const ioa_addr *default_addr);
 int stun_attr_get_first_addr_str(const u08bits *buf, size_t len, u16bits attr_type, ioa_addr* ca, const ioa_addr *default_addr);
 int stun_attr_add_channel_number_str(u08bits* buf, size_t *len, u16bits chnumber);
+int stun_attr_add_bandwidth_str(u08bits* buf, size_t *len, band_limit_t bps);
 u16bits stun_attr_get_first_channel_number_str(const u08bits *buf, size_t len);
 
 int stun_set_allocate_request_str(u08bits* buf, size_t *len, u32bits lifetime, int address_family, u08bits transport, int mobile);

+ 6 - 0
src/client/ns_turn_msg_defs_new.h

@@ -58,4 +58,10 @@ typedef enum _SHATYPE SHATYPE;
 
 /* <<== SHA AGILITY */
 
+/* Bandwidth */
+
+#define STUN_ATTRIBUTE_NEW_BANDWIDTH (0x8000 + STUN_ATTRIBUTE_BANDWIDTH)
+
+/* <<== Bandwidth */
+
 #endif //__LIB_TURN_MSG_DEFS_NEW__

+ 2 - 2
src/ns_turn_defs.h

@@ -31,8 +31,8 @@
 #ifndef __IOADEFS__
 #define __IOADEFS__
 
-#define TURN_SERVER_VERSION "4.0.0.2"
-#define TURN_SERVER_VERSION_NAME "Threetrees"
+#define TURN_SERVER_VERSION "4.0.1.2"
+#define TURN_SERVER_VERSION_NAME "Severard"
 #define TURN_SOFTWARE "Coturn-"TURN_SERVER_VERSION" '"TURN_SERVER_VERSION_NAME"'"
 
 #if (defined(__unix__) || defined(unix)) && !defined(USG)

+ 11 - 0
src/server/ns_turn_allocation.c

@@ -602,6 +602,17 @@ tcp_connection *get_and_clean_tcp_connection_by_id(ur_map *map, tcp_connection_i
 	return NULL;
 }
 
+tcp_connection *get_tcp_connection_by_id(ur_map *map, tcp_connection_id id)
+{
+	if(map) {
+		ur_map_value_type t = 0;
+		if (ur_map_get(map, (ur_map_key_type)id, &t) && t) {
+			return (tcp_connection*)t;
+		}
+	}
+	return NULL;
+}
+
 tcp_connection *get_tcp_connection_by_peer(allocation *a, ioa_addr *peer_addr)
 {
 	if(a && peer_addr) {

+ 1 - 0
src/server/ns_turn_allocation.h

@@ -217,6 +217,7 @@ ts_ur_session *get_relay_session(allocation *a);
 ioa_socket_handle get_relay_socket(allocation *a);
 
 tcp_connection *get_and_clean_tcp_connection_by_id(ur_map *map, tcp_connection_id id);
+tcp_connection *get_tcp_connection_by_id(ur_map *map, tcp_connection_id id);
 tcp_connection *get_tcp_connection_by_peer(allocation *a, ioa_addr *peer_addr);
 int can_accept_tcp_connection_from_peer(allocation *a, ioa_addr *peer_addr, int server_relay);
 tcp_connection *create_tcp_connection(u08bits server_id, allocation *a, stun_tid *tid, ioa_addr *peer_addr, int *err_code);

+ 1 - 1
src/server/ns_turn_ioalib.h

@@ -183,7 +183,7 @@ void turn_report_session_usage(void *session);
  * the function must work correctly when chnum=0
  * (when no hint information is available).
  */
-typedef void (*ioa_net_event_handler)(ioa_socket_handle s, int event_type, ioa_net_data *data, void *ctx);
+typedef void (*ioa_net_event_handler)(ioa_socket_handle s, int event_type, ioa_net_data *data, void *ctx, int can_resume);
 
 /*
  * Timer callback

+ 126 - 55
src/server/ns_turn_server.c

@@ -47,6 +47,35 @@
 int TURN_MAX_ALLOCATE_TIMEOUT = 60;
 int TURN_MAX_ALLOCATE_TIMEOUT_STUN_ONLY = 3;
 
+static inline void log_method(ts_ur_super_session* ss, const char *method, int err_code, const u08bits *reason)
+{
+  if(ss) {
+	  if(!method) method = "unknown";
+	  if(!err_code) {
+		  if(ss->origin[0]) {
+			  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+					"session %018llu: origin <%s> realm <%s> user <%s>: incoming packet %s processed, success\n",
+					(unsigned long long)(ss->id), (const char*)(ss->origin),(const char*)(ss->realm_options.name),(const char*)(ss->username),method);
+		} else {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+				"session %018llu: realm <%s> user <%s>: incoming packet %s processed, success\n",
+				(unsigned long long)(ss->id), (const char*)(ss->realm_options.name),(const char*)(ss->username),method);
+		}
+	  } else {
+		  if(!reason) reason=(const u08bits*)"Unknown error";
+		  if(ss->origin[0]) {
+			  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+					  "session %018llu: origin <%s> realm <%s> user <%s>: incoming packet %s processed, error %d: %s\n",
+					  (unsigned long long)(ss->id), (const char*)(ss->origin),(const char*)(ss->realm_options.name),(const char*)(ss->username), method, err_code, reason);
+		  } else {
+			  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+					  "session %018llu: realm <%s> user <%s>: incoming packet %s processed, error %d: %s\n",
+					  (unsigned long long)(ss->id), (const char*)(ss->realm_options.name),(const char*)(ss->username), method, err_code, reason);
+		  }
+	  }
+  }
+}
+
 ///////////////////////////////////////////
 
 static int attach_socket_to_session(turn_turnserver* server, ioa_socket_handle s, ts_ur_super_session* ss);
@@ -132,6 +161,13 @@ static void dec_quota(ts_ur_super_session* ss)
 
 		ss->quota_used = 0;
 
+		if(ss->bps) {
+			if(((turn_turnserver*)ss->server)->allocate_bps_func) {
+				((turn_turnserver*)ss->server)->allocate_bps_func(ss->bps,0);
+			}
+			ss->bps = 0;
+		}
+
 		(((turn_turnserver*)ss->server)->raqcb)(ss->username, (u08bits*)ss->realm_options.name);
 	}
 }
@@ -361,6 +397,7 @@ int turn_session_info_copy_from(struct turn_session_info* tsi, ts_ur_super_sessi
 
 	if(tsi && ss) {
 		tsi->id = ss->id;
+		tsi->bps = ss->bps;
 		tsi->start_time = ss->start_time;
 		tsi->valid = is_allocation_valid(&(ss->alloc)) && !(ss->to_be_closed) && (ss->quota_used);
 		if(tsi->valid) {
@@ -860,6 +897,8 @@ static int handle_turn_allocate(turn_turnserver *server,
 		int af = STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_DEFAULT;
 		u08bits username[STUN_MAX_USERNAME_SIZE+1]="\0";
 		size_t ulen = 0;
+		band_limit_t bps = 0;
+		band_limit_t max_bps = 0;
 
 		stun_attr_ref sar = stun_attr_get_first_str(ioa_network_buffer_data(in_buffer->nbh), 
 							    ioa_network_buffer_get_size(in_buffer->nbh));
@@ -883,6 +922,9 @@ static int handle_turn_allocate(turn_turnserver *server,
 
 			switch (attr_type) {
 			SKIP_ATTRIBUTES;
+			case STUN_ATTRIBUTE_NEW_BANDWIDTH:
+				bps = stun_attr_get_bandwidth(sar);
+				break;
 			case STUN_ATTRIBUTE_MOBILITY_TICKET:
 				if(!(*(server->mobility))) {
 					*err_code = 501;
@@ -1057,7 +1099,21 @@ static int handle_turn_allocate(turn_turnserver *server,
 
 			} else {
 
-				if (create_relay_connection(server, ss, lifetime,
+				if(server->allocate_bps_func) {
+					max_bps = ss->realm_options.perf_options.max_bps;
+					if(max_bps && (!bps || (bps && (bps>max_bps)))) {
+						bps = max_bps;
+					}
+					if(bps) {
+						ss->bps = server->allocate_bps_func(bps,1);
+						if(!(ss->bps)) {
+							*err_code = 486;
+							*reason = (const u08bits *)"Allocation Bandwidth Quota Reached";
+						}
+					}
+				}
+
+				if (*err_code || create_relay_connection(server, ss, lifetime,
 							af, transport,
 							even_port, in_reservation_token, &out_reservation_token,
 							err_code, reason,
@@ -1097,6 +1153,11 @@ static int handle_turn_allocate(turn_turnserver *server,
 									0,NULL,
 									out_reservation_token,
 									ss->s_mobile_id);
+
+						if(ss->bps) {
+							stun_attr_add_bandwidth_str(ioa_network_buffer_data(nbh), &len, ss->bps);
+						}
+
 						ioa_network_buffer_set_size(nbh,len);
 						*resp_constructed = 1;
 
@@ -1243,7 +1304,7 @@ static int handle_turn_refresh(turn_turnserver *server,
 						ioa_socket_handle new_s = detach_ioa_socket(ss->client_session.s,1);
 						if(new_s) {
 						  if(server->send_socket_to_relay(tsid, mid, tid, new_s, message_integrity, 
-										  RMT_MOBILE_SOCKET, in_buffer)<0) {
+										  RMT_MOBILE_SOCKET, in_buffer, can_resume)<0) {
 						    *err_code = 400;
 						    *reason = (const u08bits *)"Wrong mobile ticket";
 						  } else {
@@ -1471,12 +1532,13 @@ static void tcp_deliver_delayed_buffer(unsent_buffer *ub, ioa_socket_handle s, t
 	}
 }
 
-static void tcp_peer_input_handler(ioa_socket_handle s, int event_type, ioa_net_data *in_buffer, void *arg)
+static void tcp_peer_input_handler(ioa_socket_handle s, int event_type, ioa_net_data *in_buffer, void *arg, int can_resume)
 {
 	if (!(event_type & IOA_EV_READ) || !arg)
 		return;
 
 	UNUSED_ARG(s);
+	UNUSED_ARG(can_resume);
 
 	tcp_connection *tc = (tcp_connection*)arg;
 	ts_ur_super_session *ss=NULL;
@@ -1506,12 +1568,13 @@ static void tcp_peer_input_handler(ioa_socket_handle s, int event_type, ioa_net_
 	}
 }
 
-static void tcp_client_input_handler_rfc6062data(ioa_socket_handle s, int event_type, ioa_net_data *in_buffer, void *arg)
+static void tcp_client_input_handler_rfc6062data(ioa_socket_handle s, int event_type, ioa_net_data *in_buffer, void *arg, int can_resume)
 {
 	if (!(event_type & IOA_EV_READ) || !arg)
 		return;
 
 	UNUSED_ARG(s);
+	UNUSED_ARG(can_resume);
 
 	tcp_connection *tc = (tcp_connection*)arg;
 	ts_ur_super_session *ss=NULL;
@@ -1890,7 +1953,8 @@ static int handle_turn_connect(turn_turnserver *server,
 static int handle_turn_connection_bind(turn_turnserver *server,
 			       ts_ur_super_session *ss, stun_tid *tid, int *resp_constructed,
 			       int *err_code, 	const u08bits **reason, u16bits *unknown_attrs, u16bits *ua_num,
-			       ioa_net_data *in_buffer, ioa_network_buffer_handle nbh, int message_integrity) {
+			       ioa_net_data *in_buffer, ioa_network_buffer_handle nbh, int message_integrity,
+			       int can_resume) {
 
 	allocation* a = get_allocation_ss(ss);
 
@@ -1954,7 +2018,7 @@ static int handle_turn_connection_bind(turn_turnserver *server,
 				if(s) {
 					ioa_socket_handle new_s = detach_ioa_socket(s,1);
 					if(new_s) {
-					  if(server->send_socket_to_relay(sid, id, tid, new_s, message_integrity, RMT_CB_SOCKET, NULL)<0) {
+					  if(server->send_socket_to_relay(sid, id, tid, new_s, message_integrity, RMT_CB_SOCKET, in_buffer, can_resume)<0) {
 					    *err_code = 400;
 					    *reason = (const u08bits *)"Wrong connection id";
 					  }
@@ -1987,7 +2051,7 @@ static int handle_turn_connection_bind(turn_turnserver *server,
 	return 0;
 }
 
-int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_connection_id tcid, stun_tid *tid, ioa_socket_handle s, int message_integrity)
+int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_connection_id tcid, stun_tid *tid, ioa_socket_handle s, int message_integrity, ioa_net_data *in_buffer, int can_resume)
 {
 	if(!server)
 		return -1;
@@ -1998,10 +2062,13 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
 	ts_ur_super_session *ss = NULL;
 
 	int err_code = 0;
+	const u08bits *reason = NULL;
 
 	if(tcid && tid && s) {
 
-		tc = get_and_clean_tcp_connection_by_id(server->tcp_relay_connections, tcid);
+		tc = get_tcp_connection_by_id(server->tcp_relay_connections, tcid);
+		ioa_network_buffer_handle nbh = ioa_network_buffer_allocate(server->e);
+		int resp_constructed = 0;
 		if(!tc || (tc->state == TC_STATE_READY) || (tc->client_s)) {
 			err_code = 400;
 		} else {
@@ -2010,9 +2077,18 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
 				err_code = 500;
 			} else {
 				ss = (ts_ur_super_session*)(a->owner);
-				if(!check_username_hash(s,ss->username,(u08bits*)ss->realm_options.name)) {
-					err_code = 401;
-				} else {
+
+				//Check security:
+				int postpone_reply = 0;
+				check_stun_auth(server, ss, tid, &resp_constructed, &err_code, &reason, in_buffer, nbh,
+						STUN_METHOD_CONNECTION_BIND, &message_integrity, &postpone_reply, can_resume);
+
+				if(postpone_reply) {
+
+					ioa_network_buffer_delete(server->e, nbh);
+					return 0;
+
+				} else if(!err_code) {
 					tc->state = TC_STATE_READY;
 					tc->client_s = s;
 					set_ioa_socket_session(s,ss);
@@ -2028,16 +2104,19 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
 			}
 		}
 
-		ioa_network_buffer_handle nbh = ioa_network_buffer_allocate(server->e);
+		if(tc)
+			get_and_clean_tcp_connection_by_id(server->tcp_relay_connections, tcid);
 
-		if(!err_code) {
-			size_t len = ioa_network_buffer_get_size(nbh);
-			stun_init_success_response_str(STUN_METHOD_CONNECTION_BIND, ioa_network_buffer_data(nbh), &len, tid);
-			ioa_network_buffer_set_size(nbh,len);
-		} else {
-			size_t len = ioa_network_buffer_get_size(nbh);
-			stun_init_error_response_str(STUN_METHOD_CONNECTION_BIND, ioa_network_buffer_data(nbh), &len, err_code, NULL, tid);
-			ioa_network_buffer_set_size(nbh,len);
+		if(!resp_constructed) {
+			if(!err_code) {
+				size_t len = ioa_network_buffer_get_size(nbh);
+				stun_init_success_response_str(STUN_METHOD_CONNECTION_BIND, ioa_network_buffer_data(nbh), &len, tid);
+				ioa_network_buffer_set_size(nbh,len);
+			} else {
+				size_t len = ioa_network_buffer_get_size(nbh);
+				stun_init_error_response_str(STUN_METHOD_CONNECTION_BIND, ioa_network_buffer_data(nbh), &len, err_code, NULL, tid);
+				ioa_network_buffer_set_size(nbh,len);
+			}
 		}
 
 		{
@@ -2060,6 +2139,10 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
 			ioa_network_buffer_set_size(nbh, len);
 		}
 
+		if(server->verbose) {
+			log_method(ss, "CONNECTION_BIND", err_code, reason);
+		}
+
 		if(ss && !err_code) {
 			send_data_from_ioa_socket_nbh(s, NULL, nbh, TTL_IGNORE, TOS_IGNORE);
 			tcp_deliver_delayed_buffer(&(tc->ub_to_client),s,ss);
@@ -3019,6 +3102,13 @@ static int check_stun_auth(turn_turnserver *server,
 					}
 		}
 
+		if(can_resume) {
+			(server->userkeycb)(server->id, server->ct, usname, realm, resume_processing_after_username_check, in_buffer, ss->id, postpone_reply);
+			if(*postpone_reply) {
+				return 0;
+			}
+		}
+
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
 				"%s: user %s credentials are incorrect\n",
 				__FUNCTION__, (char*)usname);
@@ -3074,31 +3164,6 @@ static void set_alternate_server(turn_server_addrs_list_t *asl, const ioa_addr *
 	}
 }
 
-#define log_method(ss, method, err_code, reason) \
-{\
-  if(!(err_code)) {\
-	  if(ss->origin[0]) {\
-			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,\
-					"session %018llu: origin <%s> realm <%s> user <%s>: incoming packet " method " processed, success\n",\
-					(unsigned long long)(ss->id), (const char*)(ss->origin),(const char*)(ss->realm_options.name),(const char*)(ss->username));\
-		} else {\
-			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,\
-					"session %018llu: realm <%s> user <%s>: incoming packet " method " processed, success\n",\
-					(unsigned long long)(ss->id), (const char*)(ss->realm_options.name),(const char*)(ss->username));\
-		}\
-  } else {\
-	  if(ss->origin[0]) {\
-		  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,\
-		  "session %018llu: origin <%s> realm <%s> user <%s>: incoming packet " method " processed, error %d: %s\n",\
-		  (unsigned long long)(ss->id), (const char*)(ss->origin),(const char*)(ss->realm_options.name),(const char*)(ss->username), (err_code), (reason));\
-	  } else {\
-		  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,\
-		  "session %018llu: realm <%s> user <%s>: incoming packet " method " processed, error %d: %s\n",\
-		  (unsigned long long)(ss->id), (const char*)(ss->realm_options.name),(const char*)(ss->username), (err_code), (reason));\
-	  }\
-  }\
-}
-
 static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss, ioa_net_data *in_buffer, ioa_network_buffer_handle nbh, int *resp_constructed, int can_resume)
 {
 
@@ -3193,7 +3258,9 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss,
 			}
 
 			if(!err_code && !(*resp_constructed) && !no_response) {
-				if(!(*(server->mobility)) || (method != STUN_METHOD_REFRESH) || is_allocation_valid(get_allocation_ss(ss))) {
+				if(method == STUN_METHOD_CONNECTION_BIND) {
+					;
+				} else if(!(*(server->mobility)) || (method != STUN_METHOD_REFRESH) || is_allocation_valid(get_allocation_ss(ss))) {
 					int postpone_reply = 0;
 					check_stun_auth(server, ss, &tid, resp_constructed, &err_code, &reason, in_buffer, nbh, method, &message_integrity, &postpone_reply, can_resume);
 					if(postpone_reply)
@@ -3236,9 +3303,9 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss,
 			case STUN_METHOD_CONNECTION_BIND:
 
 				handle_turn_connection_bind(server, ss, &tid, resp_constructed, &err_code, &reason,
-								unknown_attrs, &ua_num, in_buffer, nbh, message_integrity);
+								unknown_attrs, &ua_num, in_buffer, nbh, message_integrity, can_resume);
 
-				if(server->verbose) {
+				if(server->verbose && err_code) {
 				  log_method(ss, "CONNECTION_BIND", err_code, reason);
 				}
 
@@ -3596,9 +3663,9 @@ static int write_to_peerchannel(ts_ur_super_session* ss, u16bits chnum, ioa_net_
 }
 
 static void client_input_handler(ioa_socket_handle s, int event_type,
-		ioa_net_data *data, void *arg);
+		ioa_net_data *data, void *arg, int can_resume);
 static void peer_input_handler(ioa_socket_handle s, int event_type,
-		ioa_net_data *data, void *arg);
+		ioa_net_data *data, void *arg, int can_resume);
 
 /////////////// Client actions /////////////////
 
@@ -4148,7 +4215,7 @@ int open_client_connection_session(turn_turnserver* server,
 			"client_to_be_allocated_timeout_handler");
 
 	if(sm->nd.nbh) {
-		client_input_handler(newelem->s,IOA_EV_READ,&(sm->nd),ss);
+		client_input_handler(newelem->s,IOA_EV_READ,&(sm->nd),ss,sm->can_resume);
 		ioa_network_buffer_delete(server->e, sm->nd.nbh);
 		sm->nd.nbh = NULL;
 	}
@@ -4161,7 +4228,7 @@ int open_client_connection_session(turn_turnserver* server,
 /////////////// io handlers ///////////////////
 
 static void peer_input_handler(ioa_socket_handle s, int event_type,
-		ioa_net_data *in_buffer, void *arg) {
+		ioa_net_data *in_buffer, void *arg, int can_resume) {
 
 	if (!(event_type & IOA_EV_READ) || !arg)
 		return;
@@ -4170,6 +4237,7 @@ static void peer_input_handler(ioa_socket_handle s, int event_type,
 		return;
 
 	UNUSED_ARG(s);
+	UNUSED_ARG(can_resume);
 
 	ts_ur_super_session* ss = (ts_ur_super_session*) arg;
 
@@ -4274,7 +4342,7 @@ static void peer_input_handler(ioa_socket_handle s, int event_type,
 }
 
 static void client_input_handler(ioa_socket_handle s, int event_type,
-		ioa_net_data *data, void *arg) {
+		ioa_net_data *data, void *arg, int can_resume) {
 
 	if (!arg)
 		return;
@@ -4300,7 +4368,7 @@ static void client_input_handler(ioa_socket_handle s, int event_type,
 
 	switch (elem->state) {
 	case UR_STATE_READY:
-		read_client_connection(server, elem, ss, data, 1, 1);
+		read_client_connection(server, elem, ss, data, can_resume, 1);
 		break;
 	case UR_STATE_DONE:
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
@@ -4348,7 +4416,8 @@ void init_turn_server(turn_turnserver* server,
 		ip_range_list_t* ip_whitelist, ip_range_list_t* ip_blacklist,
 		send_socket_to_relay_cb send_socket_to_relay,
 		vintp secure_stun, SHATYPE shatype, vintp mobility, int server_relay,
-		send_turn_session_info_cb send_turn_session_info) {
+		send_turn_session_info_cb send_turn_session_info,
+		allocate_bps_cb allocate_bps_func) {
 
 	if (!server)
 		return;
@@ -4405,6 +4474,8 @@ void init_turn_server(turn_turnserver* server,
 
 	server->send_socket_to_relay = send_socket_to_relay;
 
+	server->allocate_bps_func = allocate_bps_func;
+
 	set_ioa_timer(server->e, 1, 0, timer_timeout_handler, server, 1, "timer_timeout_handler");
 }
 

+ 10 - 3
src/server/ns_turn_server.h

@@ -74,6 +74,7 @@ typedef enum _MESSAGE_TO_RELAY_TYPE MESSAGE_TO_RELAY_TYPE;
 struct socket_message {
 	ioa_socket_handle s;
 	ioa_net_data nd;
+	int can_resume;
 };
 
 typedef enum {
@@ -89,9 +90,11 @@ typedef void (*get_username_resume_cb)(int success, hmackey_t hmackey, st_passwo
 typedef u08bits *(*get_user_key_cb)(turnserver_id id, turn_credential_type ct, u08bits *uname, u08bits *realm, get_username_resume_cb resume, ioa_net_data *in_buffer, u64bits ctxkey, int *postpone_reply);
 typedef int (*check_new_allocation_quota_cb)(u08bits *username, u08bits *realm);
 typedef void (*release_allocation_quota_cb)(u08bits *username, u08bits *realm);
-typedef int (*send_socket_to_relay_cb)(turnserver_id id, u64bits cid, stun_tid *tid, ioa_socket_handle s, int message_integrity, MESSAGE_TO_RELAY_TYPE rmt, ioa_net_data *nd);
+typedef int (*send_socket_to_relay_cb)(turnserver_id id, u64bits cid, stun_tid *tid, ioa_socket_handle s, int message_integrity, MESSAGE_TO_RELAY_TYPE rmt, ioa_net_data *nd, int can_resume);
 typedef int (*send_turn_session_info_cb)(struct turn_session_info *tsi);
 
+typedef band_limit_t (*allocate_bps_cb)(band_limit_t bps, int positive);
+
 struct _turn_turnserver {
 
 	turnserver_id id;
@@ -149,6 +152,9 @@ struct _turn_turnserver {
 
 	/* Server relay */
 	int server_relay;
+
+	/* Bandwidth draft: */
+	allocate_bps_cb allocate_bps_func;
 };
 
 ///////////////////////////////////////////
@@ -182,7 +188,8 @@ void init_turn_server(turn_turnserver* server,
 				    SHATYPE shatype,
 				    vintp mobility,
 				    int server_relay,
-				    send_turn_session_info_cb send_turn_session_info);
+				    send_turn_session_info_cb send_turn_session_info,
+				    allocate_bps_cb allocate_bps_func);
 
 ioa_engine_handle turn_server_get_engine(turn_turnserver *s);
 
@@ -196,7 +203,7 @@ int open_client_connection_session(turn_turnserver* server, struct socket_messag
 int shutdown_client_connection(turn_turnserver *server, ts_ur_super_session *ss, int force, const char* reason);
 void set_disconnect_cb(turn_turnserver* server, int (*disconnect)(ts_ur_super_session*));
 
-int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_connection_id tcid, stun_tid *tid, ioa_socket_handle s, int message_integrity);
+int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_connection_id tcid, stun_tid *tid, ioa_socket_handle s, int message_integrity, ioa_net_data *nd, int can_resume);
 
 int report_turn_session_info(turn_turnserver *server, ts_ur_super_session *ss, int force_invalid);
 

+ 5 - 1
src/server/ns_turn_session.h

@@ -44,7 +44,7 @@ extern "C" {
 
 typedef struct _perf_options_t {
 
-	vint max_bps;
+	band_limit_t max_bps;
 	vint total_quota;
 	vint user_quota;
 
@@ -103,6 +103,8 @@ struct _ts_ur_super_session {
   realm_options_t realm_options;
   int realm_set;
   s08bits origin[STUN_MAX_ORIGIN_SIZE + 1];
+  /* Bandwidth */
+  band_limit_t bps;
 };
 
 ////// Session info for statistics //////
@@ -147,6 +149,8 @@ struct turn_session_info {
 /* Realm */
 	char realm[STUN_MAX_REALM_SIZE+1];
 	char origin[STUN_MAX_ORIGIN_SIZE + 1];
+/* Bandwidth */
+	band_limit_t bps;
 };
 
 void turn_session_info_init(struct turn_session_info* tsi);

+ 1 - 1
turndb/schema.sql

@@ -30,7 +30,7 @@ CREATE TABLE denied_peer_ip (
 CREATE TABLE turn_origin_to_realm (
 	origin varchar(512),
 	realm varchar(512),
-	primary key (origin,realm)
+	primary key (origin)
 );
 
 CREATE TABLE turn_realm_option (