Browse Source

Merge remote branch 'origin/andrei/blst_send_flags'

Support for blacklist ignore flags, both global and on a per
message basis.
E.g.:
per message:
if (method=~"MESSAGE")
	blst_set_ignore(6);

global:
sercmd cfg.set_now_int core dst_blacklist_tcp_imask 16

* origin/andrei/blst_send_flags:
  NEWS: minor blacklist flag number correction
  tm: blacklist on 503 reply fixed for send flags
  NEWS: mentioned blacklist ignore masks
  core: cfg script support for blacklist ignore masks
  blst: global config variables for ignoring blacklist events
  blst: docs for blst_{set,clear}_ignore script functions
  blst: functions for ignoring blacklist events
  blst: use dst_blacklist_force_add
  tm: simplified blacklist add code
  blacklist: ignore mask support
  tm: updated to the new snd_flags_t structure
  core: send_flags preliminary blacklist support

Conflicts:
	NEWS
	cfg.lex
	cfg.y
	dst_blacklist.h
Andrei Pelinescu-Onciul 15 years ago
parent
commit
04f55d6c20
24 changed files with 664 additions and 191 deletions
  1. 39 1
      NEWS
  2. 4 4
      action.c
  3. 13 0
      cfg.lex
  4. 30 3
      cfg.y
  5. 14 1
      cfg_core.c
  6. 4 0
      cfg_core.h
  7. 42 6
      dst_blacklist.c
  8. 112 22
      dst_blacklist.h
  9. 2 3
      forward.c
  10. 2 2
      forward.h
  11. 27 2
      ip_addr.h
  12. 10 7
      modules/tm/t_fwd.c
  13. 16 12
      modules/tm/t_reply.c
  14. 4 4
      modules/tm/timer.c
  15. 5 3
      modules/tm/uac.c
  16. 12 4
      modules/tm/ut.h
  17. 47 0
      modules_s/blst/README
  18. 109 7
      modules_s/blst/blst.c
  19. 80 0
      modules_s/blst/doc/functions.xml
  20. 2 2
      parser/msg_parser.h
  21. 6 9
      sctp_server.c
  22. 4 3
      tcp_conn.h
  23. 70 83
      tcp_main.c
  24. 10 13
      tcp_read.c

+ 39 - 1
NEWS

@@ -3,7 +3,43 @@ Release notes for SIP Router (sr)
 
 $Id$
 
-sip-router changes
+sip-router 3.1 chages
+
+core:
+  - global, per protocol blacklist ignore masks (via extended send_flags).
+    See dst_blacklist_udp_imask a.s.o (dst_blacklist_*_imask).
+  - per message blacklist ignore masks
+
+new config variables:
+  - dst_blacklist_udp_imask - global blacklist events ignore mask for udp
+    (a blacklist event/reason set in this variable will be ignored when 
+    deciding whether or not to blacklist an udp destination). Can be set
+    at runtime. Default: 0 (no blacklist reason is ignored).
+    Possible values:  0 -disabled, 2 - send error; 4 - connect error,
+                      8 - icmp (reserverd), 16 - transaction timeout,
+                     32 - 503 received, 64 - administratively prohibited
+                     (manually set).
+   - dst_blacklist_tcp_imask - like dst_blacklist_udp_imask, but for tcp.
+   - dst_blacklist_tls_imask - like dst_blacklist_tls_imask, but for tcp.
+   - dst_blacklist_sctp_imask -like dst_blacklist_sctp_imask, but for tcp.
+
+modules:
+   - blst: functions for ignoring blacklist events per message:
+           blst_set_ignore(mask):  set the events in mask in the per
+            per message blacklist ignore mask for a request
+            (see dst_blacklist_udp_imask for possible values).
+            The basic operation is: msg_blst_ignore_mask|=mask.
+           blst_clear_ignore(mask): like blst_set_ignore(mask), but instead
+            of setting some events, it clears them
+            (msg_blst_ignore_mask&=~mask).
+           blst_rpl_set_ignore(mask): like blst_set_ignore(mask), but sets
+            the mask for possible local replies to the current message.
+           blst_rpl_clear_ignore(mask): like blst_rpl_ignore(mask), but
+            clears instead of setting.
+
+
+
+sip-router 3.0 changes
 
 core:
   - type casts operators: (int), (str).
@@ -66,6 +102,8 @@ config script changes:
   - event route support: event_route[module_name:eventid]
   - user and shm_force_alloc must now appear prior to any modparam() or route
      block.
+  - per message send_flags support (see set_forward_no_connect(),
+     set_forward_reply_no_connect(), set_forward_close() & set_reply_close())
 
 build system:
   - multiple modules directories are now supported (defined in Makefile.dirs)

+ 4 - 4
action.c

@@ -1235,19 +1235,19 @@ match_cleanup:
 				ret=v;
 			break;
 		case SET_FWD_NO_CONNECT_T:
-			msg->fwd_send_flags|= SND_F_FORCE_CON_REUSE;
+			msg->fwd_send_flags.f|= SND_F_FORCE_CON_REUSE;
 			ret=1; /* continue processing */
 			break;
 		case SET_RPL_NO_CONNECT_T:
-			msg->rpl_send_flags|= SND_F_FORCE_CON_REUSE;
+			msg->rpl_send_flags.f|= SND_F_FORCE_CON_REUSE;
 			ret=1; /* continue processing */
 			break;
 		case SET_FWD_CLOSE_T:
-			msg->fwd_send_flags|= SND_F_CON_CLOSE;
+			msg->fwd_send_flags.f|= SND_F_CON_CLOSE;
 			ret=1; /* continue processing */
 			break;
 		case SET_RPL_CLOSE_T:
-			msg->rpl_send_flags|= SND_F_CON_CLOSE;
+			msg->rpl_send_flags.f|= SND_F_CON_CLOSE;
 			ret=1; /* continue processing */
 			break;
 /*

+ 13 - 0
cfg.lex

@@ -81,6 +81,7 @@
  *  2009-04-24  add strlen, strempty and defined operators (andrei)
  *  2009-03-07  RETCODE, it's now  a core pvar (andrei)
  *  2010-01-10  added SHM_MEM_SZ (andrei)
+ *  2010-02-17 added DST_BLST_{UDP,TCP,TLS,SCTP}_IMASK (andrei)
 */
 
 
@@ -358,6 +359,10 @@ USE_DST_BLST		use_dst_blacklist
 DST_BLST_MEM		dst_blacklist_mem
 DST_BLST_TTL		dst_blacklist_expire|dst_blacklist_ttl
 DST_BLST_GC_INT		dst_blacklist_gc_interval
+DST_BLST_UDP_IMASK	dst_blacklist_udp_imask
+DST_BLST_TCP_IMASK	dst_blacklist_tcp_imask
+DST_BLST_TLS_IMASK	dst_blacklist_tls_imask
+DST_BLST_SCTP_IMASK	dst_blacklist_sctp_imask
 
 
 PORT	port
@@ -703,6 +708,14 @@ EAT_ABLE	[\ \t\b\r]
 								return DST_BLST_TTL; }
 <INITIAL>{DST_BLST_GC_INT}	{ count(); yylval.strval=yytext;
 								return DST_BLST_GC_INT; }
+<INITIAL>{DST_BLST_UDP_IMASK}	{ count(); yylval.strval=yytext;
+								return DST_BLST_UDP_IMASK; }
+<INITIAL>{DST_BLST_TCP_IMASK}	{ count(); yylval.strval=yytext;
+								return DST_BLST_TCP_IMASK; }
+<INITIAL>{DST_BLST_TLS_IMASK}	{ count(); yylval.strval=yytext;
+								return DST_BLST_TLS_IMASK; }
+<INITIAL>{DST_BLST_SCTP_IMASK}	{ count(); yylval.strval=yytext;
+								return DST_BLST_SCTP_IMASK; }
 <INITIAL>{PORT}	{ count(); yylval.strval=yytext; return PORT; }
 <INITIAL>{STAT}	{ count(); yylval.strval=yytext; return STAT; }
 <INITIAL>{MAXBUFFER}	{ count(); yylval.strval=yytext; return MAXBUFFER; }

+ 30 - 3
cfg.y

@@ -98,6 +98,7 @@
  * 2009-05-04  switched if to rval_expr (andrei)
  * 2010-01-10  init shm on first mod_param or route block;
  *             added SHM_MEM_SZ (andrei)
