Ver Fonte

Merge commit 'origin/ser_core_cvs'

* commit 'origin/ser_core_cvs': (22 commits)
  sctp: sctp_max_assocs support from the script
  sctp: core.sctp_options shows now also sctp_max_assocs
  sctp: max_assocs options
  sctp: sctp_assoc_tracking support from the script
  sctp: core.sctp_options shows now also sctp_assoc_tracking
  sctp:  assoc_tracking option
  sctp: SCTP_PEER_ADDR_PARAMS fix for older kernels
  sctp: assoc_reuse option
  core: cfg vars for the new sctp options
  core: sctp_options rpc updated
  sctp: more config variables
  tcp: remove unused var. decls
  dns: fix missing out-of-memory check
  - @next_hop.src_ip: source ip of outgoing message
  sctp: retransmission options
  sctp: sctp autoclose can now be changed at runtime
  sctp: enable runtime changing for some of the cfg vars
  tcp: minor fix: TCP_EV_IDLE_CONN_CLOSED
  tcp: minor fix: TCP_EV_CONNECT_RST() not always called
  sctp: compatibility with older linux kernels
  ...
Andrei Pelinescu-Onciul há 16 anos atrás
pai
commit
f3a1c116d4
15 ficheiros alterados com 1563 adições e 116 exclusões
  1. 106 2
      NEWS
  2. 43 0
      cfg.lex
  3. 101 5
      cfg.y
  4. 21 6
      core_cmd.c
  5. 10 7
      dns_cache.c
  6. 6 0
      main.c
  7. 521 16
      sctp_options.c
  8. 34 8
      sctp_options.h
  9. 651 60
      sctp_server.c
  10. 4 0
      sctp_server.h
  11. 51 0
      select_core.c
  12. 2 0
      select_core.h
  13. 0 4
      tcp_init.h
  14. 12 7
      tcp_main.c
  15. 1 1
      tcp_read.c

+ 106 - 2
NEWS

@@ -338,9 +338,14 @@ new config variables:
   sctp_socket_rcvbuf = number - size for the sctp socket receive buffer
   sctp_socket_sndbuf = number - size for the sctp socket send buffer
   sctp_autoclose = seconds - number of seconds before autoclosing an idle
-     assocation (default: 180 s).
+                   association (default: 180 s).
+                   Can be changed at runtime, but it will affect only new
+                   associations. E.g.:
+                   $ sercmd cfg.set_now_int sctp autoclose 120
   sctp_send_ttl = milliseconds - number of milliseconds before an unsent
-     message/chunk is dropped (default: 32000 ms or 32 s).
+                  message/chunk is dropped (default: 32000 ms or 32 s).
+                  Can be changed at runtime, e.g.:
+                  $ sercmd cfg.set_now_int sctp send_ttl 180000
   sctp_send_retries - how many times to attempt re-sending a message on a
                       re-opened association, if the sctp stack did give up
                       sending it (it's not related to sctp protocol level
@@ -349,6 +354,105 @@ new config variables:
                       machine. WARNING: use with care and low values (e.g.
                       1-3) to avoid "multiplying" traffic to unresponding 
                       hosts (default: 0).
+                      Can be changed at runtime.
+  sctp_assoc_tracking = yes/no - controls whether or not sctp associations
+     are tracked inside ser/sip-router. Turning it off would result in
+     less memory being used and slightly better performance, but it will also
+     disable some other features that depend on it (e.g. sctp_assoc_reuse).
+     Default: yes.
+     Can be changed at runtime (sercmd sctp assoc_tracking 0), but changes
+     will be allowed only if all the other features that depend on it are
+     turned off (for example it can be turned off only if first
+     sctp_assoc_reuse was turned off).
+     Note: turning sctp_assoc_tracking on/off will delete all the tracking
+     information for all the currently tracked associations and might introduce
+     a small temporary delay in the sctp processing if lots of associations
+     were tracked.
+     Config options depending on sctp_assoc_tracking being on:
+      sctp_assoc_reuse.
+  sctp_assoc_reuse = yes/no - controls sctp association reuse. For now only
+     association reuse for replies is affected by it. Default: yes.
+     Depends on sctp_assoc_tracking being on.
+     Note that even if turned off, if the port in via corresponds to the
+     source port of the association the request was sent on or if rport is
+     turned on (force_rport() or via containing a rport option), the
+     association will be automatically reused by the sctp stack.
+     Can be changed at runtime (sctp assoc_reuse), but it can be turned on
+     only if sctp_assoc_tracking is on.
+  sctp_max_assocs = number - maximum number of allowed open sctp associations.
+     -1 means maximum allowed by the OS. Default: -1.
+     Can be changed at runtime (e.g.:
+      sercmd cfg.set_now_int sctp max_assocs 10 ).
+     When the maximum associations number is exceeded and a new associations
+     is opened by a remote host, the association will be immediately closed.
+     However it is possible that some sip packets get through (especially if
+     they are sent early, as part of the 4-way handshake).
+     When ser/sip-router tries to open a new association and the max_assocs
+     is exceeded the exact behaviour depends on whether or not
+     sctp_assoc_tracking is on. If on, the send triggering the active open
+     will gracefully fail, before actually opening the new association and no
+     packet will be sent. However if sctp_assoc_tracking is off, the
+     association will first be opened and then immediately closed. In general
+     this means that the initial sip packet will be sent (as part of the 4-way
+     handshake).
+  sctp_srto_initial = milliseconds - initial value of the retr. timeout, used
+     in RTO calculations (default: OS specific).
+     Can be changed at runtime (sctp srto_initial) but it will affect only new
+     associations.
+  sctp_srto_max = milliseconds - maximum value of the retransmission timeout
+     (RTO) (default: OS specific).
+     WARNING: values lower then the sctp sack_delay will cause lots of
+     retransmissions and connection instability (see sctp_srto_min for more
+     details).
+     Can be changed at runtime (sctp srto_max) but it will affect only new
+     associations.
+  sctp_srto_min = milliseconds - minimum value of the retransmission timeout
+     (RTO) (default: OS specific).
+     WARNING: values lower then the sctp sack_delay of any peer might cause
+     retransmissions and possible interoperability problems. According to the
+     standard the sack_delay should be between 200 and 500 ms, so avoid trying
+     values lower then 500 ms unless you control all the possible sctp peers
+     and you do make sure their sack_delay is higher or their sack_freq is 1.
+     Can be changed at runtime (sctp srto_min) but it will affect only new
+     associations.
+  sctp_asocmaxrxt   = number - maximum retransmissions attempts per association
+     (default: OS specific). It should be set to sctp_pathmaxrxt * no. of
+     expected paths.
+     Can be changed at runtime (sctp asocmaxrxt) but it will affect only new
+     associations.
+  sctp_init_max_attempts = number - maximum INIT retransmission attempts
+     (default: OS specific).
+     Can be changed at runtime (sctp init_max_attempts).
+  sctp_init_max_timeo = milliseconds - maximum INIT retransmission timeout (RTO
+     max for INIT). Default: OS specific.
+     Can be changed at runtime (sctp init_max_timeo).
+  sctp_hbinterval = milliseconds - sctp heartbeat interval. Setting it to -1
+     will disable the heartbeats. Default: OS specific.
+     Can be changed at runtime (sctp hbinterval) but it will affect only new
+     associations.
+  sctp_pathmaxrxt = number - maximum retransmission attempts per path (see also
+     sctp_asocmaxrxt). Default: OS specific.
+     Can be changed at runtime (sctp pathmaxrxt) but it will affect only new
+     associations.
+  sctp_sack_delay = milliseconds - delay until an ACK is generated after
+     receiving a packet. Default: OS specific.
+     WARNING: a value higher then srto_min can cause a lot of retransmissions
+     (and strange problems). A value higher then srto_max will result in very
+     high connections instability. According to the standard the sack_delay
+     value should be between 200 and 500 ms.
+     Can be changed at runtime (sctp sack_delay) but it will affect only new
+     associations.
+  sctp_sack_freq = number - number of packets received before an ACK is sent
+     (without waiting for the sack_delay to expire).  Default: OS specific.
+     Note: on linux with lksctp up to and including 1.0.9 is not possible to
+     set this value (having it in the config will produce a warning on
+     startup).
+     Can be changed at runtime (sctp sack_freq) but it will affect only new
+     associations.
+  sctp_max_burst = number - maximum burst of packets that can be emitted by an
+     association. Default: OS specific.
+     Can be changed at runtime (sctp max_burst) but it will affect only new 
+     associations.
   server_id = number - A configurable unique server id that can be used to
                        discriminate server instances within a cluster of
                        servers when all other information, such as IP addresses

+ 43 - 0
cfg.lex

@@ -378,6 +378,21 @@ SCTP_SOCKET_SNDBUF	"sctp_socket_sndbuf"|"sctp_socket_send_buffer"
 SCTP_AUTOCLOSE	"sctp_autoclose"
 SCTP_SEND_TTL	"sctp_send_ttl"
 SCTP_SEND_RETRIES	"sctp_send_retries"
+SCTP_ASSOC_TRACKING	"sctp_assoc_tracking"
+SCTP_ASSOC_REUSE	"sctp_assoc_reuse"
+SCTP_MAX_ASSOCS		"sctp_max_assocs"
+SCTP_SRTO_INITIAL	"sctp_srto_initial"
+SCTP_SRTO_MAX		"sctp_srto_max"
+SCTP_SRTO_MIN		"sctp_srto_min"
+SCTP_ASOCMAXRXT		"sctp_asocmaxrxt"
+SCTP_INIT_MAX_ATTEMPTS		"sctp_init_max_attempts"
+SCTP_INIT_MAX_TIMEO			"sctp_init_max_timeo"
+SCTP_HBINTERVAL				"sctp_hbinterval"
+SCTP_PATHMAXRXT				"sctp_pathmaxrxt"
+SCTP_SACK_DELAY				"sctp_sack_delay"
+SCTP_SACK_FREQ				"sctp_sack_freq"
+SCTP_MAX_BURST				"sctp_max_burst"
+
 ADVERTISED_ADDRESS	"advertised_address"
 ADVERTISED_PORT		"advertised_port"
 DISABLE_CORE		"disable_core_dump"
@@ -715,6 +730,34 @@ EAT_ABLE	[\ \t\b\r]
 										return SCTP_SEND_TTL; }
 <INITIAL>{SCTP_SEND_RETRIES}	{ count(); yylval.strval=yytext;
 										return SCTP_SEND_RETRIES; }