+ * 2010-02-17  added blacklist imask (DST_BLST_*_IMASK) support (andrei)
 */
 
 %{
@@ -403,6 +404,10 @@ extern char *finame;
 %token DST_BLST_MEM
 %token DST_BLST_TTL
 %token DST_BLST_GC_INT
+%token DST_BLST_UDP_IMASK
+%token DST_BLST_TCP_IMASK
+%token DST_BLST_TLS_IMASK
+%token DST_BLST_SCTP_IMASK
 
 %token PORT
 %token STAT
@@ -840,14 +845,36 @@ assign_stm:
 	| DNS_CACHE_DEL_NONEXP error { yyerror("boolean value expected"); }
 	| DST_BLST_INIT EQUAL NUMBER   { IF_DST_BLACKLIST(dst_blacklist_init=$3); }
 	| DST_BLST_INIT error { yyerror("boolean value expected"); }
-	| USE_DST_BLST EQUAL NUMBER   { IF_DST_BLACKLIST(default_core_cfg.use_dst_blacklist=$3); }
+	| USE_DST_BLST EQUAL NUMBER {
+		IF_DST_BLACKLIST(default_core_cfg.use_dst_blacklist=$3);
+	}
 	| USE_DST_BLST error { yyerror("boolean value expected"); }
-	| DST_BLST_MEM EQUAL NUMBER   { IF_DST_BLACKLIST(default_core_cfg.blst_max_mem=$3); }
+	| DST_BLST_MEM EQUAL NUMBER {
+		IF_DST_BLACKLIST(default_core_cfg.blst_max_mem=$3); 
+	}
 	| DST_BLST_MEM error { yyerror("boolean value expected"); }
-	| DST_BLST_TTL EQUAL NUMBER   { IF_DST_BLACKLIST(default_core_cfg.blst_timeout=$3); }
+	| DST_BLST_TTL EQUAL NUMBER {
+		IF_DST_BLACKLIST(default_core_cfg.blst_timeout=$3);
+	}
 	| DST_BLST_TTL error { yyerror("boolean value expected"); }
 	| DST_BLST_GC_INT EQUAL NUMBER { IF_DST_BLACKLIST(blst_timer_interval=$3);}
 	| DST_BLST_GC_INT error { yyerror("boolean value expected"); }
+	| DST_BLST_UDP_IMASK EQUAL NUMBER {
+		IF_DST_BLACKLIST(default_core_cfg.blst_udp_imask=$3);
+	}
+	| DST_BLST_UDP_IMASK error { yyerror("number(flags) expected"); }
+	| DST_BLST_TCP_IMASK EQUAL NUMBER {
+		IF_DST_BLACKLIST(default_core_cfg.blst_tcp_imask=$3);
+	}
+	| DST_BLST_TCP_IMASK error { yyerror("number(flags) expected"); }
+	| DST_BLST_TLS_IMASK EQUAL NUMBER {
+		IF_DST_BLACKLIST(default_core_cfg.blst_tls_imask=$3);
+	}
+	| DST_BLST_TLS_IMASK error { yyerror("number(flags) expected"); }
+	| DST_BLST_SCTP_IMASK EQUAL NUMBER {
+		IF_DST_BLACKLIST(default_core_cfg.blst_sctp_imask=$3);
+	}
+	| DST_BLST_SCTP_IMASK error { yyerror("number(flags) expected"); }
 	| PORT EQUAL NUMBER   { port_no=$3; }
 	| STAT EQUAL STRING {
 		#ifdef STATS

+ 14 - 1
cfg_core.c

@@ -69,6 +69,10 @@ struct cfg_group_core default_core_cfg = {
 	0, /*!< dst blacklist is disabled by default */
 	DEFAULT_BLST_TIMEOUT,
 	DEFAULT_BLST_MAX_MEM,
+	0, /* blst_udp_imask */
+	0, /* blst_tcp_imask */
+	0, /* blst_tls_imask */
+	0, /* blst_sctp_imask */
 #endif
 	/* resolver */
 #ifdef USE_IPV6
@@ -129,7 +133,16 @@ cfg_def_t core_cfg_def[] = {
 	{"dst_blacklist_expire",	CFG_VAR_INT,	0, 0, 0, 0,
 		"how much time (in s) a blacklisted destination is kept in the list"},
 	{"dst_blacklist_mem",	CFG_VAR_INT,	0, 0, blst_max_mem_fixup, 0,
-		"maximum shared memory amount (in KB) used for keeping the blacklisted destinations"},
+		"maximum shared memory amount (in KB) used for keeping the blacklisted"
+			" destinations"},
+	{"dst_blacklist_udp_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
+		"blacklist event ignore mask for UDP"},
+	{"dst_blacklist_tcp_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
+		"blacklist event ignore mask for TCP"},
+	{"dst_blacklist_tls_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
+		"blacklist event ignore mask for TLS"},
+	{"dst_blacklist_sctp_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
+		"blacklist event ignore mask for SCTP"},
 #endif
 	/* resolver */
 #ifdef USE_DNS_CACHE

+ 4 - 0
cfg_core.h

@@ -63,6 +63,10 @@ struct cfg_group_core {
 	unsigned int	blst_timeout; /*!< blacklist entry ttl */
 	unsigned int	blst_max_mem; /*!< maximum memory used for the
 					blacklist entries */
+	unsigned int	blst_udp_imask;  /* ignore mask for udp */
+	unsigned int	blst_tcp_imask;  /* ignore mask for tcp */
+	unsigned int	blst_tls_imask;  /* ignore mask for tls */
+	unsigned int	blst_sctp_imask; /* ignore mask for sctp */
 #endif
 	/* resolver */
 	int dns_try_ipv6;

+ 42 - 6
dst_blacklist.c

@@ -143,6 +143,9 @@ struct dst_blst_lst_head* dst_blst_hash=0;
 struct t_dst_blacklist_stats* dst_blacklist_stats=0;
 #endif
 
+/* blacklist per protocol event ignore mask array */
+unsigned blst_proto_imask[PROTO_LAST+1];
+
 #ifdef DST_BLACKLIST_HOOKS
 
 /* there 2 types of callbacks supported: on add new entry to the blacklist
@@ -303,6 +306,26 @@ inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
 #endif /* DST_BLACKLIST_HOOKS */
 
 
+/** init per protocol blacklist event ignore masks.
+ * @return 0 on success, < 0 on error.
+ */
+int blst_init_ign_masks()
+{
+	if ((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) ||
+		(PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)){
+		BUG("protocol array too small\n");
+		return -1;
+	}
+	blst_proto_imask[PROTO_UDP]=cfg_get(core, core_cfg, blst_udp_imask);
+	blst_proto_imask[PROTO_TCP]=cfg_get(core, core_cfg, blst_tcp_imask);
+	blst_proto_imask[PROTO_TLS]=cfg_get(core, core_cfg, blst_tls_imask);
+	blst_proto_imask[PROTO_SCTP]=cfg_get(core, core_cfg, blst_sctp_imask);
+	blst_proto_imask[PROTO_NONE]=blst_proto_imask[PROTO_UDP];
+	return 0;
+}
+
+
+
 inline static void blst_destroy_entry(struct dst_blst_entry* e)
 {
 	shm_free(e);
@@ -485,6 +508,10 @@ int init_dst_blacklist()
 			goto error;
 		}
 	}
+	if (blst_init_ign_masks() < 0){
+		ret=E_BUG;
+		goto error;
+	}
 	return 0;
 error:
 	destroy_dst_blacklist();
@@ -801,8 +828,8 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
  * @param timeout - timeout in ticks
  * @return 0 on success, -1 on error
  */
-int dst_blacklist_add_to(unsigned char err_flags,  struct dest_info* si,
-						struct sip_msg* msg, ticks_t timeout)
+int dst_blacklist_force_add_to(unsigned char err_flags,  struct dest_info* si,
+								struct sip_msg* msg, ticks_t timeout)
 {
 	struct ip_addr ip;
 
@@ -819,12 +846,12 @@ int dst_blacklist_add_to(unsigned char err_flags,  struct dest_info* si,
 
 
 /** add dst to the blacklist, specifying the timeout.
- * (like @function dst_blacklist_add_to)= above, but uses 
+ * (like @function dst_blacklist_force_add_to)= above, but uses 
  * (proto, sockaddr_union) instead of struct dest_info)
  */
-int dst_blacklist_su_to(unsigned char err_flags, unsigned char proto,
-							union sockaddr_union* dst,
-							struct sip_msg* msg, ticks_t timeout)
+int dst_blacklist_force_su_to(unsigned char err_flags, unsigned char proto,
+								union sockaddr_union* dst,
+								struct sip_msg* msg, ticks_t timeout)
 {
 	struct ip_addr ip;
 #ifdef DST_BLACKLIST_HOOKS
@@ -1204,5 +1231,14 @@ int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val)
 	return 0;
 }
 
+
+
+/** re-inint per child blst_proto_ign_mask array. */
+void blst_reinit_ign_masks(str* gname, str* name)
+{
+	blst_init_ign_masks();
+}
+
+
 #endif /* USE_DST_BLACKLIST */
 

+ 112 - 22
dst_blacklist.h

@@ -20,9 +20,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-/**
+/** SIP-router core :: Destination blacklists.
  * @file
- * @brief SIP-router core :: Destination blacklists
  * @ingroup core
  * Module: @ref core
  */
@@ -31,6 +30,8 @@
  * --------
  *  2006-07-29  created by andrei
  *  2007-07-30  dst blacklist measurements added (Gergo)
+ *  2009-12-22  blacklist ignore mask support and dst_blacklist_{add,su}
+ *               switched to macros (andrei)
  */
 
 #ifndef dst_black_list_h
@@ -67,6 +68,9 @@
 #define DST_BLACKLIST_ADD_CB 1
 #define DST_BLACKLIST_SEARCH_CB 2
 
+
+extern unsigned blst_proto_imask[PROTO_LAST+1];
+
 #ifdef DST_BLACKLIST_HOOKS
 struct blacklist_hook{
 	/* WARNING: msg might be NULL, and it might point to shared memory
@@ -89,41 +93,127 @@ int init_dst_blacklist_stats(int iproc_num);
 void destroy_dst_blacklist();
 
 
-/** @brief like dst_blacklist_add, but the timeout can be also set */
-int dst_blacklist_add_to(unsigned char err_flags, struct dest_info* si,
-						struct sip_msg* msg, ticks_t timeout);
-/** @brief like above, but using a differnt way of passing the target */
-int dst_blacklist_su_to(unsigned char err_flags, unsigned char proto,
-							union sockaddr_union* dst,
-							struct sip_msg* msg, ticks_t timeout);
+/** force add to the blacklist.
+ * like @function dst_blacklist_add_to, but no ignore mask or
+ * blacklist enabled checks are made.
+ * @see dst_blacklist_add_to for the parameters and return value.
+ */
+int dst_blacklist_force_add_to(unsigned char err_flags, struct dest_info* si,
+								struct sip_msg* msg, ticks_t timeout);
 
-/** @brief adds a dst to the blacklist with default timeout.
- * @see dst_blacklist_add_to for more details.
+/** force add to the blacklist, long version.
+ * like @function dst_blacklist_su_to, but no ignore mask or
+ * blacklist enabled checks are made.
+ * @see dst_blacklist_su_to for the parameters and return value.
  */
-#define dst_blacklist_add(err_flags, si, msg) \
-	dst_blacklist_add_to((err_flags), (si), (msg), \
-		S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
+int dst_blacklist_force_su_to(	unsigned char err_flags,
+								unsigned char proto,
+								union sockaddr_union* dst,
+								struct sip_msg* msg,
+								ticks_t timeout);
+
+
+/** checks if blacklist should be used.
+  * @param  err_flags - blacklist reason
+  * @param si - filled dest_info structure pointer.
+  * @return 1 if blacklist is enabled (core_cfg) and the event/error
+  *           is not in the ignore list.
+  *         0 otherwise
+  */
+#define should_blacklist(err_flags, si) \
+	(cfg_get(core, core_cfg, use_dst_blacklist) && \
+		((err_flags) & ~blst_proto_imask[(unsigned)((si)->proto)] & \
+		 			   ~(si)->send_flags.blst_imask ))
+
+
+/** checks if blacklist should be used, long version.
+  * @param  err_flags - blacklist reason
+  * @param snd_flags - snd_flags pointer, can be 0.
+  * @param proto - protocol, can be 0 (PROTO_NONE).
+  * @param si  - sockaddr_union pointer, can be 0.
+  * @return 1 if blacklist is enabled (core_cfg) and the event/error
+  *           is not in the ignore list.
+  *         0 otherwise
+  */
+#define should_blacklist_su(err_flags, snd_flags, proto, su) \
+	(cfg_get(core, core_cfg, use_dst_blacklist) && \
+		((err_flags) & ~blst_proto_imask[(unsigned)(proto)] & \
+		 			~((snd_flags)?((snd_flags_t*)(snd_flags))->blst_imask:0)))
+
+
+/** adds a dst to the blacklist.
+ *
+ * @param  err_flags - blacklist reason
+ * @param si  - dest_info structure (dst).
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
+ * @param timeout - timeout in ticks.
+ * @return >=0 on success, -1 on error.
+ */
+#define dst_blacklist_add_to(err_flags, si, msg, timeout) \
+	(should_blacklist(err_flags, si)? \
+		dst_blacklist_force_add_to((err_flags), (si), (msg), (timeout))\
+		: 0)
+
+
+/** adds a dst to the blacklist, long version.
+ * Similar to dst_blacklist_add_to, but uses "unpacked" parameters.
+ * @param  err_flags - blacklist reason
+ * @param proto - protocol.
+ * @param dst  - sockaddr_union pointer.
+ * @param snd_flags - snd_flags pointer, can be 0.
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
+ * @param timeout - timeout in ticks.
+ * @return >=0 on success, -1 on error.
+ */
+#define dst_blacklist_su_to(err_flags, proto, dst, snd_flags, msg, timeout) \
+	(should_blacklist_su(err_flags, snd_flags, proto, dst) ? \
+		dst_blacklist_force_su_to((err_flags), (proto), (dst), (msg), \
+									(timeout))\
+		: 0)
+
 
-/** @brief adds a dst to the blacklist with default timeout.
- * @see dst_blacklist_su_to for more details.
+/** adds a dst to the blacklist with default timeout.
+ *
+ * @param  err_flags - blacklist reason
+ * @param si  - dest_info structure (dst).
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
+ * @return >=0 on success, -1 on error.
+ * @see dst_blacklist_add_to.
  */
-#define dst_blacklist_su(err_flags, proto, dst, msg) \
-	dst_blacklist_su_to((err_flags), (proto), (dst), (msg), \
-		S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
+#define dst_blacklist_add(err_flags, si, msg) \
+	dst_blacklist_add_to(err_flags, si, msg, \
+							S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
+
+
+/** adds a dst to the blacklist with default timeout, long version.
+ * Similar to dst_blacklist_add_to, but uses "unpacked" parameters.
+ * @param  err_flags - blacklist reason
+ * @param proto - protocol.
+ * @param dst  - sockaddr_union pointer.
+ * @param snd_flags - snd_flags pointer, can be 0.
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
+ * @return >=0 on success, -1 on error.
+ * @see dst_blacklist_su_to.
+ */
+#define dst_blacklist_su(err_flags, proto, dst, snd_flags, msg) \
+	dst_blacklist_su_to(err_flags, proto, dst, snd_flags, msg, \
+							S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
 
 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg);
 
-/** @brief  delete an entry from the blacklist */
+/** delete an entry from the blacklist. */
 int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg);
 
-/** @brief deletes all the entries from the blacklist except the permanent ones
+/** deletes all the entries from the blacklist except the permanent ones.
  * (which are marked with BLST_PERMANENT)
  */
 void dst_blst_flush(void);
 
 int use_dst_blacklist_fixup(void *handle, str *gname, str *name, void **val);
 
-/** @brief KByte to Byte conversion */
+/** KByte to Byte conversion. */
 int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val);
 
+void blst_reinit_ign_masks(str* gname, str* name);
+
 #endif

+ 2 - 3
forward.c

@@ -603,8 +603,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
 		if (msg_send(send_info, buf, len)<0){
 			ret=ser_error=E_SEND;
 #ifdef USE_DST_BLACKLIST
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
-				dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
+			dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
 #endif
 #ifdef USE_DNS_FAILOVER
 			continue; /* try another ip */
@@ -766,7 +765,7 @@ int forward_reply(struct sip_msg* msg)
 	}
 
 	dst.proto=msg->via2->proto;
-	dst.send_flags=msg->fwd_send_flags | msg->rpl_send_flags;
+	SND_FLAGS_OR(&dst.send_flags, &msg->fwd_send_flags, &msg->rpl_send_flags);
 	if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error;
 #ifdef USE_COMP
 	dst.comp=msg->via2->comp_no;

+ 2 - 2
forward.h

@@ -158,7 +158,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 			goto error;
 		}else{
 			from=0;
-			if (unlikely((dst->send_flags & SND_F_FORCE_SOCKET) &&
+			if (unlikely((dst->send_flags.f & SND_F_FORCE_SOCKET) &&
 						dst->send_sock)) {
 				local_addr=dst->send_sock->su;
 				su_setport(&local_addr, 0); /* any local port will do */
@@ -180,7 +180,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 			goto error;
 		}else{
 			from=0;
-			if (unlikely((dst->send_flags & SND_F_FORCE_SOCKET) &&
+			if (unlikely((dst->send_flags.f & SND_F_FORCE_SOCKET) &&
 						dst->send_sock)) {
 				local_addr=dst->send_sock->su;
 				su_setport(&local_addr, 0); /* any local port will do */

+ 27 - 2
ip_addr.h

@@ -142,7 +142,31 @@ struct receive_info{
 #define SND_F_CON_CLOSE			2 /* close the connection after sending */
 #define SND_F_FORCE_SOCKET		4 /* send socket in dst is forced */
 
-typedef unsigned char  snd_flags_t;
+struct snd_flags {
+	unsigned char f;          /* snd flags */
+	unsigned char blst_imask; /* blacklist ignore mask */
+};
+
+
+typedef struct snd_flags  snd_flags_t;
+
+#define SND_FLAGS_INIT(sflags) \
+	do{ \
+		(sflags)->f=0; \
+		(sflags)->blst_imask=0; \
+	}while(0)
+
+#define SND_FLAGS_OR(dst, src1, src2) \
+	do{ \
+		(dst)->f = (src1)->f | (src2)->f; \
+		(dst)->blst_imask = (src1)->blst_imask | (src2)->blst_imask; \
+	}while(0)
+
+#define SND_FLAGS_AND(dst, src1, src2) \
+	do{ \
+		(dst)->f = (src1)->f & (src2)->f; \
+		(dst)->blst_imask = (src1)->blst_imask & (src2)->blst_imask; \
+	}while(0)
 
 struct dest_info{
 	struct socket_info* send_sock;
@@ -757,7 +781,8 @@ inline static void init_dst_from_rcv(struct dest_info* dst,
 		dst->to=rcv->src_su;
 		dst->id=rcv->proto_reserved1;
 		dst->proto=rcv->proto;
-		dst->send_flags=0;
+		dst->send_flags.f=0;
+		dst->send_flags.blst_imask=0;
 #ifdef USE_COMP
 		dst->comp=rcv->comp;
 #endif

+ 10 - 7
modules/tm/t_fwd.c

@@ -659,8 +659,10 @@ static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
 		t->uac[branch].request.dst.send_sock =
 		get_send_socket( request, &t->uac[branch].request.dst.to,
 								t->uac[branch].request.dst.proto);
-		t->uac[branch].request.dst.send_flags=request?
-												request->fwd_send_flags:0;
+		if (request)
+			t->uac[branch].request.dst.send_flags=request->fwd_send_flags;
+		else
+			SND_FLAGS_INIT(&t->uac[branch].request.dst.send_flags);
 		next_hop=0;
 	}else {
 		next_hop= next_hop?next_hop:uri;
@@ -845,7 +847,7 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 				 * in the rest of the message, only in the VIA HF (Miklos) */
 				ret=add_uac_from_buf(t,  msg, &old_uac->uri,
 							&old_uac->path,
-							 (old_uac->request.dst.send_flags &
+							 (old_uac->request.dst.send_flags.f &
 								SND_F_FORCE_SOCKET)?
 									old_uac->request.dst.send_sock:0,
 							old_uac->request.dst.send_flags,
@@ -858,7 +860,7 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 				 *  must be changed and the send_socket might be different =>
 				 *  re-create the whole uac */
 				ret=add_uac(t,  msg, &old_uac->uri, 0, &old_uac->path, 0,
-							 (old_uac->request.dst.send_flags &
+							 (old_uac->request.dst.send_flags.f &
 								SND_F_FORCE_SOCKET)?
 									old_uac->request.dst.send_sock:0,
 							old_uac->request.dst.send_flags,
@@ -883,6 +885,7 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 	int ret;
 	char *shbuf;
 	unsigned int len;
+	snd_flags_t snd_flags;
 
 	ret=-1;
 	if (t_cancel->uac[branch].request.buffer) {
@@ -928,12 +931,13 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 			cancel_msg->first_line.u.request.method.len+1;
 		t_cancel->uac[branch].uri.len=t_invite->uac[branch].uri.len;
 	} else {
+		SND_FLAGS_INIT(&snd_flags);
 		/* buffer is constructed from the received CANCEL with lumps applied */
 		/*  t_cancel...request.dst is already filled (see above) */
 		if (unlikely((ret=prepare_new_uac( t_cancel, cancel_msg, branch,
 									&t_invite->uac[branch].uri,
 									&t_invite->uac[branch].path,
-									0, 0, 0, PROTO_NONE, 0)) <0)){
+									0, 0, snd_flags, PROTO_NONE, 0)) <0)){
 			ser_error=ret;
 			goto error;
 		}
@@ -1215,8 +1219,7 @@ int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
 							ip_addr2a(&ip), su_getport(&uac->request.dst.to),
 							uac->request.dst.proto);
 #ifdef USE_DST_BLACKLIST
-		if (cfg_get(core, core_cfg, use_dst_blacklist))
-			dst_blacklist_add(BLST_ERR_SEND, &uac->request.dst, p_msg);
+		dst_blacklist_add(BLST_ERR_SEND, &uac->request.dst, p_msg);
 #endif
 #ifdef USE_DNS_FAILOVER
 		/* if the destination resolves to more ips, add another

+ 16 - 12
modules/tm/t_reply.c

@@ -1651,7 +1651,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 				}
 				/* update send_flags with possible additions from the
 				   reply route */
-				uas_rb->dst.send_flags|=relayed_msg->rpl_send_flags;
+				SND_FLAGS_OR(&uas_rb->dst.send_flags, &uas_rb->dst.send_flags,
+								&relayed_msg->rpl_send_flags);
 			}
 		}
 		update_reply_stats( relayed_code );
@@ -1885,7 +1886,6 @@ int reply_received( struct sip_msg  *p_msg )
 #endif
 #ifdef USE_DST_BLACKLIST
 	int blst_503_timeout;
-	struct dest_info src;
 	struct hdr_field* hf;
 #endif
 #ifdef TMCB_ONSEND
@@ -2014,6 +2014,10 @@ int reply_received( struct sip_msg  *p_msg )
 			switch_rb_retr_to_t2(&uac->request);
 		}
 	}
+	/* pre-set the ignore BLST_503 flag in the message, if the
+	   corresponding branch had it set on send */
+	p_msg->fwd_send_flags.blst_imask|=
+		uac->request.dst.send_flags.blst_imask & BLST_503;
 	/* processing of on_reply block */
 	if (t->on_reply) {
 		set_route_type(ONREPLY_ROUTE);
@@ -2062,10 +2066,13 @@ int reply_received( struct sip_msg  *p_msg )
 	}
 #ifdef USE_DST_BLACKLIST
 		/* add temporary to the blacklist the source of a 503 reply */
-		if (cfg_get(tm, tm_cfg, tm_blst_503)
-			&& cfg_get(core, core_cfg, use_dst_blacklist)
-			&& (msg_status==503)
-		){
+		if (	(msg_status==503) &&
+				cfg_get(tm, tm_cfg, tm_blst_503) &&
+				/* check if the request sent on the branch had the the
+				   blst 503 ignore flags set or it was set in the onreply_r*/
+				should_blacklist_su(BLST_503, &p_msg->fwd_send_flags,
+										p_msg->rcv.proto, &p_msg->rcv.src_su)
+			){
 			blst_503_timeout=cfg_get(tm, tm_cfg, tm_blst_503_default);
 			if ((parse_headers(p_msg, HDR_RETRY_AFTER_F, 0)==0) && 
 				(p_msg->parsed_flag & HDR_RETRY_AFTER_F)){
@@ -2081,12 +2088,9 @@ int reply_received( struct sip_msg  *p_msg )
 					}
 			}
 			if (blst_503_timeout){
-				src.send_sock=0;
-				src.to=p_msg->rcv.src_su;
-				src.id=p_msg->rcv.proto_reserved1;
-				src.proto=p_msg->rcv.proto;
-				dst_blacklist_add_to(BLST_503, &src,  p_msg, 
-									S_TO_TICKS(blst_503_timeout));
+				dst_blacklist_force_su_to(BLST_503, p_msg->rcv.proto,
+											&p_msg->rcv.src_su, p_msg,
+											S_TO_TICKS(blst_503_timeout));
 			}
 		}
 #endif /* USE_DST_BLACKLIST */

+ 4 - 4
modules/tm/timer.c

@@ -478,13 +478,13 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
 	){
 		/* no reply received */
 #ifdef USE_DST_BLACKLIST
-		if (cfg_get(core, core_cfg, use_dst_blacklist)
-        		&& r_buf->my_T
+		if (r_buf->my_T
 			&& r_buf->my_T->uas.request
-			&& (r_buf->my_T->uas.request->REQ_METHOD & cfg_get(tm, tm_cfg, tm_blst_methods_add))
+			&& (r_buf->my_T->uas.request->REQ_METHOD &
+					cfg_get(tm, tm_cfg, tm_blst_methods_add))
 		)
 			dst_blacklist_add( BLST_ERR_TIMEOUT, &r_buf->dst,
-						r_buf->my_T->uas.request);
+								r_buf->my_T->uas.request);
 #endif
 #ifdef USE_DNS_FAILOVER
 		/* if this is an invite, the destination resolves to more ips, and

+ 5 - 3
modules/tm/uac.c

@@ -215,6 +215,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 	int sflag_bk;
 	int backup_route_type;
 #endif
+	snd_flags_t snd_flags;
 
 	ret=-1;
 	hi=0; /* make gcc happy */
@@ -239,10 +240,11 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 			uac_r->dialog->hooks.next_hop->s);
 	/* new message => take the dialog send_socket if set, or the default
 	  send_socket if not*/
+	SND_FLAGS_INIT(&snd_flags);
 #ifdef USE_DNS_FAILOVER
 	if (cfg_get(core, core_cfg, use_dns_failover)){
 		dns_srv_handle_init(&dns_h);
-		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, 0,
+		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, snd_flags,
 							uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
 				|| (dst.send_sock==0)){
 			dns_srv_handle_put(&dns_h);
@@ -253,7 +255,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 		}
 		dns_srv_handle_put(&dns_h); /* not needed anymore */
 	}else{
-		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, 0,
+		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, snd_flags,
 						uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 				(dst.send_sock==0)){
 			ser_error = E_NO_SOCKET;
@@ -263,7 +265,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 		}
 	}
 #else /* USE_DNS_FAILOVER */
-	if ((uri2dst2(&dst, uac_r->dialog->send_sock, 0,
+	if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags,
 					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
 			(dst.send_sock==0)){
 		ser_error = E_NO_SOCKET;

+ 12 - 4
modules/tm/ut.h

@@ -356,16 +356,24 @@ inline static struct dest_info *uri2dst(struct dns_srv_handle* dns_h,
 										struct sip_msg *msg, str *uri, 
 											int proto )
 {
-	return uri2dst2(dns_h, dst, msg?msg->force_send_socket:0,
-						msg?msg->fwd_send_flags:0, uri, proto);
+	snd_flags_t sflags;
+	if (msg)
+		return uri2dst2(dns_h, dst, msg->force_send_socket,
+							msg->fwd_send_flags, uri, proto);
+	SND_FLAGS_INIT(&sflags);
+	return uri2dst2(dns_h, dst, 0, sflags, uri, proto);
 }
 #else
 inline static struct dest_info *uri2dst(struct dest_info* dst,
 										struct sip_msg *msg, str *uri, 
 											int proto )
 {
-	return uri2dst2(dst, msg?msg->force_send_socket:0,
-						msg?msg->fwd_send_flags:0, uri, proto);
+	snd_flags_t sflags;
+	if (msg)
+		return uri2dst2(dst, msg->force_send_socket, msg->fwd_send_flags,
+						uri, proto);
+	SND_FLAGS_INIT(&sflags);
+	return uri2dst2(dst, 0, sflags, uri, proto);
 }
 #endif /* USE_DNS_FAILOVER */
 

+ 47 - 0
modules_s/blst/README

@@ -16,6 +16,11 @@ Andrei Pelinescu-Onciul
         1.2.2. blst_add_retry_after(min, max)
         1.2.3. blst_del()
         1.2.4. blst_is_blacklisted()
+        1.2.5. blst_set_ignore() blst_set_ignore(flags)
+                blst_rpl_set_ignore() blst_rpl_set_ignore(flags)
+
+        1.2.6. blst_clear_ignore() blst_clear_ignore(flags)
+                blst_rpl_clear_ignore() blst_rpl_clear_ignore(flags)
 
 1.1. Overview
 
@@ -80,3 +85,45 @@ if (msg_status==503){ # blacklist 503 source for Retry-After seconds
         drop;
    }
 ...
+
+1.2.5.  blst_set_ignore() blst_set_ignore(flags) blst_rpl_set_ignore()
+blst_rpl_set_ignore(flags)
+
+   Set errors that will not be taken into account when deciding whether or
+   not to blacklist a destination for the current message or a local reply
+   to the current message.
+
+   blst_set_ignore(..) works for forwarding the current message and
+   blst_rpl_set_ignore(...) works for local replies to the current
+   message.
+
+   The variants with no parameters will ignore everything (equivalent with
+   passing 0xff).
+
+   The following flags are defined:
+     * 0x02 - generic send error (send denied/ failed).
+     * 0x04 - connect failed (TCP, TLS or SCTP).
+     * 0x08 - ICMP error (not currently used).
+     * 0x10 - SIP transaction timeout.
+     * 0x20 - 503 reply (statefull mode only). For more details see
+       tmblst_503.
+
+Note
+
+   TCP and TLS send and connect errors are handled per connection and not
+   per message. The connection blacklist ignore flags are inherithed from
+   the message that caused the connection establishment.
+
+   Example 5. blst_set_ignore usage
+    blst_set_ignore(6); # ignore send and connect errors
+
+1.2.6.  blst_clear_ignore() blst_clear_ignore(flags) blst_rpl_clear_ignore()
+blst_rpl_clear_ignore(flags)
+
+   Clears blacklist ignore flags previously set by the corresponding
+   blst_set_ignore(...) or blst_rpl_set_ignore(...) functions.
+
+   See also blst_set_ignore.
+
+   Example 6. blst_clear_ignore usage
+    blst_clear_ignore(4); # ignore connect errors

+ 109 - 7
modules_s/blst/blst.c

@@ -45,6 +45,10 @@ static int blst_add_f(struct sip_msg*, char*, char*);
 static int blst_add_retry_after_f(struct sip_msg*, char*, char*);
 static int blst_del_f(struct sip_msg*, char*, char*);
 static int blst_is_blacklisted_f(struct sip_msg*, char*, char*);
+static int blst_set_ignore_f(struct sip_msg*, char*, char*);
+static int blst_clear_ignore_f(struct sip_msg*, char*, char*);
+static int blst_rpl_set_ignore_f(struct sip_msg*, char*, char*);
+static int blst_rpl_clear_ignore_f(struct sip_msg*, char*, char*);
 
 
 
@@ -59,6 +63,22 @@ static cmd_export_t cmds[]={
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
 	{"blst_is_blacklisted",   blst_is_blacklisted_f, 0, 0,
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
+	{"blst_set_ignore",         blst_set_ignore_f,   0,  0,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
+	{"blst_set_ignore",         blst_set_ignore_f,   1,  fixup_var_int_1,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
+	{"blst_clear_ignore",         blst_clear_ignore_f,   0,  0,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
+	{"blst_clear_ignore",         blst_clear_ignore_f,   1,  fixup_var_int_1,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
+	{"blst_rpl_set_ignore",       blst_rpl_set_ignore_f, 0,  0,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
+	{"blst_rpl_set_ignore",      blst_rpl_set_ignore_f,  1,  fixup_var_int_1,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
+	{"blst_rpl_clear_ignore",   blst_rpl_clear_ignore_f, 0,  0,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
+	{"blst_rpl_clear_ignore",   blst_rpl_clear_ignore_f, 1,  fixup_var_int_1,
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
 	{0,0,0,0,0}
 };
 
@@ -90,16 +110,15 @@ static int blst_add_f(struct sip_msg* msg, char* to, char* foo)
 		t=0;
 		if (unlikely( to && (get_int_fparam(&t, msg, (fparam_t*)to)<0)))
 			return -1;
-	
+		if (t==0)
+			t=cfg_get(core, core_cfg, blst_timeout);
+		init_dest_info(&src);
 		src.send_sock=0;
 		src.to=msg->rcv.src_su;
 		src.id=msg->rcv.proto_reserved1;
 		src.proto=msg->rcv.proto;
-		if (t)
-			dst_blacklist_add_to(BLST_ADM_PROHIBITED, &src, msg,
+		dst_blacklist_force_add_to(BLST_ADM_PROHIBITED, &src, msg,
 									S_TO_TICKS(t));
-		else
-			dst_blacklist_add(BLST_ADM_PROHIBITED, &src, msg);
 		return 1;
 	}else{
 		LOG(L_WARN, "WARNING: blst: blst_add: blacklist support disabled\n");
@@ -130,6 +149,7 @@ static int blst_add_retry_after_f(struct sip_msg* msg, char* min, char* max)
 			t_max=0;
 		}
 	
+		init_dest_info(&src);
 		src.send_sock=0;
 		src.to=msg->rcv.src_su;
 		src.id=msg->rcv.proto_reserved1;
@@ -150,8 +170,8 @@ static int blst_add_retry_after_f(struct sip_msg* msg, char* min, char* max)
 		t=MAX_unsigned(t, t_min);
 		t=MIN_unsigned(t, t_max);
 		if (likely(t))
-			dst_blacklist_add_to(BLST_ADM_PROHIBITED, &src, msg,
-									S_TO_TICKS(t));
+			dst_blacklist_force_add_to(BLST_ADM_PROHIBITED, &src, msg,
+										S_TO_TICKS(t));
 		return 1;
 	}else{
 		LOG(L_WARN, "WARNING: blst: blst_add_retry_after:"
@@ -173,6 +193,7 @@ static int blst_del_f(struct sip_msg* msg, char* foo, char* bar)
 	
 	if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
 	
+		init_dest_info(&src);
 		src.send_sock=0;
 		src.to=msg->rcv.src_su;
 		src.id=msg->rcv.proto_reserved1;
@@ -197,6 +218,7 @@ static int blst_is_blacklisted_f(struct sip_msg* msg, char* foo, char* bar)
 	struct dest_info src;
 	
 	if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
+		init_dest_info(&src);
 		src.send_sock=0;
 		src.to=msg->rcv.src_su;
 		src.id=msg->rcv.proto_reserved1;
@@ -213,3 +235,83 @@ static int blst_is_blacklisted_f(struct sip_msg* msg, char* foo, char* bar)
 #endif /* USE_DST_BLACKLIST */
 	return -1;
 }
+
+
+
+static int blst_set_ignore_f(struct sip_msg* msg, char* flags, char* foo)
+{
+#ifdef USE_DST_BLACKLIST
+	unsigned char blst_imask;
+	int mask;
+	
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
+		return -1;
+	blst_imask=flags?mask:0xff;
+	msg->fwd_send_flags.blst_imask|=blst_imask;
+	return 1;
+#else /* USE_DST_BLACKLIST */
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
+				" not compiled-in - no effect -\n");
+#endif /* USE_DST_BLACKLIST */
+	return 1;
+}
+
+
+
+static int blst_clear_ignore_f(struct sip_msg* msg, char* flags, char* foo)
+{
+#ifdef USE_DST_BLACKLIST
+	unsigned char blst_imask;
+	int mask;
+	
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
+		return -1;
+	blst_imask=flags?mask:0xff;
+	msg->fwd_send_flags.blst_imask&=~blst_imask;
+	return 1;
+#else /* USE_DST_BLACKLIST */
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
+				" not compiled-in - no effect -\n");
+#endif /* USE_DST_BLACKLIST */
+	return 1;
+}
+
+
+
+static int blst_rpl_set_ignore_f(struct sip_msg* msg, char* flags, char* foo)
+{
+#ifdef USE_DST_BLACKLIST
+	unsigned char blst_imask;
+	int mask;
+	
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
+		return -1;
+	blst_imask=flags?mask:0xff;
+	msg->rpl_send_flags.blst_imask|=blst_imask;
+	return 1;
+#else /* USE_DST_BLACKLIST */
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
+				" not compiled-in - no effect -\n");
+#endif /* USE_DST_BLACKLIST */
+	return 1;
+}
+
+
+
+static int blst_rpl_clear_ignore_f(struct sip_msg* msg, char* flags, char* foo)
+{
+#ifdef USE_DST_BLACKLIST
+	unsigned char blst_imask;
+	int mask;
+	
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
+		return -1;
+	blst_imask=flags?mask:0xff;
+	msg->rpl_send_flags.blst_imask&=~blst_imask;
+	return 1;
+#else /* USE_DST_BLACKLIST */
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
+				" not compiled-in - no effect -\n");
+#endif /* USE_DST_BLACKLIST */
+	return 1;
+}

+ 80 - 0
modules_s/blst/doc/functions.xml

@@ -108,4 +108,84 @@ if (msg_status==503){ # blacklist 503 source for Retry-After seconds
 	</example>
     </section>
 
+	<section id="blst_set_ignore">
+	<title>
+		<function>blst_set_ignore()</function>
+		<function>blst_set_ignore(flags)</function>
+		<function>blst_rpl_set_ignore()</function>
+		<function>blst_rpl_set_ignore(flags)</function>
+	</title>
+	<para>
+		Set errors that will not be taken into account when deciding
+		whether or not to blacklist a destination for the current message
+		or a local reply to the current message.
+	</para>
+	<para>
+		<function>blst_set_ignore(..)</function> works for forwarding the
+		current message and <function>blst_rpl_set_ignore(...)</function>
+		works for local replies to the current message.
+	</para>
+	<para>
+		The variants with no parameters will ignore everything (equivalent
+		with passing 0xff).
+	</para>
+	<para>
+		The following flags are defined:
+		<itemizedlist>
+			<listitem>
+				<emphasis>0x02</emphasis> - generic send error (send denied/
+				 failed).
+			</listitem>
+			<listitem>
+				<emphasis>0x04</emphasis> - connect failed (TCP, TLS or SCTP).
+			</listitem>
+			<listitem>
+				<emphasis>0x08</emphasis> - ICMP error (not currently used).
+			</listitem>
+			<listitem>
+				<emphasis>0x10</emphasis> - SIP transaction timeout.
+			</listitem>
+			<listitem>
+				<emphasis>0x20</emphasis> - 503 reply (statefull mode only).
+				For more details see <emphasis>tm</emphasis>
+				<varname>blst_503</varname>.
+			</listitem>
+		</itemizedlist>
+	</para>
+	<note>
+		TCP and TLS send and connect errors are handled per connection and
+		not per message. The connection blacklist ignore flags are inherithed
+		from the message that caused the connection establishment.
+	</note>
+	<example>
+		<title><function>blst_set_ignore</function> usage</title>
+		<programlisting>
+    blst_set_ignore(6); # ignore send and connect errors
+		</programlisting>
+	</example>
+	</section>
+
+	<section id="blst_clear_ignore">
+	<title>
+		<function>blst_clear_ignore()</function>
+		<function>blst_clear_ignore(flags)</function>
+		<function>blst_rpl_clear_ignore()</function>
+		<function>blst_rpl_clear_ignore(flags)</function>
+	</title>
+	<para>
+		Clears blacklist ignore flags previously set by the corresponding
+		<function>blst_set_ignore(...)</function> or
+		<function>blst_rpl_set_ignore(...)</function> functions.
+	</para>
+	<para>
+		See also <function>blst_set_ignore</function>.
+	</para>
+	<example>
+		<title><function>blst_clear_ignore</function> usage</title>
+	    <programlisting>
+    blst_clear_ignore(4); # ignore connect errors
+		</programlisting>
+	</example>
+	</section>
+
 </section>

+ 2 - 2
parser/msg_parser.h

@@ -448,9 +448,9 @@ void reset_path_vector(struct sip_msg* msg);
 	do { \
 		(msg)->force_send_socket=(fsocket); \
 		if ((msg)->force_send_socket) \
-			(msg)->fwd_send_flags |= SND_F_FORCE_SOCKET; \
+			(msg)->fwd_send_flags.f |= SND_F_FORCE_SOCKET; \
 		else \
-			(msg)->fwd_send_flags &= ~SND_F_FORCE_SOCKET; \
+			(msg)->fwd_send_flags.f &= ~SND_F_FORCE_SOCKET; \
 	} while (0)
 
 /** reset a previously forced send socket. */

+ 6 - 9
sctp_server.c

@@ -2133,13 +2133,12 @@ static int sctp_handle_send_failed(struct socket_info* si,
 		ret=sctp_msg_send_ext(&dst, data, data_len, &sinfo);
 	}
 #ifdef USE_DST_BLACKLIST
-	 else if (cfg_get(core, core_cfg, use_dst_blacklist) &&
-					cfg_get(sctp, sctp_cfg, send_retries)) {
+	 else if (cfg_get(sctp, sctp_cfg, send_retries)) {
 		/* blacklist only if send_retries is on, if off we blacklist
 		   from SCTP_ASSOC_CHANGE: SCTP_COMM_LOST/SCTP_CANT_STR_ASSOC
 		   which is better (because we can tell connect errors from send
 		   errors and we blacklist a failed dst only once) */
-		dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0);
+		dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
 	}
 #endif /* USE_DST_BLACKLIST */
 	
@@ -2220,9 +2219,8 @@ again:
 #ifdef USE_DST_BLACKLIST
 			/* blacklist only if send_retries is turned off (if on we don't
 			   know here if we did retry or we are at the first error) */
-			if (cfg_get(core, core_cfg, use_dst_blacklist) &&
-					(cfg_get(sctp, sctp_cfg, send_retries)==0))
-						dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0);
+			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
+						dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
 #endif /* USE_DST_BLACKLIST */
 			/* no break */
 			goto comm_lost_cont;	/* do not increment counters for
@@ -2254,9 +2252,8 @@ comm_lost_cont:
 #ifdef USE_DST_BLACKLIST
 			/* blacklist only if send_retries is turned off (if on we don't 
 			   know here if we did retry or we are at the first error) */
-			if (cfg_get(core, core_cfg, use_dst_blacklist) &&
-					(cfg_get(sctp, sctp_cfg, send_retries)==0))
-						dst_blacklist_su(BLST_ERR_CONNECT, PROTO_SCTP, su, 0);
+			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
+					dst_blacklist_su(BLST_ERR_CONNECT, PROTO_SCTP, su, 0, 0);
 #endif /* USE_DST_BLACKLIST */
 			break;
 		default:

+ 4 - 3
tcp_conn.h

@@ -172,7 +172,7 @@ struct tcp_connection{
 	atomic_t refcnt;
 	enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */
 	unsigned short flags; /* connection related flags */
-	unsigned short send_flags; /* special send flags */
+	snd_flags_t send_flags; /* special send flags */
 	enum tcp_conn_states state; /* connection state */
 	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
 	struct timer_ln timer;
@@ -192,9 +192,10 @@ struct tcp_connection{
 
 /* helper macros */
 
-#define tcpconn_set_send_flags(c, snd_flags) ((c)->send_flags|=(snd_flags))
+#define tcpconn_set_send_flags(c, snd_flags) \
+	SND_FLAGS_OR(&(c)->send_flags, &(c)->send_flags, &(snd_flags))
 
-#define tcpconn_close_after_send(c)	((c)->send_flags & SND_F_CON_CLOSE)
+#define tcpconn_close_after_send(c)	((c)->send_flags.f & SND_F_CON_CLOSE)
 
 #define TCP_RCV_INFO(c) (&(c)->rcv)
 

+ 70 - 83
tcp_main.c

@@ -484,7 +484,7 @@ error:
  * if BLOCKING_USE_SELECT and HAVE_SELECT are defined it will internally
  * use select() instead of poll (bad if fd > FD_SET_SIZE, poll is preferred)
  */
-static int tcp_blocking_connect(int fd, int type,
+static int tcp_blocking_connect(int fd, int type, snd_flags_t* send_flags,
 								const struct sockaddr *servaddr,
 								socklen_t addrlen)
 {
@@ -577,18 +577,16 @@ error_errno:
 		case ENETUNREACH:
 		case EHOSTUNREACH:
 #ifdef USE_DST_BLACKLIST
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
-				dst_blacklist_su(BLST_ERR_CONNECT, type,
-							 (union sockaddr_union*)servaddr, 0);
+			dst_blacklist_su(BLST_ERR_CONNECT, type,
+							 (union sockaddr_union*)servaddr, send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 			TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0,
 							(union sockaddr_union*)servaddr, type);
 			break;
 		case ETIMEDOUT:
 #ifdef USE_DST_BLACKLIST
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
-				dst_blacklist_su(BLST_ERR_CONNECT, type,
-								 (union sockaddr_union*)servaddr, 0);
+			dst_blacklist_su(BLST_ERR_CONNECT, type,
+							 (union sockaddr_union*)servaddr, send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 			TCP_EV_CONNECT_TIMEOUT(errno, 0, 0,
 							(union sockaddr_union*)servaddr, type);
@@ -596,9 +594,8 @@ error_errno:
 		case ECONNREFUSED:
 		case ECONNRESET:
 #ifdef USE_DST_BLACKLIST
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
-				dst_blacklist_su(BLST_ERR_CONNECT, type,
-								 (union sockaddr_union*)servaddr, 0);
+			dst_blacklist_su(BLST_ERR_CONNECT, type,
+							 (union sockaddr_union*)servaddr, send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 			TCP_EV_CONNECT_RST(errno, 0, 0,
 							(union sockaddr_union*)servaddr, type);
@@ -618,9 +615,8 @@ error_errno:
 error_timeout:
 	/* timeout */
 #ifdef USE_DST_BLACKLIST
-	if (cfg_get(core, core_cfg, use_dst_blacklist))
-		dst_blacklist_su(BLST_ERR_CONNECT, type,
-							(union sockaddr_union*)servaddr, 0);
+	dst_blacklist_su(BLST_ERR_CONNECT, type,
+						(union sockaddr_union*)servaddr, send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 	TCP_EV_CONNECT_TIMEOUT(0, 0, 0, (union sockaddr_union*)servaddr, type);
 	LOG(L_ERR, "ERROR: tcp_blocking_connect %s: timeout %d s elapsed "
@@ -673,22 +669,16 @@ inline static int _wbufq_add(struct  tcp_connection* c, char* data,
 		if (q->first && TICKS_LT(q->wr_timeout, t)){
 			if (unlikely(c->state==S_CONN_CONNECT)){
 #ifdef USE_DST_BLACKLIST
-				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
-					DBG("blacklisting, state=%d\n", c->state);
-					dst_blacklist_su( BLST_ERR_CONNECT, c->rcv.proto,
-										&c->rcv.src_su, 0);
-				}
+				dst_blacklist_su( BLST_ERR_CONNECT, c->rcv.proto,
+										&c->rcv.src_su, &c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 				TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(c), TCP_LPORT(c),
 											TCP_PSU(c), TCP_PROTO(c));
 				TCP_STATS_CONNECT_FAILED();
 			}else{
 #ifdef USE_DST_BLACKLIST
-				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
-					DBG("blacklisting, state=%d\n", c->state);
-					dst_blacklist_su( BLST_ERR_SEND, c->rcv.proto,
-										&c->rcv.src_su, 0);
-				}
+				dst_blacklist_su( BLST_ERR_SEND, c->rcv.proto,
+									&c->rcv.src_su, &c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 				TCP_EV_SEND_TIMEOUT(0, &c->rcv);
 				TCP_STATS_SEND_TIMEOUT();
@@ -872,10 +862,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
 							case ENETUNREACH:
 							case EHOSTUNREACH: /* not posix for send() */
 #ifdef USE_DST_BLACKLIST
-								if (cfg_get(core, core_cfg, use_dst_blacklist))
-									dst_blacklist_su(BLST_ERR_CONNECT,
-															c->rcv.proto,
-															&c->rcv.src_su, 0);
+								dst_blacklist_su(BLST_ERR_CONNECT,
+													c->rcv.proto,
+													&c->rcv.src_su,
+													&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 								TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
 													TCP_LPORT(c), TCP_PSU(c),
@@ -884,10 +874,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
 							case ECONNREFUSED:
 							case ECONNRESET:
 #ifdef USE_DST_BLACKLIST
-								if (cfg_get(core, core_cfg, use_dst_blacklist))
-									dst_blacklist_su(BLST_ERR_CONNECT,
-															c->rcv.proto,
-															&c->rcv.src_su, 0);
+								dst_blacklist_su(BLST_ERR_CONNECT,
+													c->rcv.proto,
+													&c->rcv.src_su,
+													&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 								TCP_EV_CONNECT_RST(0, TCP_LADDR(c),
 													TCP_LPORT(c), TCP_PSU(c),
@@ -908,10 +898,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
 							case ENETUNREACH:
 							case EHOSTUNREACH: /* not posix for send() */
 #ifdef USE_DST_BLACKLIST
-								if (cfg_get(core, core_cfg, use_dst_blacklist))
-									dst_blacklist_su(BLST_ERR_SEND,
-														c->rcv.proto,
-														&c->rcv.src_su, 0);
+								dst_blacklist_su(BLST_ERR_SEND,
+													c->rcv.proto,
+													&c->rcv.src_su,
+													&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 								break;
 						}
@@ -1090,6 +1080,7 @@ error:
 inline static int tcp_do_connect(	union sockaddr_union* server,
 									union sockaddr_union* from,
 									int type,
+									snd_flags_t* send_flags,
 									union sockaddr_union* res_local_addr,
 									struct socket_info** res_si,
 									enum tcp_conn_states *state
@@ -1134,23 +1125,23 @@ again:
 					case ENETUNREACH:
 					case EHOSTUNREACH:
 #ifdef USE_DST_BLACKLIST
-						if (cfg_get(core, core_cfg, use_dst_blacklist))
-							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
+						dst_blacklist_su(BLST_ERR_CONNECT, type, server,
+											send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 						TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0, server, type);
 						break;
 					case ETIMEDOUT:
 #ifdef USE_DST_BLACKLIST
-						if (cfg_get(core, core_cfg, use_dst_blacklist))
-							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
+						dst_blacklist_su(BLST_ERR_CONNECT, type, server,
+											send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 						TCP_EV_CONNECT_TIMEOUT(errno, 0, 0, server, type);
 						break;
 					case ECONNREFUSED:
 					case ECONNRESET:
 #ifdef USE_DST_BLACKLIST
-						if (cfg_get(core, core_cfg, use_dst_blacklist))
-							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
+						dst_blacklist_su(BLST_ERR_CONNECT, type, server,
+											send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 						TCP_EV_CONNECT_RST(errno, 0, 0, server, type);
 						break;
@@ -1169,7 +1160,7 @@ again:
 		}
 	}else{
 #endif /* TCP_ASYNC */
-		if (tcp_blocking_connect(s, type, &server->s,
+		if (tcp_blocking_connect(s, type,  send_flags, &server->s,
 									sockaddru_len(*server))<0){
 			LOG(L_ERR, "ERROR: tcp_do_connect: tcp_blocking_connect %s"
 						" failed\n", su2a(server, sizeof(*server)));
@@ -1219,9 +1210,9 @@ error:
 
 
 
-struct tcp_connection* tcpconn_connect( union sockaddr_union* server, 
+struct tcp_connection* tcpconn_connect( union sockaddr_union* server,
 										union sockaddr_union* from,
-										int type)
+										int type, snd_flags_t* send_flags)
 {
 	int s;
 	struct socket_info* si;
@@ -1238,7 +1229,7 @@ struct tcp_connection* tcpconn_connect( union sockaddr_union* server,
 					cfg_get(tcp, tcp_cfg, max_connections));
 		goto error;
 	}
-	s=tcp_do_connect(server, from, type, &my_name, &si, &state);
+	s=tcp_do_connect(server, from, type,  send_flags, &my_name, &si, &state);
 	if (s==-1){
 		LOG(L_ERR, "ERROR: tcp_do_connect %s: failed (%d) %s\n",
 				su2a(server, sizeof(*server)), errno, strerror(errno));
@@ -1250,6 +1241,7 @@ struct tcp_connection* tcpconn_connect( union sockaddr_union* server,
 				 " socket\n", su2a(server, sizeof(*server)));
 		goto error;
 	}
+	tcpconn_set_send_flags(con, *send_flags);
 	return con;
 	/*FIXME: set sock idx! */
 error:
@@ -1271,7 +1263,8 @@ int tcpconn_finish_connect( struct tcp_connection* c,
 	struct tcp_conn_alias* a;
 	int new_conn_alias_flags;
 	
-	s=tcp_do_connect(&c->rcv.src_su, from, c->type, &local_addr, &si, &state);
+	s=tcp_do_connect(&c->rcv.src_su, from, c->type, &c->send_flags,
+						&local_addr, &si, &state);
 	if (unlikely(s==-1)){
 		LOG(L_ERR, "ERROR: tcpconn_finish_connect %s: tcp_do_connect for %p"
 					" failed\n", su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)),
@@ -1787,7 +1780,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 				c=0;
 			}
 			/* check if connect() is disabled */
-			if (unlikely((dst->send_flags & SND_F_FORCE_CON_REUSE) ||
+			if (unlikely((dst->send_flags.f & SND_F_FORCE_CON_REUSE) ||
 							cfg_get(tcp, tcp_cfg, no_connect)))
 				return -1;
 			DBG("tcp_send: no open tcp connection found, opening new one\n");
@@ -1905,8 +1898,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 						case ENETUNREACH:
 						case EHOSTUNREACH:  /* not posix for send() */
 #ifdef USE_DST_BLACKLIST
-							if (cfg_get(core, core_cfg, use_dst_blacklist))
-								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
+							dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
 #endif /* USE_DST_BLACKLIST */
 							TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
@@ -1914,8 +1906,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 						case ECONNREFUSED:
 						case ECONNRESET:
 #ifdef USE_DST_BLACKLIST
-							if (cfg_get(core, core_cfg, use_dst_blacklist))
-								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
+							dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
 #endif /* USE_DST_BLACKLIST */
 							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
@@ -1934,7 +1925,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 				}
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
 				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
-				if (unlikely(dst->send_flags & SND_F_CON_CLOSE)){
+				if (unlikely(dst->send_flags.f & SND_F_CON_CLOSE)){
 					/* if close-after-send requested, don't bother
 					   sending the fd back to tcp_main, try closing it
 					   immediately (no other tcp_send should use it,
@@ -1957,7 +1948,8 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 				goto end;
 			}
 #endif /* TCP_CONNECT_WAIT  && TCP_ASYNC */
-			if (unlikely((c=tcpconn_connect(&dst->to, from, dst->proto))==0)){
+			if (unlikely((c=tcpconn_connect(&dst->to, from, dst->proto,
+											&dst->send_flags))==0)){
 				LOG(L_ERR, "ERROR: tcp_send %s: connect failed\n",
 								su2a(&dst->to, sizeof(dst->to)));
 				return -1;
@@ -2150,9 +2142,8 @@ send_it:
 				case ENETUNREACH:
 				case EHOSTUNREACH: /* not posix for send() */
 #ifdef USE_DST_BLACKLIST
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
-						dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
-											&c->rcv.src_su, 0);
+					dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
+										&c->rcv.src_su, &c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 					TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
@@ -2160,9 +2151,8 @@ send_it:
 				case ECONNREFUSED:
 				case ECONNRESET:
 #ifdef USE_DST_BLACKLIST
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
-						dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
-											&c->rcv.src_su, 0);
+					dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
+										&c->rcv.src_su, &c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 					TCP_EV_CONNECT_RST(errno, TCP_LADDR(c), TCP_LPORT(c),
 										TCP_PSU(c), TCP_PROTO(c));
@@ -2181,9 +2171,8 @@ send_it:
 				case ENETUNREACH:
 				/*case EHOSTUNREACH: -- not posix */
 #ifdef USE_DST_BLACKLIST
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
-						dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
-												&c->rcv.src_su, 0);
+					dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
+										&c->rcv.src_su, &c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 					break;
 			}
@@ -2231,7 +2220,7 @@ error:
 			TCP_STATS_ESTABLISHED(c->state);
 			c->state=S_CONN_OK;
 	}
-	if (unlikely(dst->send_flags & SND_F_CON_CLOSE)){
+	if (unlikely(dst->send_flags.f & SND_F_CON_CLOSE)){
 		/* close after write => send EOF request to tcp_main */
 		c->state=S_CONN_BAD;
 		c->timeout=get_ticks_raw();
@@ -2903,10 +2892,10 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
 					/* timeout */
 					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,
-													&tcpconn->rcv.src_su, 0);
+						dst_blacklist_su( BLST_ERR_CONNECT,
+											tcpconn->rcv.proto,
+											&tcpconn->rcv.src_su,
+											&tcpconn->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 						TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(tcpconn),
 										TCP_LPORT(tcpconn), TCP_PSU(tcpconn),
@@ -2914,10 +2903,10 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
 						TCP_STATS_CONNECT_FAILED();
 					}else{
 #ifdef USE_DST_BLACKLIST
-						if (cfg_get(core, core_cfg, use_dst_blacklist))
-							dst_blacklist_su( BLST_ERR_SEND,
-													tcpconn->rcv.proto,
-													&tcpconn->rcv.src_su, 0);
+						dst_blacklist_su( BLST_ERR_SEND,
+											tcpconn->rcv.proto,
+											&tcpconn->rcv.src_su,
+											&tcpconn->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 						TCP_EV_SEND_TIMEOUT(0, &tcpconn->rcv);
 						TCP_STATS_SEND_TIMEOUT();
@@ -3560,9 +3549,9 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
 			if (unlikely(ev & POLLERR)){
 				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,
-											&tcpconn->rcv.src_su, 0);
+					dst_blacklist_su(BLST_ERR_CONNECT, tcpconn->rcv.proto,
+										&tcpconn->rcv.src_su,
+										&tcpconn->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 					TCP_EV_CONNECT_ERR(0, TCP_LADDR(tcpconn),
 										TCP_LPORT(tcpconn), TCP_PSU(tcpconn),
@@ -3570,9 +3559,9 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
 					TCP_STATS_CONNECT_FAILED();
 				}else{
 #ifdef USE_DST_BLACKLIST
-					if (cfg_get(core, core_cfg, use_dst_blacklist))
-						dst_blacklist_su(BLST_ERR_SEND, tcpconn->rcv.proto,
-											&tcpconn->rcv.src_su, 0);
+					dst_blacklist_su(BLST_ERR_SEND, tcpconn->rcv.proto,
+										&tcpconn->rcv.src_su,
+										&tcpconn->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 					TCP_STATS_CON_RESET(); /* FIXME: it could != RST */
 				}
@@ -3747,18 +3736,16 @@ static ticks_t tcpconn_main_timeout(ticks_t t, struct timer_ln* tl, void* data)
 	if (tcp_async && _wbufq_non_empty(c) && TICKS_GE(t, c->wbuf_q.wr_timeout)){
 		if (unlikely(c->state==S_CONN_CONNECT)){
 #ifdef USE_DST_BLACKLIST
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
-				dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
-									&c->rcv.src_su, 0);
+			dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto, &c->rcv.src_su,
+								&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 			TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(c), TCP_LPORT(c), TCP_PSU(c),
 									TCP_PROTO(c));
 			TCP_STATS_CONNECT_FAILED();
 		}else{
 #ifdef USE_DST_BLACKLIST
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
-				dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
-									&c->rcv.src_su, 0);
+			dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto, &c->rcv.src_su,
+								&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 			TCP_EV_SEND_TIMEOUT(0, &c->rcv);
 			TCP_STATS_SEND_TIMEOUT();

+ 10 - 13
tcp_read.c

@@ -160,20 +160,18 @@ again:
 					switch(errno){
 						case ECONNRESET:
 #ifdef USE_DST_BLACKLIST
-							if (cfg_get(core, core_cfg, use_dst_blacklist))
-								dst_blacklist_su(BLST_ERR_CONNECT,
-														c->rcv.proto,
-														&c->rcv.src_su, 0);
+							dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
+												&c->rcv.src_su,
+												&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
 							break;
 						case ETIMEDOUT:
 #ifdef USE_DST_BLACKLIST
-							if (cfg_get(core, core_cfg, use_dst_blacklist))
-								dst_blacklist_su(BLST_ERR_CONNECT,
-														c->rcv.proto,
-														&c->rcv.src_su, 0);
+							dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
+												&c->rcv.src_su,
+												&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 							TCP_EV_CONNECT_TIMEOUT(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
@@ -189,10 +187,9 @@ again:
 								TCP_STATS_CON_RESET();
 							case ETIMEDOUT:
 #ifdef USE_DST_BLACKLIST
-								if (cfg_get(core, core_cfg, use_dst_blacklist))
-									dst_blacklist_su(BLST_ERR_SEND,
-														c->rcv.proto,
-														&c->rcv.src_su, 0);
+								dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
+													&c->rcv.src_su,
+													&c->send_flags, 0);
 #endif /* USE_DST_BLACKLIST */
 								break;
 						}
@@ -971,7 +968,7 @@ again:
 			con=(struct tcp_connection*)fm->data;
 			if (unlikely(con->state==S_CONN_BAD)){
 				resp=CONN_ERROR;
-				if (!(con->send_flags & SND_F_CON_CLOSE))
+				if (!(con->send_flags.f & SND_F_CON_CLOSE))
 					LOG(L_WARN, "WARNING: tcp_receive: handle_io: F_TCPCONN"
 							" connection marked as bad: %p id %d refcnt %d\n",
 							con, con->id, atomic_get(&con->refcnt));