+<INITIAL>{SCTP_ASSOC_TRACKING}	{ count(); yylval.strval=yytext;
+										return SCTP_ASSOC_TRACKING; }
+<INITIAL>{SCTP_ASSOC_REUSE}		{ count(); yylval.strval=yytext;
+										return SCTP_ASSOC_REUSE; }
+<INITIAL>{SCTP_MAX_ASSOCS}		{ count(); yylval.strval=yytext;
+										return SCTP_MAX_ASSOCS; }
+<INITIAL>{SCTP_SRTO_INITIAL}	{ count(); yylval.strval=yytext;
+										return SCTP_SRTO_INITIAL; }
+<INITIAL>{SCTP_SRTO_MAX}	{ count(); yylval.strval=yytext;
+										return SCTP_SRTO_MAX; }
+<INITIAL>{SCTP_SRTO_MIN}	{ count(); yylval.strval=yytext;
+										return SCTP_SRTO_MIN; }
+<INITIAL>{SCTP_ASOCMAXRXT}	{ count(); yylval.strval=yytext;
+										return SCTP_ASOCMAXRXT; }
+<INITIAL>{SCTP_INIT_MAX_ATTEMPTS}	{ count(); yylval.strval=yytext;
+										return SCTP_INIT_MAX_ATTEMPTS; }
+<INITIAL>{SCTP_INIT_MAX_TIMEO}	{ count(); yylval.strval=yytext;
+										return SCTP_INIT_MAX_TIMEO; }
+<INITIAL>{SCTP_HBINTERVAL}	{ count(); yylval.strval=yytext;
+										return SCTP_HBINTERVAL; }
+<INITIAL>{SCTP_PATHMAXRXT}	{ count(); yylval.strval=yytext;
+										return SCTP_PATHMAXRXT; }
+<INITIAL>{SCTP_SACK_DELAY}	{ count(); yylval.strval=yytext;
+										return SCTP_SACK_DELAY; }
+<INITIAL>{SCTP_SACK_FREQ}	{ count(); yylval.strval=yytext;
+										return SCTP_SACK_FREQ; }
+<INITIAL>{SCTP_MAX_BURST}	{ count(); yylval.strval=yytext;
+										return SCTP_MAX_BURST; }
 <INITIAL>{SERVER_SIGNATURE}	{ count(); yylval.strval=yytext; return SERVER_SIGNATURE; }
 <INITIAL>{REPLY_TO_VIA}	{ count(); yylval.strval=yytext; return REPLY_TO_VIA; }
 <INITIAL>{ADVERTISED_ADDRESS}	{	count(); yylval.strval=yytext;

+ 101 - 5
cfg.y

@@ -185,6 +185,12 @@
 	#define IF_STUN(x) warn("stun support not compiled in")
 #endif
 
+#ifdef USE_SCTP
+	#define IF_SCTP(x) x
+#else
+	#define IF_SCTP(x) warn("sctp support not compiled in")
+#endif
+
 
 extern int yylex();
 static void yyerror(char* s, ...);
@@ -439,6 +445,20 @@ static int case_check_default(struct case_stms* stms);
 %token SCTP_AUTOCLOSE
 %token SCTP_SEND_TTL
 %token SCTP_SEND_RETRIES
+%token SCTP_ASSOC_TRACKING
+%token SCTP_ASSOC_REUSE
+%token SCTP_MAX_ASSOCS
+%token SCTP_SRTO_INITIAL
+%token SCTP_SRTO_MAX
+%token SCTP_SRTO_MIN
+%token SCTP_ASOCMAXRXT
+%token SCTP_INIT_MAX_ATTEMPTS
+%token SCTP_INIT_MAX_TIMEO
+%token SCTP_HBINTERVAL
+%token SCTP_PATHMAXRXT
+%token SCTP_SACK_DELAY
+%token SCTP_SACK_FREQ
+%token SCTP_MAX_BURST
 %token ADVERTISED_ADDRESS
 %token ADVERTISED_PORT
 %token DISABLE_CORE
@@ -1214,7 +1234,7 @@ assign_stm:
 	| SCTP_CHILDREN EQUAL error { yyerror("number expected"); }
 	| SCTP_SOCKET_RCVBUF EQUAL NUMBER {
 		#ifdef USE_SCTP
-			sctp_options.sctp_so_rcvbuf=$3;
+			sctp_default_cfg.so_rcvbuf=$3;
 		#else
 			warn("sctp support not compiled in");
 		#endif
@@ -1222,7 +1242,7 @@ assign_stm:
 	| SCTP_SOCKET_RCVBUF EQUAL error { yyerror("number expected"); }
 	| SCTP_SOCKET_SNDBUF EQUAL NUMBER {
 		#ifdef USE_SCTP
-			sctp_options.sctp_so_sndbuf=$3;
+			sctp_default_cfg.so_sndbuf=$3;
 		#else
 			warn("sctp support not compiled in");
 		#endif
@@ -1230,7 +1250,7 @@ assign_stm:
 	| SCTP_SOCKET_SNDBUF EQUAL error { yyerror("number expected"); }
 	| SCTP_AUTOCLOSE EQUAL NUMBER {
 		#ifdef USE_SCTP
-			sctp_options.sctp_autoclose=$3;
+			sctp_default_cfg.autoclose=$3;
 		#else
 			warn("sctp support not compiled in");
 		#endif
@@ -1238,7 +1258,7 @@ assign_stm:
 	| SCTP_AUTOCLOSE EQUAL error { yyerror("number expected"); }
 	| SCTP_SEND_TTL EQUAL NUMBER {
 		#ifdef USE_SCTP
-			sctp_options.sctp_send_ttl=$3;
+			sctp_default_cfg.send_ttl=$3;
 		#else
 			warn("sctp support not compiled in");
 		#endif
@@ -1246,12 +1266,88 @@ assign_stm:
 	| SCTP_SEND_TTL EQUAL error { yyerror("number expected"); }
 	| SCTP_SEND_RETRIES EQUAL NUMBER {
 		#ifdef USE_SCTP
-			sctp_options.sctp_send_retries=$3;
+			sctp_default_cfg.send_retries=$3;
 		#else
 			warn("sctp support not compiled in");
 		#endif
 	}
 	| SCTP_SEND_RETRIES EQUAL error { yyerror("number expected"); }
+	| SCTP_ASSOC_TRACKING EQUAL NUMBER {
+		#ifdef USE_SCTP
+			#ifdef SCTP_CONN_REUSE
+				sctp_default_cfg.assoc_tracking=$3;
+			#else
+				if ($3)
+					warn("sctp association tracking/reuse (SCTP_CONN_REUSE) "
+							"support not compiled in");
+			#endif /* SCTP_CONN_REUSE */
+		#else
+			warn("sctp support not compiled in");
+		#endif /* USE_SCTP */
+	}
+	| SCTP_ASSOC_TRACKING EQUAL error { yyerror("number expected"); }
+	| SCTP_ASSOC_REUSE EQUAL NUMBER {
+		#ifdef USE_SCTP
+			#ifdef SCTP_CONN_REUSE
+				sctp_default_cfg.assoc_reuse=$3;
+			#else
+				if ($3)
+					warn("sctp association reuse (SCTP_CONN_REUSE) support"
+							" not compiled in");
+			#endif /* SCTP_CONN_REUSE */
+		#else
+			warn("sctp support not compiled in");
+		#endif /* USE_SCTP */
+	}
+	| SCTP_ASSOC_REUSE EQUAL error { yyerror("number expected"); }
+	| SCTP_MAX_ASSOCS EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.max_assocs=$3);
+	}
+	| SCTP_MAX_ASSOCS EQUAL error { yyerror("number expected"); }
+	| SCTP_SRTO_INITIAL EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.srto_initial=$3);
+	}
+	| SCTP_SRTO_INITIAL EQUAL error { yyerror("number expected"); }
+	| SCTP_SRTO_MAX EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.srto_max=$3);
+	}
+	| SCTP_SRTO_MAX EQUAL error { yyerror("number expected"); }
+	| SCTP_SRTO_MIN EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.srto_min=$3);
+	}
+	| SCTP_SRTO_MIN EQUAL error { yyerror("number expected"); }
+	| SCTP_ASOCMAXRXT EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.asocmaxrxt=$3);
+	}
+	| SCTP_ASOCMAXRXT EQUAL error { yyerror("number expected"); }
+	| SCTP_INIT_MAX_ATTEMPTS EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.init_max_attempts=$3);
+	}
+	| SCTP_INIT_MAX_ATTEMPTS EQUAL error { yyerror("number expected"); }
+	| SCTP_INIT_MAX_TIMEO EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.init_max_timeo=$3);
+	}
+	| SCTP_INIT_MAX_TIMEO EQUAL error { yyerror("number expected"); }
+	| SCTP_HBINTERVAL EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.hbinterval=$3);
+	}
+	| SCTP_HBINTERVAL EQUAL error { yyerror("number expected"); }
+	| SCTP_PATHMAXRXT EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.pathmaxrxt=$3);
+	}
+	| SCTP_PATHMAXRXT EQUAL error { yyerror("number expected"); }
+	| SCTP_SACK_DELAY EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.sack_delay=$3);
+	}
+	| SCTP_SACK_DELAY EQUAL error { yyerror("number expected"); }
+	| SCTP_SACK_FREQ EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.sack_freq=$3);
+	}
+	| SCTP_SACK_FREQ EQUAL error { yyerror("number expected"); }
+	| SCTP_MAX_BURST EQUAL NUMBER {
+			IF_SCTP(sctp_default_cfg.max_burst=$3);
+	}
+	| SCTP_MAX_BURST EQUAL error { yyerror("number expected"); }
 	| SERVER_SIGNATURE EQUAL NUMBER { server_signature=$3; }
 	| SERVER_SIGNATURE EQUAL error { yyerror("boolean value expected"); }
 	| REPLY_TO_VIA EQUAL NUMBER { reply_to_via=$3; }

+ 21 - 6
core_cmd.c

@@ -627,16 +627,31 @@ static void core_sctp_options(rpc_t* rpc, void* c)
 {
 #ifdef USE_SCTP
 	void *handle;
-	struct sctp_cfg_options t;
+	struct cfg_group_sctp t;
 
 	if (!sctp_disable){
 		sctp_options_get(&t);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "dddd",
-			"sctp_autoclose",		t.sctp_autoclose,
-			"sctp_send_ttl",	t.sctp_autoclose,
-			"sctp_socket_rcvbuf",	t.sctp_so_rcvbuf,
-			"sctp_socket_sndbuf",	t.sctp_so_sndbuf
+		rpc->struct_add(handle, "ddddddddddddddddddd",
+			"sctp_socket_rcvbuf",	t.so_rcvbuf,
+			"sctp_socket_sndbuf",	t.so_sndbuf,
+			"sctp_autoclose",		t.autoclose,
+			"sctp_send_ttl",	t.send_ttl,
+			"sctp_send_retries",	t.send_retries,
+			"sctp_assoc_tracking",	t.assoc_tracking,
+			"sctp_assoc_reuse",	t.assoc_reuse,
+			"sctp_max_assocs", t.max_assocs,
+			"sctp_srto_initial",	t.srto_initial,
+			"sctp_srto_max",		t.srto_max,
+			"sctp_srto_min",		t.srto_min,
+			"sctp_asocmaxrxt",	t.asocmaxrxt,
+			"sctp_init_max_attempts",	t.init_max_attempts,
+			"sctp_init_max_timeo",t.init_max_timeo,
+			"sctp_hbinterval",	t.hbinterval,
+			"sctp_pathmaxrxt",	t.pathmaxrxt,
+			"sctp_sack_delay",	t.sack_delay,
+			"sctp_sack_freq",	t.sack_freq,
+			"sctp_max_burst",	t.max_burst
 		);
 	}else{
 		rpc->fault(c, 500, "sctp support disabled");

+ 10 - 7
dns_cache.c

@@ -1866,7 +1866,7 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
 	if (type==T_A){
 		if ((ip=str2ip(name))!=0){
 				e=dns_cache_mk_ip_entry(name, ip);
-				if (e)
+				if (likely(e))
 					atomic_set(&e->refcnt, 1);/* because we ret. a ref. to it*/
 				goto end; /* we do not cache obvious stuff */
 		}
@@ -1875,7 +1875,7 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
 	else if (type==T_AAAA){
 		if ((ip=str2ip6(name))!=0){
 				e=dns_cache_mk_ip_entry(name, ip);
-				if (e)
+				if (likely(e))
 					atomic_set(&e->refcnt, 1);/* because we ret. a ref. to it*/
 				goto end;/* we do not cache obvious stuff */
 		}
@@ -1897,12 +1897,12 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
 	if (records){
 #ifdef CACHE_RELEVANT_RECS_ONLY
 		e=dns_cache_mk_rd_entry(name, type, &records);
-		if (e){
+		if (likely(e)){
 			l=e;
 			e=dns_get_related(l, type, &records);
 			/* e should contain the searched entry (if found) and l
 			 * all the entries (e and related) */
-			if (e){
+			if (likely(e)){
 				atomic_set(&e->refcnt, 1); /* 1 because we return a
 												ref. to it */
 			}else{
@@ -1943,9 +1943,12 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
 #endif
 		free_rdata_list(records);
 	}else if (cfg_get(core, core_cfg, dns_neg_cache_ttl)){
-		e=dns_cache_mk_bad_entry(name, type, cfg_get(core, core_cfg, dns_neg_cache_ttl), DNS_BAD_NAME);
-		atomic_set(&e->refcnt, 1); /* 1 because we return a ref. to it */
-		dns_cache_add(e); /* refcnt++ inside*/
+		e=dns_cache_mk_bad_entry(name, type, 
+				cfg_get(core, core_cfg, dns_neg_cache_ttl), DNS_BAD_NAME);
+		if (likely(e)) {
+			atomic_set(&e->refcnt, 1); /* 1 because we return a ref. to it */
+			dns_cache_add(e); /* refcnt++ inside*/
+		}
 		goto end;
 	}
 #ifndef CACHE_RELEVANT_RECS_ONLY

+ 6 - 0
main.c

@@ -1960,6 +1960,12 @@ try_again:
 		goto error;
 	}
 #endif /* USE_TCP */
+#ifdef USE_SCTP
+	if (sctp_register_cfg()){
+		LOG(L_CRIT, "could not register the sctp configuration\n");
+		goto error;
+	}
+#endif /* USE_SCTP */
 	/*init timer, before parsing the cfg!*/
 	if (init_timer()<0){
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");

+ 521 - 16
sctp_options.c

@@ -22,31 +22,132 @@
  * History:
  * --------
  *  2008-08-07  initial version (andrei)
+ *  2009-05-26  runtime cfg support (andrei)
  */
 
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/sctp.h>
+#include <errno.h>
 
 #include "sctp_options.h"
 #include "dprint.h"
+#include "cfg/cfg.h"
+#include "socket_info.h"
+#include "sctp_server.h"
 
+struct cfg_group_sctp sctp_default_cfg;
 
-struct sctp_cfg_options sctp_options;
+
+
+#ifdef USE_SCTP
+
+
+static int set_autoclose(void* cfg_h, str* gname, str* name, void** val);
+static int set_assoc_tracking(void* cfg_h, str* gname, str* name, void** val);
+static int set_assoc_reuse(void* cfg_h, str* gname, str* name, void** val);
+static int set_srto_initial(void* cfg_h, str* gname, str* name, void** val);
+static int set_srto_max(void* cfg_h, str* gname, str* name, void** val);
+static int set_srto_min(void* cfg_h, str* gname, str* name, void** val);
+static int set_asocmaxrxt(void* cfg_h, str* gname, str* name, void** val);
+static int set_sinit_max_attempts(void* cfg_h, str* gname, str* name,
+										void** val);
+static int set_sinit_max_init_timeo(void* cfg_h, str* gname, str* name,
+										void** val);
+static int set_hbinterval(void* cfg_h, str* gname, str* name, void** val);
+static int set_pathmaxrxt(void* cfg_h, str* gname, str* name, void** val);
+static int set_sack_freq(void* cfg_h, str* gname, str* name, void** val);
+static int set_sack_delay(void* cfg_h, str* gname, str* name, void** val);
+static int set_max_burst(void* cfg_h, str* gname, str* name, void** val);
+
+/** cfg_group_sctp description (for the config framework). */
+static cfg_def_t sctp_cfg_def[] = {
+	/*   name        , type |input type| chg type, min, max, fixup, proc. cbk.
+	      description */
+	{ "socket_rcvbuf", CFG_VAR_INT| CFG_READONLY, 512, 102400, 0, 0,
+		"socket receive buffer size (read-only)" },
+	{ "socket_sndbuf", CFG_VAR_INT| CFG_READONLY, 512, 102400, 0, 0,
+		"socket send buffer size (read-only)" },
+	{ "autoclose", CFG_VAR_INT| CFG_ATOMIC, 1, 1<<30, set_autoclose, 0,
+		"seconds before closing and idle connection (must be non-zero)" },
+	{ "send_ttl", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, 0, 0,
+		"milliseconds before aborting a send" },
+	{ "send_retries", CFG_VAR_INT| CFG_ATOMIC, 0, MAX_SCTP_SEND_RETRIES, 0, 0,
+		"re-send attempts on failure" },
+	{ "assoc_tracking", CFG_VAR_INT| CFG_ATOMIC, 0, 1, set_assoc_tracking, 0,
+		"connection/association tracking (see also assoc_reuse)" },
+	{ "assoc_reuse", CFG_VAR_INT| CFG_ATOMIC, 0, 1, set_assoc_reuse, 0,
+		"connection/association reuse (for now used only for replies)"
+		", depends on assoc_tracking being set"},
+	{ "max_assocs", CFG_VAR_INT| CFG_ATOMIC, 0, 0, 0, 0,
+		"maximum allowed open associations (-1 = disable, "
+			"as many as allowed by the OS)"},
+	{ "srto_initial", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_initial, 0,
+		"initial value of the retr. timeout, used in RTO calculations,"
+			" in msecs" },
+	{ "srto_max", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_max, 0,
+		"maximum value of the retransmission timeout (RTO), in msecs" },
+	{ "srto_min", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_srto_min, 0,
+		"minimum value of the retransmission timeout (RTO), in msecs" },
+	{ "asocmaxrxt", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<10, set_asocmaxrxt, 0,
+		"maximum retransmission attempts per association" },
+	{ "init_max_attempts", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<10,
+		set_sinit_max_attempts, 0, "max INIT retransmission attempts" },
+	{ "init_max_timeo", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<10,
+		set_sinit_max_init_timeo, 0,
+		"max INIT retransmission timeout (RTO max for INIT), in msecs" },
+	{ "hbinterval", CFG_VAR_INT| CFG_ATOMIC, 0, 0, set_hbinterval, 0,
+		"heartbeat interval in msecs" },
+	{ "pathmaxrxt", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<10, set_pathmaxrxt, 0,
+		"maximum retransmission attempts per path" },
+	{ "sack_delay", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, set_sack_delay, 0,
+		"time since the last received packet before sending a SACK, in msecs"},
+	{ "sack_freq", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<10, set_sack_freq, 0,
+		"number of received packets that trigger the sending of a SACK"},
+	{ "max_burst", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<10, set_max_burst, 0,
+		"maximum burst of packets that can be emitted by an association"},
+	{0, 0, 0, 0, 0, 0, 0}
+};
+
+
+
+void* sctp_cfg; /* sctp config handle */
+
+#endif /* USE_SCTP */
 
 void init_sctp_options()
 {
 #ifdef USE_SCTP
-	sctp_options.sctp_autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
-	sctp_options.sctp_send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
-	sctp_options.sctp_send_retries=DEFAULT_SCTP_SEND_RETRIES;
+	sctp_get_os_defaults(&sctp_default_cfg);
+#if 0
+	sctp_default_cfg.so_rcvbuf=0; /* do nothing, use the kernel default */
+	sctp_default_cfg.so_sndbuf=0; /* do nothing, use the kernel default */
+#endif
+	sctp_default_cfg.autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
+	sctp_default_cfg.send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
+	sctp_default_cfg.send_retries=DEFAULT_SCTP_SEND_RETRIES;
+	sctp_default_cfg.max_assocs=-1; /* as much as possible by default */
+#ifdef SCTP_CONN_REUSE
+	sctp_default_cfg.assoc_tracking=1; /* on by default */
+	sctp_default_cfg.assoc_reuse=1; /* on by default */
+#else
+	sctp_default_cfg.assoc_tracking=0;
+	sctp_default_cfg.assoc_reuse=0;
+#endif /* SCTP_CONN_REUSE */
 #endif
 }
 
 
 
 #define W_OPT_NSCTP(option) \
-	if (sctp_options.option){\
+	if (sctp_default_cfg.option){\
 		WARN("sctp_options: " #option \
 			" cannot be enabled (sctp support not compiled-in)\n"); \
-			sctp_options.option=0; \
+			sctp_default_cfg.option=0; \
 	}
 
 
@@ -54,21 +155,425 @@ void init_sctp_options()
 void sctp_options_check()
 {
 #ifndef USE_SCTP
-	W_OPT_NSCTP(sctp_autoclose);
-	W_OPT_NSCTP(sctp_send_ttl);
-	W_OPT_NSCTP(sctp_send_retries);
-#else
-	if (sctp_options.sctp_send_retries>MAX_SCTP_SEND_RETRIES) {
+	W_OPT_NSCTP(autoclose);
+	W_OPT_NSCTP(send_ttl);
+	W_OPT_NSCTP(send_retries);
+	W_OPT_NSCTP(assoc_tracking);
+	W_OPT_NSCTP(assoc_reuse);
+	W_OPT_NSCTP(max_assocs);
+#else /* USE_SCTP */
+	if (sctp_default_cfg.send_retries>MAX_SCTP_SEND_RETRIES) {
 		WARN("sctp: sctp_send_retries too high (%d), setting it to %d\n",
-				sctp_options.sctp_send_retries, MAX_SCTP_SEND_RETRIES);
-		sctp_options.sctp_send_retries=MAX_SCTP_SEND_RETRIES;
+				sctp_default_cfg.send_retries, MAX_SCTP_SEND_RETRIES);
+		sctp_default_cfg.send_retries=MAX_SCTP_SEND_RETRIES;
 	}
-#endif
+#ifndef CONN_REUSE
+	if (sctp_default_cfg.assoc_tracking || sctp_default_cfg.assoc_reuse){
+		WARN("sctp_options: assoc_tracking and assoc_reuse support cannnot"
+				" be enabled (CONN_REUSE support not compiled-in)\n");
+		sctp_default_cfg.assoc_tracking=0;
+		sctp_default_cfg.assoc_reuse=0;
+	}
+#else /* CONN_REUSE */
+	if (sctp_default_cfg.assoc_reuse && sctp_default_cfg.assoc_tracking==0){
+		sctp_default_cfg.assoc_tracking=1;
+	}
+#endif /* CONN_REUSE */
+#endif /* USE_SCTP */
+}
+
+
+
+void sctp_options_get(struct cfg_group_sctp *s)
+{
+#ifdef USE_SCTP
+	*s=*(struct cfg_group_sctp*)sctp_cfg;
+#else
+	memset(s, 0, sizeof(*s));
+#endif /* USE_SCTP */
+}
+
+
+
+#ifdef USE_SCTP
+/** register sctp config into the configuration framework.
+ * @return 0 on success, -1 on error */
+int sctp_register_cfg()
+{
+	if (cfg_declare("sctp", sctp_cfg_def, &sctp_default_cfg, cfg_sizeof(sctp),
+				&sctp_cfg))
+		return -1;
+	if (sctp_cfg==0){
+		BUG("null sctp cfg");
+		return -1;
+	}
+	return 0;
+}
+
+
+
+#define SCTP_SET_SOCKOPT_DECLS \
+	int err; \
+	struct socket_info* si
+
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
+	err=0; \
+	for (si=sctp_listen; si; si=si->next){ \
+		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
+							sizeof((val)), (err_prefix))<0); \
+	} \
+	return -(err!=0)
+
+
+
+static int set_autoclose(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_AUTOCLOSE
+	int optval;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	optval=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_AUTOCLOSE, optval,
+							"cfg: setting SCTP_AUTOCLOSE");
+#else
+	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_AUTOCLOSE */
+}
+
+
+
+static int set_assoc_tracking(void* cfg_h, str* gname, str* name, void** val)
+{
+	int optval;
+	
+	optval=(int)(long)(*val);
+#ifndef SCTP_CONN_REUSE
+	if (optval!=0){
+		ERR("no SCTP_CONN_REUSE support, please recompile with it enabled\n");
+		return -1;
+	}
+#else /* SCTP_CONN_REUSE */
+	if (optval==0){
+		/* turn tracking off */
+		/* check if assoc_reuse is off */
+		if (cfg_get(sctp, cfg_h, assoc_reuse)!=0){
+			ERR("cannot turn sctp assoc_tracking off while assoc_reuse is"
+					" still on, please turn assoc_reuse off first\n");
+			return -1;
+		}
+		sctp_con_tracking_flush();
+	}else if (optval==1 && cfg_get(sctp, cfg_h, assoc_reuse)==0){
+		/* turning from off to on, make sure we flush the tracked list
+		   again, just incase the off flush was racing with a new connection*/
+		sctp_con_tracking_flush();
+	}
+#endif /* SCTP_CONN_REUSE */
+	return 0;
+}
+
+
+
+static int set_assoc_reuse(void* cfg_h, str* gname, str* name, void** val)
+{
+	int optval;
+	
+	optval=(int)(long)(*val);
+#ifndef SCTP_CONN_REUSE
+	if (optval!=0){
+		ERR("no SCTP_CONN_REUSE support, please recompile with it enabled\n");
+		return -1;
+	}
+#else /* SCTP_CONN_REUSE */
+	if (optval==1 && cfg_get(sctp, cfg_h, assoc_tracking)==0){
+		/* conn reuse on, but assoc_tracking off => not possible */
+		ERR("cannot turn sctp assoc_reuse on while assoc_tracking is"
+					" off, please turn assoc_tracking on first\n");
+		return -1;
+	}
+#endif /* SCTP_CONN_REUSE */
+	return 0;
+}
+
+
+
+static int set_srto_initial(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_initial);
+		return 0;
+	}
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_initial=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+							"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
+}
+
+
+
+static int set_srto_max(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_max);
+		return 0;
+	}
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_max=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+							"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
 }
 
 
 
-void sctp_options_get(struct sctp_cfg_options *s)
+static int set_srto_min(void* cfg_h, str* gname, str* name, void** val)
 {
-	*s=sctp_options;
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_min);
+		return 0;
+	}
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_min=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+							"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
 }
+
+
+
+static int set_asocmaxrxt(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_ASSOCINFO
+	struct sctp_assocparams ap;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, asocmaxrxt);
+		return 0;
+	}
+	memset(&ap, 0, sizeof(ap)); /* zero everything we don't care about */
+	ap.sasoc_assoc_id=0; /* all */
+	ap.sasoc_asocmaxrxt=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_ASSOCINFO, ap,
+							"cfg: setting SCTP_ASSOCINFO");
+#else
+	ERR("no SCTP_ASSOCINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_ASSOCINFO */
+}
+
+
+
+static int set_sinit_max_init_timeo(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_INITMSG
+	struct sctp_initmsg im;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, init_max_timeo);
+		return 0;
+	}
+	memset(&im, 0, sizeof(im)); /* zero everything we don't care about */
+	im.sinit_max_init_timeo=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_INITMSG, im,
+							"cfg: setting SCTP_INITMSG");
+#else
+	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_INITMSG */
+}
+
+
+
+static int set_sinit_max_attempts(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_INITMSG
+	struct sctp_initmsg im;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, init_max_attempts);
+		return 0;
+	}
+	memset(&im, 0, sizeof(im)); /* zero everything we don't care about */
+	im.sinit_max_attempts=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_INITMSG, im,
+							"cfg: setting SCTP_INITMSG");
+#else
+	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_INITMSG */
+}
+
+
+
+static int set_hbinterval(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_PEER_ADDR_PARAMS
+	struct sctp_paddrparams pp;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, hbinterval);
+		return 0;
+	}
+	memset(&pp, 0, sizeof(pp)); /* zero everything we don't care about */
+	if ((int)(long)(*val)!=-1){
+		pp.spp_hbinterval=(int)(long)(*val);
+		pp.spp_flags=SPP_HB_ENABLE;
+	}else{
+		pp.spp_flags=SPP_HB_DISABLE;
+	}
+	err=0;
+	for (si=sctp_listen; si; si=si->next){
+		/* set the AF, needed on older linux kernels even for INADDR_ANY */
+		pp.spp_address.ss_family=si->address.af;
+		err+=(sctp_setsockopt(si->socket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS,
+								(void*)(&pp), sizeof(pp),
+								"cfg: setting SCTP_PEER_ADDR_PARAMS")<0);
+	}
+	return -(err!=0);
+#else
+	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
+			" sctp library\n");
+	return -1;
+#endif /* SCTP_PEER_ADDR_PARAMS */
+}
+
+
+
+static int set_pathmaxrxt(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_PEER_ADDR_PARAMS
+	struct sctp_paddrparams pp;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, pathmaxrxt);
+		return 0;
+	}
+	memset(&pp, 0, sizeof(pp)); /* zero everything we don't care about */
+	pp.spp_pathmaxrxt=(int)(long)(*val);
+	err=0;
+	for (si=sctp_listen; si; si=si->next){
+		/* set the AF, needed on older linux kernels even for INADDR_ANY */
+		pp.spp_address.ss_family=si->address.af;
+		err+=(sctp_setsockopt(si->socket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS,
+								(void*)(&pp), sizeof(pp),
+								"cfg: setting SCTP_PEER_ADDR_PARAMS")<0);
+	}
+	return -(err!=0);
+#else
+	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
+			" sctp library\n");
+	return -1;
+#endif /* SCTP_PEER_ADDR_PARAMS */
+}
+
+
+
+static int set_sack_delay(void* cfg_h, str* gname, str* name, void** val)
+{
+#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
+#ifdef SCTP_DELAYED_SACK
+	struct sctp_sack_info sa;
+#else /* old lib */
+	struct sctp_assoc_value sa;
+#endif /* SCTP_DELAYED_SACK */
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
+		return 0;
+	}
+	memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
+#ifdef SCTP_DELAYED_SACK
+	sa.sack_delay=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_SACK, sa,
+							"cfg: setting SCTP_DELAYED_SACK");
+#else /* old sctp lib version which uses SCTP_DELAYED_ACK_TIME */
+	sa.assoc_value=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, sa,
+							"cfg: setting SCTP_DELAYED_ACK_TIME");
+#endif /* SCTP_DELAYED_SACK */
+#else
+	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_DELAYED_SACK | SCTP_DELAYED_ACK_TIME */
+}
+
+
+
+static int set_sack_freq(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_DELAYED_SACK
+	struct sctp_sack_info sa;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_freq);
+		return 0;
+	}
+	memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
+	sa.sack_freq=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_SACK, sa,
+							"cfg: setting SCTP_DELAYED_SACK");
+#else
+	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_DELAYED_SACK */
+}
+
+
+
+static int set_max_burst(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_MAX_BURST
+	struct sctp_assoc_value av;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, max_burst);
+		return 0;
+	}
+	memset(&av, 0, sizeof(av)); /* zero everything we don't care about */
+	av.assoc_value=(int)(long)(*val);
+	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_MAX_BURST, av,
+							"cfg: setting SCTP_MAX_BURST");
+#else
+	ERR("no SCTP_MAX_BURST support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_MAX_BURST */
+}
+
+#endif /* USE_SCTP */

+ 34 - 8
sctp_options.h

@@ -22,29 +22,55 @@
  * History:
  * --------
  *  2008-08-07  initial version (andrei)
+ *  2009-05-26  runtime cfg support (andrei)
  */
 
 #ifndef _sctp_options_h
 #define _sctp_options_h
 
+#ifndef NO_SCTP_CONN_REUSE
+/* SCTP connection reuse by default */
+#define SCTP_CONN_REUSE
+#endif
+
 #define DEFAULT_SCTP_AUTOCLOSE 180 /* seconds */
 #define DEFAULT_SCTP_SEND_TTL  32000 /* in ms (32s)  */
 #define DEFAULT_SCTP_SEND_RETRIES 0
 #define MAX_SCTP_SEND_RETRIES 9
 
 
-struct sctp_cfg_options{
-	int sctp_so_rcvbuf;
-	int sctp_so_sndbuf;
-	unsigned int sctp_autoclose; /* in seconds */
-	unsigned int sctp_send_ttl; /* in milliseconds */
-	unsigned int sctp_send_retries;
+struct cfg_group_sctp{
+	int so_rcvbuf;
+	int so_sndbuf;
+	unsigned int autoclose; /* in seconds */
+	unsigned int send_ttl; /* in milliseconds */
+	unsigned int send_retries;
+	int assoc_tracking; /* track associations */
+	int assoc_reuse; /* reuse the request connection for sending the reply,
+					    depends on assoc_tracking */
+	int max_assocs; /* maximum associations, -1 means disabled */
+	unsigned int srto_initial; /** initial retr. timeout */
+	unsigned int srto_max;     /** max retr. timeout */
+	unsigned int srto_min;     /** min retr. timeout */
+	unsigned int asocmaxrxt; /** max. retr. attempts per association */
+	unsigned int init_max_attempts; /** max., INIT retr. attempts */
+	unsigned int init_max_timeo; /** rto max for INIT */
+	unsigned int hbinterval;  /** heartbeat interval in msecs */
+	unsigned int pathmaxrxt;  /** max. retr. attempts per path */
+	unsigned int sack_delay; /** msecs after which a delayed SACK is sent */
+	unsigned int sack_freq; /** no. of packets after which a SACK is sent */
+	unsigned int max_burst; /** maximum burst of packets per assoc. */
 };
 
-extern struct sctp_cfg_options sctp_options;
+extern struct cfg_group_sctp sctp_default_cfg;
+
+/* sctp config handle */
+extern void* sctp_cfg;
 
 void init_sctp_options();
 void sctp_options_check();
-void sctp_options_get(struct sctp_cfg_options *s);
+int sctp_register_cfg();
+void sctp_options_get(struct cfg_group_sctp *s);
+int sctp_get_os_defaults(struct cfg_group_sctp *s);
 
 #endif /* _sctp_options_h */

Diff do ficheiro suprimidas por serem muito extensas
+ 651 - 60
sctp_server.c


+ 4 - 0
sctp_server.h

@@ -48,4 +48,8 @@ void sctp_get_info(struct sctp_gen_info* sinf);
 
 void destroy_sctp();
 
+int sctp_setsockopt(int s, int level, int optname,
+					void* optval, socklen_t optlen, char* err_prefix);
+
+void sctp_con_tracking_flush();
 #endif /* _sctp_server_h */

+ 51 - 0
select_core.c

@@ -61,6 +61,8 @@
 #include "parser/parse_body.h"
 #include "dset.h"
 #include "sr_module.h"
+#include "resolve.h"
+#include "forward.h"
 
 #define RETURN0_res(x) {*res=(x);return 0;}
 #define TRIM_RET0_res(x) {*res=(x);trim(res);return 0;} 
@@ -122,6 +124,55 @@ int select_next_hop(str* res, select_t* s, struct sip_msg* msg)
 	return -1;
 }
 
+int select_next_hop_src_ip(str* res, select_t* s, struct sip_msg* msg) {
+	struct socket_info* socket_info;
+	union sockaddr_union to;
+	char proto;
+	struct sip_uri *u, next_hop;
+	str *dst_host;
+
+	if (msg->first_line.type!=SIP_REQUEST) 
+		return -1;
+
+	if (msg->force_send_socket) {
+		*res = msg->force_send_socket->address_str;
+		return 0;
+	}
+
+	if (msg->dst_uri.len) {
+		if (parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop) < 0)
+			return -1;
+		u = &next_hop;
+	}
+	else {
+		if (parse_sip_msg_uri(msg) < 0)
+			return -1;
+		u = &msg->parsed_uri;
+	}
+#ifdef USE_TLS
+	if (u->type==SIPS_URI_T)
+		proto = PROTO_TLS;
+	else
+#endif
+		proto = u->proto;
+
+#ifdef HONOR_MADDR
+	if (u->maddr_val.s && u->maddr_val.len)
+		dst_host = &u->maddr_val;
+	else
+#endif
+		dst_host = &u->host;
+
+	if (sip_hostport2su(&to, dst_host, u->port_no, &proto) < 0)
+		return -1;
+	socket_info = get_send_socket(msg, &to, proto);
+	if (!socket_info)
+		return -1;
+
+	*res = socket_info->address_str;
+	return 0;
+}
+
 #define SELECT_uri_header(_name_) \
 int select_##_name_(str* res, select_t* s, struct sip_msg* msg) \
 { \

+ 2 - 0
select_core.h

@@ -86,6 +86,7 @@ enum {
 SELECT_F(select_ruri)
 SELECT_F(select_dst_uri)
 SELECT_F(select_next_hop)
+SELECT_F(select_next_hop_src_ip)
 SELECT_F(select_from)
 SELECT_F(select_from_uri)
 SELECT_F(select_from_tag)
@@ -222,6 +223,7 @@ static select_row_t select_core[] = {
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("dst_uri"), select_dst_uri, 0},
 	{ select_dst_uri, SEL_PARAM_STR, STR_NULL, select_any_uri, NESTED},
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("next_hop"), select_next_hop, 0},
+	{ select_next_hop, SEL_PARAM_STR, STR_STATIC_INIT("src_ip"), select_next_hop_src_ip, 0},
 	{ select_next_hop, SEL_PARAM_STR, STR_NULL, select_any_uri, NESTED},
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("from"), select_from, 0},
 	{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("f"), select_from, 0},

+ 0 - 4
tcp_init.h

@@ -54,10 +54,6 @@ struct tcp_child{
 #define TCP_ALIAS_FORCE_ADD 1
 #define TCP_ALIAS_REPLACE   2
 
-/* flags used for adding new aliases */
-extern int tcp_alias_flags;
-/* flags used for adding the default aliases of a new tcp connection */
-extern int tcp_new_conn_alias_flags;
 
 int init_tcp();
 void destroy_tcp();

+ 12 - 7
tcp_main.c

@@ -3493,12 +3493,8 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
 			}
 			tcpconn->flags&=~(F_CONN_WRITE_W|F_CONN_READ_W|
 								F_CONN_WANTS_RD|F_CONN_WANTS_WR);
-			if (unlikely(!tcpconn_try_unhash(tcpconn))){
-				LOG(L_CRIT, "BUG: tcpconn_ev: unhashed connection %p\n",
-							tcpconn);
-			}
 			if (unlikely(ev & POLLERR)){
-				if (unlikely(tcpconn->state=S_CONN_CONNECT)){
+				if (unlikely(tcpconn->state==S_CONN_CONNECT)){
 #ifdef USE_DST_BLACKLIST
 					if (cfg_get(core, core_cfg, use_dst_blacklist))
 						dst_blacklist_su(BLST_ERR_CONNECT, tcpconn->rcv.proto,
@@ -3517,6 +3513,10 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
 					TCP_STATS_CON_RESET(); /* FIXME: it could != RST */
 				}
 			}
+			if (unlikely(!tcpconn_try_unhash(tcpconn))){
+				LOG(L_CRIT, "BUG: tcpconn_ev: unhashed connection %p\n",
+							tcpconn);
+			}
 			tcpconn_put_destroy(tcpconn);
 			goto error;
 		}
@@ -3699,12 +3699,19 @@ static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
 			TCP_EV_SEND_TIMEOUT(0, &c->rcv);
 			TCP_STATS_SEND_TIMEOUT();
 		}
+	}else{
+		/* idle timeout */
+		TCP_EV_IDLE_CONN_CLOSED(0, &c->rcv);
+		TCP_STATS_CON_TIMEOUT();
 	}
 #else /* ! TCP_ASYNC */
 	if (TICKS_LT(t, c->timeout)){
 		/* timeout extended, exit */
 		return (ticks_t)(c->timeout - t);
 	}
+	/* idle timeout */
+	TCP_EV_IDLE_CONN_CLOSED(0, &c->rcv);
+	TCP_STATS_CON_TIMEOUT();
 #endif /* TCP_ASYNC */
 	DBG("tcp_main: timeout for %p\n", c);
 	if (likely(c->flags & F_CONN_HASHED)){
@@ -3726,8 +3733,6 @@ static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
 			c->flags&=~(F_CONN_READ_W|F_CONN_WRITE_W);
 		}
 	}
-	TCP_EV_IDLE_CONN_CLOSED(0, &c->rcv);
-	TCP_STATS_CON_TIMEOUT();
 	tcpconn_put_destroy(c);
 	return 0;
 }

+ 1 - 1
tcp_read.c

@@ -149,7 +149,7 @@ again:
 				bytes_read=0; /* nothing has been read */
 			}else if (errno == EINTR) goto again;
 			else{
-				if (unlikely(c->state=S_CONN_CONNECT)){
+				if (unlikely(c->state==S_CONN_CONNECT)){
 					switch(errno){
 						case ECONNRESET:
 #ifdef USE_DST_BLACKLIST

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff