Browse code

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 authored on 19/02/2010 15:37:51
Showing 24 changed files
... ...
@@ -3,7 +3,43 @@ Release notes for SIP Router (sr)
3 3
 
4 4
 $Id$
5 5
 
6
-sip-router changes
6
+sip-router 3.1 chages
7
+
8
+core:
9
+  - global, per protocol blacklist ignore masks (via extended send_flags).
10
+    See dst_blacklist_udp_imask a.s.o (dst_blacklist_*_imask).
11
+  - per message blacklist ignore masks
12
+
13
+new config variables:
14
+  - dst_blacklist_udp_imask - global blacklist events ignore mask for udp
15
+    (a blacklist event/reason set in this variable will be ignored when 
16
+    deciding whether or not to blacklist an udp destination). Can be set
17
+    at runtime. Default: 0 (no blacklist reason is ignored).
18
+    Possible values:  0 -disabled, 2 - send error; 4 - connect error,
19
+                      8 - icmp (reserverd), 16 - transaction timeout,
20
+                     32 - 503 received, 64 - administratively prohibited
21
+                     (manually set).
22
+   - dst_blacklist_tcp_imask - like dst_blacklist_udp_imask, but for tcp.
23
+   - dst_blacklist_tls_imask - like dst_blacklist_tls_imask, but for tcp.
24
+   - dst_blacklist_sctp_imask -like dst_blacklist_sctp_imask, but for tcp.
25
+
26
+modules:
27
+   - blst: functions for ignoring blacklist events per message:
28
+           blst_set_ignore(mask):  set the events in mask in the per
29
+            per message blacklist ignore mask for a request
30
+            (see dst_blacklist_udp_imask for possible values).
31
+            The basic operation is: msg_blst_ignore_mask|=mask.
32
+           blst_clear_ignore(mask): like blst_set_ignore(mask), but instead
33
+            of setting some events, it clears them
34
+            (msg_blst_ignore_mask&=~mask).
35
+           blst_rpl_set_ignore(mask): like blst_set_ignore(mask), but sets
36
+            the mask for possible local replies to the current message.
37
+           blst_rpl_clear_ignore(mask): like blst_rpl_ignore(mask), but
38
+            clears instead of setting.
39
+
40
+
41
+
42
+sip-router 3.0 changes
7 43
 
8 44
 core:
9 45
   - type casts operators: (int), (str).
... ...
@@ -66,6 +102,8 @@ config script changes:
66 66
   - event route support: event_route[module_name:eventid]
67 67
   - user and shm_force_alloc must now appear prior to any modparam() or route
68 68
      block.
69
+  - per message send_flags support (see set_forward_no_connect(),
70
+     set_forward_reply_no_connect(), set_forward_close() & set_reply_close())
69 71
 
70 72
 build system:
71 73
   - multiple modules directories are now supported (defined in Makefile.dirs)
... ...
@@ -1235,19 +1235,19 @@ match_cleanup:
1235 1235
 				ret=v;
1236 1236
 			break;
1237 1237
 		case SET_FWD_NO_CONNECT_T:
1238
-			msg->fwd_send_flags|= SND_F_FORCE_CON_REUSE;
1238
+			msg->fwd_send_flags.f|= SND_F_FORCE_CON_REUSE;
1239 1239
 			ret=1; /* continue processing */
1240 1240
 			break;
1241 1241
 		case SET_RPL_NO_CONNECT_T:
1242
-			msg->rpl_send_flags|= SND_F_FORCE_CON_REUSE;
1242
+			msg->rpl_send_flags.f|= SND_F_FORCE_CON_REUSE;
1243 1243
 			ret=1; /* continue processing */
1244 1244
 			break;
1245 1245
 		case SET_FWD_CLOSE_T:
1246
-			msg->fwd_send_flags|= SND_F_CON_CLOSE;
1246
+			msg->fwd_send_flags.f|= SND_F_CON_CLOSE;
1247 1247
 			ret=1; /* continue processing */
1248 1248
 			break;
1249 1249
 		case SET_RPL_CLOSE_T:
1250
-			msg->rpl_send_flags|= SND_F_CON_CLOSE;
1250
+			msg->rpl_send_flags.f|= SND_F_CON_CLOSE;
1251 1251
 			ret=1; /* continue processing */
1252 1252
 			break;
1253 1253
 /*
... ...
@@ -81,6 +81,7 @@
81 81
  *  2009-04-24  add strlen, strempty and defined operators (andrei)
82 82
  *  2009-03-07  RETCODE, it's now  a core pvar (andrei)
83 83
  *  2010-01-10  added SHM_MEM_SZ (andrei)
84
+ *  2010-02-17 added DST_BLST_{UDP,TCP,TLS,SCTP}_IMASK (andrei)
84 85
 */
85 86
 
86 87
 
... ...
@@ -358,6 +359,10 @@ USE_DST_BLST		use_dst_blacklist
358 358
 DST_BLST_MEM		dst_blacklist_mem
359 359
 DST_BLST_TTL		dst_blacklist_expire|dst_blacklist_ttl
360 360
 DST_BLST_GC_INT		dst_blacklist_gc_interval
361
+DST_BLST_UDP_IMASK	dst_blacklist_udp_imask
362
+DST_BLST_TCP_IMASK	dst_blacklist_tcp_imask
363
+DST_BLST_TLS_IMASK	dst_blacklist_tls_imask
364
+DST_BLST_SCTP_IMASK	dst_blacklist_sctp_imask
361 365
 
362 366
 
363 367
 PORT	port
... ...
@@ -703,6 +708,14 @@ EAT_ABLE	[\ \t\b\r]
703 703
 								return DST_BLST_TTL; }
704 704
 <INITIAL>{DST_BLST_GC_INT}	{ count(); yylval.strval=yytext;
705 705
 								return DST_BLST_GC_INT; }
706
+<INITIAL>{DST_BLST_UDP_IMASK}	{ count(); yylval.strval=yytext;
707
+								return DST_BLST_UDP_IMASK; }
708
+<INITIAL>{DST_BLST_TCP_IMASK}	{ count(); yylval.strval=yytext;
709
+								return DST_BLST_TCP_IMASK; }
710
+<INITIAL>{DST_BLST_TLS_IMASK}	{ count(); yylval.strval=yytext;
711
+								return DST_BLST_TLS_IMASK; }
712
+<INITIAL>{DST_BLST_SCTP_IMASK}	{ count(); yylval.strval=yytext;
713
+								return DST_BLST_SCTP_IMASK; }
706 714
 <INITIAL>{PORT}	{ count(); yylval.strval=yytext; return PORT; }
707 715
 <INITIAL>{STAT}	{ count(); yylval.strval=yytext; return STAT; }
708 716
 <INITIAL>{MAXBUFFER}	{ count(); yylval.strval=yytext; return MAXBUFFER; }
... ...
@@ -98,6 +98,7 @@
98 98
  * 2009-05-04  switched if to rval_expr (andrei)
99 99
  * 2010-01-10  init shm on first mod_param or route block;
100 100
  *             added SHM_MEM_SZ (andrei)
101
+ * 2010-02-17  added blacklist imask (DST_BLST_*_IMASK) support (andrei)
101 102
 */
102 103
 
103 104
 %{
... ...
@@ -403,6 +404,10 @@ extern char *finame;
403 403
 %token DST_BLST_MEM
404 404
 %token DST_BLST_TTL
405 405
 %token DST_BLST_GC_INT
406
+%token DST_BLST_UDP_IMASK
407
+%token DST_BLST_TCP_IMASK
408
+%token DST_BLST_TLS_IMASK
409
+%token DST_BLST_SCTP_IMASK
406 410
 
407 411
 %token PORT
408 412
 %token STAT
... ...
@@ -840,14 +845,36 @@ assign_stm:
840 840
 	| DNS_CACHE_DEL_NONEXP error { yyerror("boolean value expected"); }
841 841
 	| DST_BLST_INIT EQUAL NUMBER   { IF_DST_BLACKLIST(dst_blacklist_init=$3); }
842 842
 	| DST_BLST_INIT error { yyerror("boolean value expected"); }
843
-	| USE_DST_BLST EQUAL NUMBER   { IF_DST_BLACKLIST(default_core_cfg.use_dst_blacklist=$3); }
843
+	| USE_DST_BLST EQUAL NUMBER {
844
+		IF_DST_BLACKLIST(default_core_cfg.use_dst_blacklist=$3);
845
+	}
844 846
 	| USE_DST_BLST error { yyerror("boolean value expected"); }
845
-	| DST_BLST_MEM EQUAL NUMBER   { IF_DST_BLACKLIST(default_core_cfg.blst_max_mem=$3); }
847
+	| DST_BLST_MEM EQUAL NUMBER {
848
+		IF_DST_BLACKLIST(default_core_cfg.blst_max_mem=$3); 
849
+	}
846 850
 	| DST_BLST_MEM error { yyerror("boolean value expected"); }
847
-	| DST_BLST_TTL EQUAL NUMBER   { IF_DST_BLACKLIST(default_core_cfg.blst_timeout=$3); }
851
+	| DST_BLST_TTL EQUAL NUMBER {
852
+		IF_DST_BLACKLIST(default_core_cfg.blst_timeout=$3);
853
+	}
848 854
 	| DST_BLST_TTL error { yyerror("boolean value expected"); }
849 855
 	| DST_BLST_GC_INT EQUAL NUMBER { IF_DST_BLACKLIST(blst_timer_interval=$3);}
850 856
 	| DST_BLST_GC_INT error { yyerror("boolean value expected"); }
857
+	| DST_BLST_UDP_IMASK EQUAL NUMBER {
858
+		IF_DST_BLACKLIST(default_core_cfg.blst_udp_imask=$3);
859
+	}
860
+	| DST_BLST_UDP_IMASK error { yyerror("number(flags) expected"); }
861
+	| DST_BLST_TCP_IMASK EQUAL NUMBER {
862
+		IF_DST_BLACKLIST(default_core_cfg.blst_tcp_imask=$3);
863
+	}
864
+	| DST_BLST_TCP_IMASK error { yyerror("number(flags) expected"); }
865
+	| DST_BLST_TLS_IMASK EQUAL NUMBER {
866
+		IF_DST_BLACKLIST(default_core_cfg.blst_tls_imask=$3);
867
+	}
868
+	| DST_BLST_TLS_IMASK error { yyerror("number(flags) expected"); }
869
+	| DST_BLST_SCTP_IMASK EQUAL NUMBER {
870
+		IF_DST_BLACKLIST(default_core_cfg.blst_sctp_imask=$3);
871
+	}
872
+	| DST_BLST_SCTP_IMASK error { yyerror("number(flags) expected"); }
851 873
 	| PORT EQUAL NUMBER   { port_no=$3; }
852 874
 	| STAT EQUAL STRING {
853 875
 		#ifdef STATS
... ...
@@ -69,6 +69,10 @@ struct cfg_group_core default_core_cfg = {
69 69
 	0, /*!< dst blacklist is disabled by default */
70 70
 	DEFAULT_BLST_TIMEOUT,
71 71
 	DEFAULT_BLST_MAX_MEM,
72
+	0, /* blst_udp_imask */
73
+	0, /* blst_tcp_imask */
74
+	0, /* blst_tls_imask */
75
+	0, /* blst_sctp_imask */
72 76
 #endif
73 77
 	/* resolver */
74 78
 #ifdef USE_IPV6
... ...
@@ -129,7 +133,16 @@ cfg_def_t core_cfg_def[] = {
129 129
 	{"dst_blacklist_expire",	CFG_VAR_INT,	0, 0, 0, 0,
130 130
 		"how much time (in s) a blacklisted destination is kept in the list"},
131 131
 	{"dst_blacklist_mem",	CFG_VAR_INT,	0, 0, blst_max_mem_fixup, 0,
132
-		"maximum shared memory amount (in KB) used for keeping the blacklisted destinations"},
132
+		"maximum shared memory amount (in KB) used for keeping the blacklisted"
133
+			" destinations"},
134
+	{"dst_blacklist_udp_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
135
+		"blacklist event ignore mask for UDP"},
136
+	{"dst_blacklist_tcp_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
137
+		"blacklist event ignore mask for TCP"},
138
+	{"dst_blacklist_tls_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
139
+		"blacklist event ignore mask for TLS"},
140
+	{"dst_blacklist_sctp_imask", CFG_VAR_INT, 0, 0, 0, blst_reinit_ign_masks,
141
+		"blacklist event ignore mask for SCTP"},
133 142
 #endif
134 143
 	/* resolver */
135 144
 #ifdef USE_DNS_CACHE
... ...
@@ -63,6 +63,10 @@ struct cfg_group_core {
63 63
 	unsigned int	blst_timeout; /*!< blacklist entry ttl */
64 64
 	unsigned int	blst_max_mem; /*!< maximum memory used for the
65 65
 					blacklist entries */
66
+	unsigned int	blst_udp_imask;  /* ignore mask for udp */
67
+	unsigned int	blst_tcp_imask;  /* ignore mask for tcp */
68
+	unsigned int	blst_tls_imask;  /* ignore mask for tls */
69
+	unsigned int	blst_sctp_imask; /* ignore mask for sctp */
66 70
 #endif
67 71
 	/* resolver */
68 72
 	int dns_try_ipv6;
... ...
@@ -143,6 +143,9 @@ struct dst_blst_lst_head* dst_blst_hash=0;
143 143
 struct t_dst_blacklist_stats* dst_blacklist_stats=0;
144 144
 #endif
145 145
 
146
+/* blacklist per protocol event ignore mask array */
147
+unsigned blst_proto_imask[PROTO_LAST+1];
148
+
146 149
 #ifdef DST_BLACKLIST_HOOKS
147 150
 
148 151
 /* 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,
303 303
 #endif /* DST_BLACKLIST_HOOKS */
304 304
 
305 305
 
306
+/** init per protocol blacklist event ignore masks.
307
+ * @return 0 on success, < 0 on error.
308
+ */
309
+int blst_init_ign_masks()
310
+{
311
+	if ((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) ||
312
+		(PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)){
313
+		BUG("protocol array too small\n");
314
+		return -1;
315
+	}
316
+	blst_proto_imask[PROTO_UDP]=cfg_get(core, core_cfg, blst_udp_imask);
317
+	blst_proto_imask[PROTO_TCP]=cfg_get(core, core_cfg, blst_tcp_imask);
318
+	blst_proto_imask[PROTO_TLS]=cfg_get(core, core_cfg, blst_tls_imask);
319
+	blst_proto_imask[PROTO_SCTP]=cfg_get(core, core_cfg, blst_sctp_imask);
320
+	blst_proto_imask[PROTO_NONE]=blst_proto_imask[PROTO_UDP];
321
+	return 0;
322
+}
323
+
324
+
325
+
306 326
 inline static void blst_destroy_entry(struct dst_blst_entry* e)
307 327
 {
308 328
 	shm_free(e);
... ...
@@ -485,6 +508,10 @@ int init_dst_blacklist()
485 485
 			goto error;
486 486
 		}
487 487
 	}
488
+	if (blst_init_ign_masks() < 0){
489
+		ret=E_BUG;
490
+		goto error;
491
+	}
488 492
 	return 0;
489 493
 error:
490 494
 	destroy_dst_blacklist();
... ...
@@ -801,8 +828,8 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
801 801
  * @param timeout - timeout in ticks
802 802
  * @return 0 on success, -1 on error
803 803
  */
804
-int dst_blacklist_add_to(unsigned char err_flags,  struct dest_info* si,
805
-						struct sip_msg* msg, ticks_t timeout)
804
+int dst_blacklist_force_add_to(unsigned char err_flags,  struct dest_info* si,
805
+								struct sip_msg* msg, ticks_t timeout)
806 806
 {
807 807
 	struct ip_addr ip;
808 808
 
... ...
@@ -819,12 +846,12 @@ int dst_blacklist_add_to(unsigned char err_flags,  struct dest_info* si,
819 819
 
820 820
 
821 821
 /** add dst to the blacklist, specifying the timeout.
822
- * (like @function dst_blacklist_add_to)= above, but uses 
822
+ * (like @function dst_blacklist_force_add_to)= above, but uses 
823 823
  * (proto, sockaddr_union) instead of struct dest_info)
824 824
  */
825
-int dst_blacklist_su_to(unsigned char err_flags, unsigned char proto,
826
-							union sockaddr_union* dst,
827
-							struct sip_msg* msg, ticks_t timeout)
825
+int dst_blacklist_force_su_to(unsigned char err_flags, unsigned char proto,
826
+								union sockaddr_union* dst,
827
+								struct sip_msg* msg, ticks_t timeout)
828 828
 {
829 829
 	struct ip_addr ip;
830 830
 #ifdef DST_BLACKLIST_HOOKS
... ...
@@ -1204,5 +1231,14 @@ int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val)
1204 1204
 	return 0;
1205 1205
 }
1206 1206
 
1207
+
1208
+
1209
+/** re-inint per child blst_proto_ign_mask array. */
1210
+void blst_reinit_ign_masks(str* gname, str* name)
1211
+{
1212
+	blst_init_ign_masks();
1213
+}
1214
+
1215
+
1207 1216
 #endif /* USE_DST_BLACKLIST */
1208 1217
 
... ...
@@ -20,9 +20,8 @@
20 20
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 21
  */
22 22
 
23
-/**
23
+/** SIP-router core :: Destination blacklists.
24 24
  * @file
25
- * @brief SIP-router core :: Destination blacklists
26 25
  * @ingroup core
27 26
  * Module: @ref core
28 27
  */
... ...
@@ -31,6 +30,8 @@
31 31
  * --------
32 32
  *  2006-07-29  created by andrei
33 33
  *  2007-07-30  dst blacklist measurements added (Gergo)
34
+ *  2009-12-22  blacklist ignore mask support and dst_blacklist_{add,su}
35
+ *               switched to macros (andrei)
34 36
  */
35 37
 
36 38
 #ifndef dst_black_list_h
... ...
@@ -67,6 +68,9 @@
67 67
 #define DST_BLACKLIST_ADD_CB 1
68 68
 #define DST_BLACKLIST_SEARCH_CB 2
69 69
 
70
+
71
+extern unsigned blst_proto_imask[PROTO_LAST+1];
72
+
70 73
 #ifdef DST_BLACKLIST_HOOKS
71 74
 struct blacklist_hook{
72 75
 	/* WARNING: msg might be NULL, and it might point to shared memory
... ...
@@ -89,41 +93,127 @@ int init_dst_blacklist_stats(int iproc_num);
89 89
 void destroy_dst_blacklist();
90 90
 
91 91
 
92
-/** @brief like dst_blacklist_add, but the timeout can be also set */
93
-int dst_blacklist_add_to(unsigned char err_flags, struct dest_info* si,
94
-						struct sip_msg* msg, ticks_t timeout);
95
-/** @brief like above, but using a differnt way of passing the target */
96
-int dst_blacklist_su_to(unsigned char err_flags, unsigned char proto,
97
-							union sockaddr_union* dst,
98
-							struct sip_msg* msg, ticks_t timeout);
92
+/** force add to the blacklist.
93
+ * like @function dst_blacklist_add_to, but no ignore mask or
94
+ * blacklist enabled checks are made.
95
+ * @see dst_blacklist_add_to for the parameters and return value.
96
+ */
97
+int dst_blacklist_force_add_to(unsigned char err_flags, struct dest_info* si,
98
+								struct sip_msg* msg, ticks_t timeout);
99 99
 
100
-/** @brief adds a dst to the blacklist with default timeout.
101
- * @see dst_blacklist_add_to for more details.
100
+/** force add to the blacklist, long version.
101
+ * like @function dst_blacklist_su_to, but no ignore mask or
102
+ * blacklist enabled checks are made.
103
+ * @see dst_blacklist_su_to for the parameters and return value.
102 104
  */
103
-#define dst_blacklist_add(err_flags, si, msg) \
104
-	dst_blacklist_add_to((err_flags), (si), (msg), \
105
-		S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
105
+int dst_blacklist_force_su_to(	unsigned char err_flags,
106
+								unsigned char proto,
107
+								union sockaddr_union* dst,
108
+								struct sip_msg* msg,
109
+								ticks_t timeout);
110
+
111
+
112
+/** checks if blacklist should be used.
113
+  * @param  err_flags - blacklist reason
114
+  * @param si - filled dest_info structure pointer.
115
+  * @return 1 if blacklist is enabled (core_cfg) and the event/error
116
+  *           is not in the ignore list.
117
+  *         0 otherwise
118
+  */
119
+#define should_blacklist(err_flags, si) \
120
+	(cfg_get(core, core_cfg, use_dst_blacklist) && \
121
+		((err_flags) & ~blst_proto_imask[(unsigned)((si)->proto)] & \
122
+		 			   ~(si)->send_flags.blst_imask ))
123
+
124
+
125
+/** checks if blacklist should be used, long version.
126
+  * @param  err_flags - blacklist reason
127
+  * @param snd_flags - snd_flags pointer, can be 0.
128
+  * @param proto - protocol, can be 0 (PROTO_NONE).
129
+  * @param si  - sockaddr_union pointer, can be 0.
130
+  * @return 1 if blacklist is enabled (core_cfg) and the event/error
131
+  *           is not in the ignore list.
132
+  *         0 otherwise
133
+  */
134
+#define should_blacklist_su(err_flags, snd_flags, proto, su) \
135
+	(cfg_get(core, core_cfg, use_dst_blacklist) && \
136
+		((err_flags) & ~blst_proto_imask[(unsigned)(proto)] & \
137
+		 			~((snd_flags)?((snd_flags_t*)(snd_flags))->blst_imask:0)))
138
+
139
+
140
+/** adds a dst to the blacklist.
141
+ *
142
+ * @param  err_flags - blacklist reason
143
+ * @param si  - dest_info structure (dst).
144
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
145
+ * @param timeout - timeout in ticks.
146
+ * @return >=0 on success, -1 on error.
147
+ */
148
+#define dst_blacklist_add_to(err_flags, si, msg, timeout) \
149
+	(should_blacklist(err_flags, si)? \
150
+		dst_blacklist_force_add_to((err_flags), (si), (msg), (timeout))\
151
+		: 0)
152
+
153
+
154
+/** adds a dst to the blacklist, long version.
155
+ * Similar to dst_blacklist_add_to, but uses "unpacked" parameters.
156
+ * @param  err_flags - blacklist reason
157
+ * @param proto - protocol.
158
+ * @param dst  - sockaddr_union pointer.
159
+ * @param snd_flags - snd_flags pointer, can be 0.
160
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
161
+ * @param timeout - timeout in ticks.
162
+ * @return >=0 on success, -1 on error.
163
+ */
164
+#define dst_blacklist_su_to(err_flags, proto, dst, snd_flags, msg, timeout) \
165
+	(should_blacklist_su(err_flags, snd_flags, proto, dst) ? \
166
+		dst_blacklist_force_su_to((err_flags), (proto), (dst), (msg), \
167
+									(timeout))\
168
+		: 0)
169
+
106 170
 
107
-/** @brief adds a dst to the blacklist with default timeout.
108
- * @see dst_blacklist_su_to for more details.
171
+/** adds a dst to the blacklist with default timeout.
172
+ *
173
+ * @param  err_flags - blacklist reason
174
+ * @param si  - dest_info structure (dst).
175
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
176
+ * @return >=0 on success, -1 on error.
177
+ * @see dst_blacklist_add_to.
109 178
  */
110
-#define dst_blacklist_su(err_flags, proto, dst, msg) \
111
-	dst_blacklist_su_to((err_flags), (proto), (dst), (msg), \
112
-		S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
179
+#define dst_blacklist_add(err_flags, si, msg) \
180
+	dst_blacklist_add_to(err_flags, si, msg, \
181
+							S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
182
+
183
+
184
+/** adds a dst to the blacklist with default timeout, long version.
185
+ * Similar to dst_blacklist_add_to, but uses "unpacked" parameters.
186
+ * @param  err_flags - blacklist reason
187
+ * @param proto - protocol.
188
+ * @param dst  - sockaddr_union pointer.
189
+ * @param snd_flags - snd_flags pointer, can be 0.
190
+ * @param msg - sip msg struct. pointer if known, 0 otherwise.
191
+ * @return >=0 on success, -1 on error.
192
+ * @see dst_blacklist_su_to.
193
+ */
194
+#define dst_blacklist_su(err_flags, proto, dst, snd_flags, msg) \
195
+	dst_blacklist_su_to(err_flags, proto, dst, snd_flags, msg, \
196
+							S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))
113 197
 
114 198
 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg);
115 199
 
116
-/** @brief  delete an entry from the blacklist */
200
+/** delete an entry from the blacklist. */
117 201
 int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg);
118 202
 
119
-/** @brief deletes all the entries from the blacklist except the permanent ones
203
+/** deletes all the entries from the blacklist except the permanent ones.
120 204
  * (which are marked with BLST_PERMANENT)
121 205
  */
122 206
 void dst_blst_flush(void);
123 207
 
124 208
 int use_dst_blacklist_fixup(void *handle, str *gname, str *name, void **val);
125 209
 
126
-/** @brief KByte to Byte conversion */
210
+/** KByte to Byte conversion. */
127 211
 int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val);
128 212
 
213
+void blst_reinit_ign_masks(str* gname, str* name);
214
+
129 215
 #endif
... ...
@@ -603,8 +603,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
603 603
 		if (msg_send(send_info, buf, len)<0){
604 604
 			ret=ser_error=E_SEND;
605 605
 #ifdef USE_DST_BLACKLIST
606
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
607
-				dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
606
+			dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
608 607
 #endif
609 608
 #ifdef USE_DNS_FAILOVER
610 609
 			continue; /* try another ip */
... ...
@@ -766,7 +765,7 @@ int forward_reply(struct sip_msg* msg)
766 766
 	}
767 767
 
768 768
 	dst.proto=msg->via2->proto;
769
-	dst.send_flags=msg->fwd_send_flags | msg->rpl_send_flags;
769
+	SND_FLAGS_OR(&dst.send_flags, &msg->fwd_send_flags, &msg->rpl_send_flags);
770 770
 	if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error;
771 771
 #ifdef USE_COMP
772 772
 	dst.comp=msg->via2->comp_no;
... ...
@@ -158,7 +158,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
158 158
 			goto error;
159 159
 		}else{
160 160
 			from=0;
161
-			if (unlikely((dst->send_flags & SND_F_FORCE_SOCKET) &&
161
+			if (unlikely((dst->send_flags.f & SND_F_FORCE_SOCKET) &&
162 162
 						dst->send_sock)) {
163 163
 				local_addr=dst->send_sock->su;
164 164
 				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)
180 180
 			goto error;
181 181
 		}else{
182 182
 			from=0;
183
-			if (unlikely((dst->send_flags & SND_F_FORCE_SOCKET) &&
183
+			if (unlikely((dst->send_flags.f & SND_F_FORCE_SOCKET) &&
184 184
 						dst->send_sock)) {
185 185
 				local_addr=dst->send_sock->su;
186 186
 				su_setport(&local_addr, 0); /* any local port will do */
... ...
@@ -142,7 +142,31 @@ struct receive_info{
142 142
 #define SND_F_CON_CLOSE			2 /* close the connection after sending */
143 143
 #define SND_F_FORCE_SOCKET		4 /* send socket in dst is forced */
144 144
 
145
-typedef unsigned char  snd_flags_t;
145
+struct snd_flags {
146
+	unsigned char f;          /* snd flags */
147
+	unsigned char blst_imask; /* blacklist ignore mask */
148
+};
149
+
150
+
151
+typedef struct snd_flags  snd_flags_t;
152
+
153
+#define SND_FLAGS_INIT(sflags) \
154
+	do{ \
155
+		(sflags)->f=0; \
156
+		(sflags)->blst_imask=0; \
157
+	}while(0)
158
+
159
+#define SND_FLAGS_OR(dst, src1, src2) \
160
+	do{ \
161
+		(dst)->f = (src1)->f | (src2)->f; \
162
+		(dst)->blst_imask = (src1)->blst_imask | (src2)->blst_imask; \
163
+	}while(0)
164
+
165
+#define SND_FLAGS_AND(dst, src1, src2) \
166
+	do{ \
167
+		(dst)->f = (src1)->f & (src2)->f; \
168
+		(dst)->blst_imask = (src1)->blst_imask & (src2)->blst_imask; \
169
+	}while(0)
146 170
 
147 171
 struct dest_info{
148 172
 	struct socket_info* send_sock;
... ...
@@ -757,7 +781,8 @@ inline static void init_dst_from_rcv(struct dest_info* dst,
757 757
 		dst->to=rcv->src_su;
758 758
 		dst->id=rcv->proto_reserved1;
759 759
 		dst->proto=rcv->proto;
760
-		dst->send_flags=0;
760
+		dst->send_flags.f=0;
761
+		dst->send_flags.blst_imask=0;
761 762
 #ifdef USE_COMP
762 763
 		dst->comp=rcv->comp;
763 764
 #endif
... ...
@@ -659,8 +659,10 @@ static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
659 659
 		t->uac[branch].request.dst.send_sock =
660 660
 		get_send_socket( request, &t->uac[branch].request.dst.to,
661 661
 								t->uac[branch].request.dst.proto);
662
-		t->uac[branch].request.dst.send_flags=request?
663
-												request->fwd_send_flags:0;
662
+		if (request)
663
+			t->uac[branch].request.dst.send_flags=request->fwd_send_flags;
664
+		else
665
+			SND_FLAGS_INIT(&t->uac[branch].request.dst.send_flags);
664 666
 		next_hop=0;
665 667
 	}else {
666 668
 		next_hop= next_hop?next_hop:uri;
... ...
@@ -845,7 +847,7 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
845 845
 				 * in the rest of the message, only in the VIA HF (Miklos) */
846 846
 				ret=add_uac_from_buf(t,  msg, &old_uac->uri,
847 847
 							&old_uac->path,
848
-							 (old_uac->request.dst.send_flags &
848
+							 (old_uac->request.dst.send_flags.f &
849 849
 								SND_F_FORCE_SOCKET)?
850 850
 									old_uac->request.dst.send_sock:0,
851 851
 							old_uac->request.dst.send_flags,
... ...
@@ -858,7 +860,7 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
858 858
 				 *  must be changed and the send_socket might be different =>
859 859
 				 *  re-create the whole uac */
860 860
 				ret=add_uac(t,  msg, &old_uac->uri, 0, &old_uac->path, 0,
861
-							 (old_uac->request.dst.send_flags &
861
+							 (old_uac->request.dst.send_flags.f &
862 862
 								SND_F_FORCE_SOCKET)?
863 863
 									old_uac->request.dst.send_sock:0,
864 864
 							old_uac->request.dst.send_flags,
... ...
@@ -883,6 +885,7 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
883 883
 	int ret;
884 884
 	char *shbuf;
885 885
 	unsigned int len;
886
+	snd_flags_t snd_flags;
886 887
 
887 888
 	ret=-1;
888 889
 	if (t_cancel->uac[branch].request.buffer) {
... ...
@@ -928,12 +931,13 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
928 928
 			cancel_msg->first_line.u.request.method.len+1;
929 929
 		t_cancel->uac[branch].uri.len=t_invite->uac[branch].uri.len;
930 930
 	} else {
931
+		SND_FLAGS_INIT(&snd_flags);
931 932
 		/* buffer is constructed from the received CANCEL with lumps applied */
932 933
 		/*  t_cancel...request.dst is already filled (see above) */
933 934
 		if (unlikely((ret=prepare_new_uac( t_cancel, cancel_msg, branch,
934 935
 									&t_invite->uac[branch].uri,
935 936
 									&t_invite->uac[branch].path,
936
-									0, 0, 0, PROTO_NONE, 0)) <0)){
937
+									0, 0, snd_flags, PROTO_NONE, 0)) <0)){
937 938
 			ser_error=ret;
938 939
 			goto error;
939 940
 		}
... ...
@@ -1215,8 +1219,7 @@ int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
1215 1215
 							ip_addr2a(&ip), su_getport(&uac->request.dst.to),
1216 1216
 							uac->request.dst.proto);
1217 1217
 #ifdef USE_DST_BLACKLIST
1218
-		if (cfg_get(core, core_cfg, use_dst_blacklist))
1219
-			dst_blacklist_add(BLST_ERR_SEND, &uac->request.dst, p_msg);
1218
+		dst_blacklist_add(BLST_ERR_SEND, &uac->request.dst, p_msg);
1220 1219
 #endif
1221 1220
 #ifdef USE_DNS_FAILOVER
1222 1221
 		/* if the destination resolves to more ips, add another
... ...
@@ -1651,7 +1651,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
1651 1651
 				}
1652 1652
 				/* update send_flags with possible additions from the
1653 1653
 				   reply route */
1654
-				uas_rb->dst.send_flags|=relayed_msg->rpl_send_flags;
1654
+				SND_FLAGS_OR(&uas_rb->dst.send_flags, &uas_rb->dst.send_flags,
1655
+								&relayed_msg->rpl_send_flags);
1655 1656
 			}
1656 1657
 		}
1657 1658
 		update_reply_stats( relayed_code );
... ...
@@ -1885,7 +1886,6 @@ int reply_received( struct sip_msg  *p_msg )
1885 1885
 #endif
1886 1886
 #ifdef USE_DST_BLACKLIST
1887 1887
 	int blst_503_timeout;
1888
-	struct dest_info src;
1889 1888
 	struct hdr_field* hf;
1890 1889
 #endif
1891 1890
 #ifdef TMCB_ONSEND
... ...
@@ -2014,6 +2014,10 @@ int reply_received( struct sip_msg  *p_msg )
2014 2014
 			switch_rb_retr_to_t2(&uac->request);
2015 2015
 		}
2016 2016
 	}
2017
+	/* pre-set the ignore BLST_503 flag in the message, if the
2018
+	   corresponding branch had it set on send */
2019
+	p_msg->fwd_send_flags.blst_imask|=
2020
+		uac->request.dst.send_flags.blst_imask & BLST_503;
2017 2021
 	/* processing of on_reply block */
2018 2022
 	if (t->on_reply) {
2019 2023
 		set_route_type(ONREPLY_ROUTE);
... ...
@@ -2062,10 +2066,13 @@ int reply_received( struct sip_msg  *p_msg )
2062 2062
 	}
2063 2063
 #ifdef USE_DST_BLACKLIST
2064 2064
 		/* add temporary to the blacklist the source of a 503 reply */
2065
-		if (cfg_get(tm, tm_cfg, tm_blst_503)
2066
-			&& cfg_get(core, core_cfg, use_dst_blacklist)
2067
-			&& (msg_status==503)
2068
-		){
2065
+		if (	(msg_status==503) &&
2066
+				cfg_get(tm, tm_cfg, tm_blst_503) &&
2067
+				/* check if the request sent on the branch had the the
2068
+				   blst 503 ignore flags set or it was set in the onreply_r*/
2069
+				should_blacklist_su(BLST_503, &p_msg->fwd_send_flags,
2070
+										p_msg->rcv.proto, &p_msg->rcv.src_su)
2071
+			){
2069 2072
 			blst_503_timeout=cfg_get(tm, tm_cfg, tm_blst_503_default);
2070 2073
 			if ((parse_headers(p_msg, HDR_RETRY_AFTER_F, 0)==0) && 
2071 2074
 				(p_msg->parsed_flag & HDR_RETRY_AFTER_F)){
... ...
@@ -2081,12 +2088,9 @@ int reply_received( struct sip_msg  *p_msg )
2081 2081
 					}
2082 2082
 			}
2083 2083
 			if (blst_503_timeout){
2084
-				src.send_sock=0;
2085
-				src.to=p_msg->rcv.src_su;
2086
-				src.id=p_msg->rcv.proto_reserved1;
2087
-				src.proto=p_msg->rcv.proto;
2088
-				dst_blacklist_add_to(BLST_503, &src,  p_msg, 
2089
-									S_TO_TICKS(blst_503_timeout));
2084
+				dst_blacklist_force_su_to(BLST_503, p_msg->rcv.proto,
2085
+											&p_msg->rcv.src_su, p_msg,
2086
+											S_TO_TICKS(blst_503_timeout));
2090 2087
 			}
2091 2088
 		}
2092 2089
 #endif /* USE_DST_BLACKLIST */
... ...
@@ -478,13 +478,13 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
478 478
 	){
479 479
 		/* no reply received */
480 480
 #ifdef USE_DST_BLACKLIST
481
-		if (cfg_get(core, core_cfg, use_dst_blacklist)
482
-        		&& r_buf->my_T
481
+		if (r_buf->my_T
483 482
 			&& r_buf->my_T->uas.request
484
-			&& (r_buf->my_T->uas.request->REQ_METHOD & cfg_get(tm, tm_cfg, tm_blst_methods_add))
483
+			&& (r_buf->my_T->uas.request->REQ_METHOD &
484
+					cfg_get(tm, tm_cfg, tm_blst_methods_add))
485 485
 		)
486 486
 			dst_blacklist_add( BLST_ERR_TIMEOUT, &r_buf->dst,
487
-						r_buf->my_T->uas.request);
487
+								r_buf->my_T->uas.request);
488 488
 #endif
489 489
 #ifdef USE_DNS_FAILOVER
490 490
 		/* if this is an invite, the destination resolves to more ips, and
... ...
@@ -215,6 +215,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
215 215
 	int sflag_bk;
216 216
 	int backup_route_type;
217 217
 #endif
218
+	snd_flags_t snd_flags;
218 219
 
219 220
 	ret=-1;
220 221
 	hi=0; /* make gcc happy */
... ...
@@ -239,10 +240,11 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
239 239
 			uac_r->dialog->hooks.next_hop->s);
240 240
 	/* new message => take the dialog send_socket if set, or the default
241 241
 	  send_socket if not*/
242
+	SND_FLAGS_INIT(&snd_flags);
242 243
 #ifdef USE_DNS_FAILOVER
243 244
 	if (cfg_get(core, core_cfg, use_dns_failover)){
244 245
 		dns_srv_handle_init(&dns_h);
245
-		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, 0,
246
+		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, snd_flags,
246 247
 							uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
247 248
 				|| (dst.send_sock==0)){
248 249
 			dns_srv_handle_put(&dns_h);
... ...
@@ -253,7 +255,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
253 253
 		}
254 254
 		dns_srv_handle_put(&dns_h); /* not needed anymore */
255 255
 	}else{
256
-		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, 0,
256
+		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, snd_flags,
257 257
 						uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
258 258
 				(dst.send_sock==0)){
259 259
 			ser_error = E_NO_SOCKET;
... ...
@@ -263,7 +265,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
263 263
 		}
264 264
 	}
265 265
 #else /* USE_DNS_FAILOVER */
266
-	if ((uri2dst2(&dst, uac_r->dialog->send_sock, 0,
266
+	if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags,
267 267
 					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
268 268
 			(dst.send_sock==0)){
269 269
 		ser_error = E_NO_SOCKET;
... ...
@@ -356,16 +356,24 @@ inline static struct dest_info *uri2dst(struct dns_srv_handle* dns_h,
356 356
 										struct sip_msg *msg, str *uri, 
357 357
 											int proto )
358 358
 {
359
-	return uri2dst2(dns_h, dst, msg?msg->force_send_socket:0,
360
-						msg?msg->fwd_send_flags:0, uri, proto);
359
+	snd_flags_t sflags;
360
+	if (msg)
361
+		return uri2dst2(dns_h, dst, msg->force_send_socket,
362
+							msg->fwd_send_flags, uri, proto);
363
+	SND_FLAGS_INIT(&sflags);
364
+	return uri2dst2(dns_h, dst, 0, sflags, uri, proto);
361 365
 }
362 366
 #else
363 367
 inline static struct dest_info *uri2dst(struct dest_info* dst,
364 368
 										struct sip_msg *msg, str *uri, 
365 369
 											int proto )
366 370
 {
367
-	return uri2dst2(dst, msg?msg->force_send_socket:0,
368
-						msg?msg->fwd_send_flags:0, uri, proto);
371
+	snd_flags_t sflags;
372
+	if (msg)
373
+		return uri2dst2(dst, msg->force_send_socket, msg->fwd_send_flags,
374
+						uri, proto);
375
+	SND_FLAGS_INIT(&sflags);
376
+	return uri2dst2(dst, 0, sflags, uri, proto);
369 377
 }
370 378
 #endif /* USE_DNS_FAILOVER */
371 379
 
... ...
@@ -16,6 +16,11 @@ Andrei Pelinescu-Onciul
16 16
         1.2.2. blst_add_retry_after(min, max)
17 17
         1.2.3. blst_del()
18 18
         1.2.4. blst_is_blacklisted()
19
+        1.2.5. blst_set_ignore() blst_set_ignore(flags)
20
+                blst_rpl_set_ignore() blst_rpl_set_ignore(flags)
21
+
22
+        1.2.6. blst_clear_ignore() blst_clear_ignore(flags)
23
+                blst_rpl_clear_ignore() blst_rpl_clear_ignore(flags)
19 24
 
20 25
 1.1. Overview
21 26
 
... ...
@@ -80,3 +85,45 @@ if (msg_status==503){ # blacklist 503 source for Retry-After seconds
80 80
         drop;
81 81
    }
82 82
 ...
83
+
84
+1.2.5.  blst_set_ignore() blst_set_ignore(flags) blst_rpl_set_ignore()
85
+blst_rpl_set_ignore(flags)
86
+
87
+   Set errors that will not be taken into account when deciding whether or
88
+   not to blacklist a destination for the current message or a local reply
89
+   to the current message.
90
+
91
+   blst_set_ignore(..) works for forwarding the current message and
92
+   blst_rpl_set_ignore(...) works for local replies to the current
93
+   message.
94
+
95
+   The variants with no parameters will ignore everything (equivalent with
96
+   passing 0xff).
97
+
98
+   The following flags are defined:
99
+     * 0x02 - generic send error (send denied/ failed).
100
+     * 0x04 - connect failed (TCP, TLS or SCTP).
101
+     * 0x08 - ICMP error (not currently used).
102
+     * 0x10 - SIP transaction timeout.
103
+     * 0x20 - 503 reply (statefull mode only). For more details see
104
+       tmblst_503.
105
+
106
+Note
107
+
108
+   TCP and TLS send and connect errors are handled per connection and not
109
+   per message. The connection blacklist ignore flags are inherithed from
110
+   the message that caused the connection establishment.
111
+
112
+   Example 5. blst_set_ignore usage
113
+    blst_set_ignore(6); # ignore send and connect errors
114
+
115
+1.2.6.  blst_clear_ignore() blst_clear_ignore(flags) blst_rpl_clear_ignore()
116
+blst_rpl_clear_ignore(flags)
117
+
118
+   Clears blacklist ignore flags previously set by the corresponding
119
+   blst_set_ignore(...) or blst_rpl_set_ignore(...) functions.
120
+
121
+   See also blst_set_ignore.
122
+
123
+   Example 6. blst_clear_ignore usage
124
+    blst_clear_ignore(4); # ignore connect errors
... ...
@@ -45,6 +45,10 @@ static int blst_add_f(struct sip_msg*, char*, char*);
45 45
 static int blst_add_retry_after_f(struct sip_msg*, char*, char*);
46 46
 static int blst_del_f(struct sip_msg*, char*, char*);
47 47
 static int blst_is_blacklisted_f(struct sip_msg*, char*, char*);
48
+static int blst_set_ignore_f(struct sip_msg*, char*, char*);
49
+static int blst_clear_ignore_f(struct sip_msg*, char*, char*);
50
+static int blst_rpl_set_ignore_f(struct sip_msg*, char*, char*);
51
+static int blst_rpl_clear_ignore_f(struct sip_msg*, char*, char*);
48 52
 
49 53
 
50 54
 
... ...
@@ -59,6 +63,22 @@ static cmd_export_t cmds[]={
59 59
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
60 60
 	{"blst_is_blacklisted",   blst_is_blacklisted_f, 0, 0,
61 61
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
62
+	{"blst_set_ignore",         blst_set_ignore_f,   0,  0,
63
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
64
+	{"blst_set_ignore",         blst_set_ignore_f,   1,  fixup_var_int_1,
65
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
66
+	{"blst_clear_ignore",         blst_clear_ignore_f,   0,  0,
67
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
68
+	{"blst_clear_ignore",         blst_clear_ignore_f,   1,  fixup_var_int_1,
69
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
70
+	{"blst_rpl_set_ignore",       blst_rpl_set_ignore_f, 0,  0,
71
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
72
+	{"blst_rpl_set_ignore",      blst_rpl_set_ignore_f,  1,  fixup_var_int_1,
73
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
74
+	{"blst_rpl_clear_ignore",   blst_rpl_clear_ignore_f, 0,  0,
75
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
76
+	{"blst_rpl_clear_ignore",   blst_rpl_clear_ignore_f, 1,  fixup_var_int_1,
77
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
62 78
 	{0,0,0,0,0}
63 79
 };
64 80
 
... ...
@@ -90,16 +110,15 @@ static int blst_add_f(struct sip_msg* msg, char* to, char* foo)
90 90
 		t=0;
91 91
 		if (unlikely( to && (get_int_fparam(&t, msg, (fparam_t*)to)<0)))
92 92
 			return -1;
93
-	
93
+		if (t==0)
94
+			t=cfg_get(core, core_cfg, blst_timeout);
95
+		init_dest_info(&src);
94 96
 		src.send_sock=0;
95 97
 		src.to=msg->rcv.src_su;
96 98
 		src.id=msg->rcv.proto_reserved1;
97 99
 		src.proto=msg->rcv.proto;
98
-		if (t)
99
-			dst_blacklist_add_to(BLST_ADM_PROHIBITED, &src, msg,
100
+		dst_blacklist_force_add_to(BLST_ADM_PROHIBITED, &src, msg,
100 101
 									S_TO_TICKS(t));
101
-		else
102
-			dst_blacklist_add(BLST_ADM_PROHIBITED, &src, msg);
103 102
 		return 1;
104 103
 	}else{
105 104
 		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)
130 130
 			t_max=0;
131 131
 		}
132 132
 	
133
+		init_dest_info(&src);
133 134
 		src.send_sock=0;
134 135
 		src.to=msg->rcv.src_su;
135 136
 		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)
150 150
 		t=MAX_unsigned(t, t_min);
151 151
 		t=MIN_unsigned(t, t_max);
152 152
 		if (likely(t))
153
-			dst_blacklist_add_to(BLST_ADM_PROHIBITED, &src, msg,
154
-									S_TO_TICKS(t));
153
+			dst_blacklist_force_add_to(BLST_ADM_PROHIBITED, &src, msg,
154
+										S_TO_TICKS(t));
155 155
 		return 1;
156 156
 	}else{
157 157
 		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)
173 173
 	
174 174
 	if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
175 175
 	
176
+		init_dest_info(&src);
176 177
 		src.send_sock=0;
177 178
 		src.to=msg->rcv.src_su;
178 179
 		src.id=msg->rcv.proto_reserved1;
... ...
@@ -197,6 +218,7 @@ static int blst_is_blacklisted_f(struct sip_msg* msg, char* foo, char* bar)
197 197
 	struct dest_info src;
198 198
 	
199 199
 	if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
200
+		init_dest_info(&src);
200 201
 		src.send_sock=0;
201 202
 		src.to=msg->rcv.src_su;
202 203
 		src.id=msg->rcv.proto_reserved1;
... ...
@@ -213,3 +235,83 @@ static int blst_is_blacklisted_f(struct sip_msg* msg, char* foo, char* bar)
213 213
 #endif /* USE_DST_BLACKLIST */
214 214
 	return -1;
215 215
 }
216
+
217
+
218
+
219
+static int blst_set_ignore_f(struct sip_msg* msg, char* flags, char* foo)
220
+{
221
+#ifdef USE_DST_BLACKLIST
222
+	unsigned char blst_imask;
223
+	int mask;
224
+	
225
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
226
+		return -1;
227
+	blst_imask=flags?mask:0xff;
228
+	msg->fwd_send_flags.blst_imask|=blst_imask;
229
+	return 1;
230
+#else /* USE_DST_BLACKLIST */
231
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
232
+				" not compiled-in - no effect -\n");
233
+#endif /* USE_DST_BLACKLIST */
234
+	return 1;
235
+}
236
+
237
+
238
+
239
+static int blst_clear_ignore_f(struct sip_msg* msg, char* flags, char* foo)
240
+{
241
+#ifdef USE_DST_BLACKLIST
242
+	unsigned char blst_imask;
243
+	int mask;
244
+	
245
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
246
+		return -1;
247
+	blst_imask=flags?mask:0xff;
248
+	msg->fwd_send_flags.blst_imask&=~blst_imask;
249
+	return 1;
250
+#else /* USE_DST_BLACKLIST */
251
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
252
+				" not compiled-in - no effect -\n");
253
+#endif /* USE_DST_BLACKLIST */
254
+	return 1;
255
+}
256
+
257
+
258
+
259
+static int blst_rpl_set_ignore_f(struct sip_msg* msg, char* flags, char* foo)
260
+{
261
+#ifdef USE_DST_BLACKLIST
262
+	unsigned char blst_imask;
263
+	int mask;
264
+	
265
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
266
+		return -1;
267
+	blst_imask=flags?mask:0xff;
268
+	msg->rpl_send_flags.blst_imask|=blst_imask;
269
+	return 1;
270
+#else /* USE_DST_BLACKLIST */
271
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
272
+				" not compiled-in - no effect -\n");
273
+#endif /* USE_DST_BLACKLIST */
274
+	return 1;
275
+}
276
+
277
+
278
+
279
+static int blst_rpl_clear_ignore_f(struct sip_msg* msg, char* flags, char* foo)
280
+{
281
+#ifdef USE_DST_BLACKLIST
282
+	unsigned char blst_imask;
283
+	int mask;
284
+	
285
+	if (unlikely(flags && (get_int_fparam(&mask, msg, (fparam_t*)flags)<0)))
286
+		return -1;
287
+	blst_imask=flags?mask:0xff;
288
+	msg->rpl_send_flags.blst_imask&=~blst_imask;
289
+	return 1;
290
+#else /* USE_DST_BLACKLIST */
291
+	LOG(L_WARN, "WARNING: blst: blst_ignore_req: blacklist support"
292
+				" not compiled-in - no effect -\n");
293
+#endif /* USE_DST_BLACKLIST */
294
+	return 1;
295
+}
... ...
@@ -108,4 +108,84 @@ if (msg_status==503){ # blacklist 503 source for Retry-After seconds
108 108
 	</example>
109 109
     </section>
110 110
 
111
+	<section id="blst_set_ignore">
112
+	<title>
113
+		<function>blst_set_ignore()</function>
114
+		<function>blst_set_ignore(flags)</function>
115
+		<function>blst_rpl_set_ignore()</function>
116
+		<function>blst_rpl_set_ignore(flags)</function>
117
+	</title>
118
+	<para>
119
+		Set errors that will not be taken into account when deciding
120
+		whether or not to blacklist a destination for the current message
121
+		or a local reply to the current message.
122
+	</para>
123
+	<para>
124
+		<function>blst_set_ignore(..)</function> works for forwarding the
125
+		current message and <function>blst_rpl_set_ignore(...)</function>
126
+		works for local replies to the current message.
127
+	</para>
128
+	<para>
129
+		The variants with no parameters will ignore everything (equivalent
130
+		with passing 0xff).
131
+	</para>
132
+	<para>
133
+		The following flags are defined:
134
+		<itemizedlist>
135
+			<listitem>
136
+				<emphasis>0x02</emphasis> - generic send error (send denied/
137
+				 failed).
138
+			</listitem>
139
+			<listitem>
140
+				<emphasis>0x04</emphasis> - connect failed (TCP, TLS or SCTP).
141
+			</listitem>
142
+			<listitem>
143
+				<emphasis>0x08</emphasis> - ICMP error (not currently used).
144
+			</listitem>
145
+			<listitem>
146
+				<emphasis>0x10</emphasis> - SIP transaction timeout.
147
+			</listitem>
148
+			<listitem>
149
+				<emphasis>0x20</emphasis> - 503 reply (statefull mode only).
150
+				For more details see <emphasis>tm</emphasis>
151
+				<varname>blst_503</varname>.
152
+			</listitem>
153
+		</itemizedlist>
154
+	</para>
155
+	<note>
156
+		TCP and TLS send and connect errors are handled per connection and
157
+		not per message. The connection blacklist ignore flags are inherithed
158
+		from the message that caused the connection establishment.
159
+	</note>
160
+	<example>
161
+		<title><function>blst_set_ignore</function> usage</title>
162
+		<programlisting>
163
+    blst_set_ignore(6); # ignore send and connect errors
164
+		</programlisting>
165
+	</example>
166
+	</section>
167
+
168
+	<section id="blst_clear_ignore">
169
+	<title>
170
+		<function>blst_clear_ignore()</function>
171
+		<function>blst_clear_ignore(flags)</function>
172
+		<function>blst_rpl_clear_ignore()</function>
173
+		<function>blst_rpl_clear_ignore(flags)</function>
174
+	</title>
175
+	<para>
176
+		Clears blacklist ignore flags previously set by the corresponding
177
+		<function>blst_set_ignore(...)</function> or
178
+		<function>blst_rpl_set_ignore(...)</function> functions.
179
+	</para>
180
+	<para>
181
+		See also <function>blst_set_ignore</function>.
182
+	</para>
183
+	<example>
184
+		<title><function>blst_clear_ignore</function> usage</title>
185
+	    <programlisting>
186
+    blst_clear_ignore(4); # ignore connect errors
187
+		</programlisting>
188
+	</example>
189
+	</section>
190
+
111 191
 </section>
... ...
@@ -448,9 +448,9 @@ void reset_path_vector(struct sip_msg* msg);
448 448
 	do { \
449 449
 		(msg)->force_send_socket=(fsocket); \
450 450
 		if ((msg)->force_send_socket) \
451
-			(msg)->fwd_send_flags |= SND_F_FORCE_SOCKET; \
451
+			(msg)->fwd_send_flags.f |= SND_F_FORCE_SOCKET; \
452 452
 		else \
453
-			(msg)->fwd_send_flags &= ~SND_F_FORCE_SOCKET; \
453
+			(msg)->fwd_send_flags.f &= ~SND_F_FORCE_SOCKET; \
454 454
 	} while (0)
455 455
 
456 456
 /** reset a previously forced send socket. */
... ...
@@ -2133,13 +2133,12 @@ static int sctp_handle_send_failed(struct socket_info* si,
2133 2133
 		ret=sctp_msg_send_ext(&dst, data, data_len, &sinfo);
2134 2134
 	}
2135 2135
 #ifdef USE_DST_BLACKLIST
2136
-	 else if (cfg_get(core, core_cfg, use_dst_blacklist) &&
2137
-					cfg_get(sctp, sctp_cfg, send_retries)) {
2136
+	 else if (cfg_get(sctp, sctp_cfg, send_retries)) {
2138 2137
 		/* blacklist only if send_retries is on, if off we blacklist
2139 2138
 		   from SCTP_ASSOC_CHANGE: SCTP_COMM_LOST/SCTP_CANT_STR_ASSOC
2140 2139
 		   which is better (because we can tell connect errors from send
2141 2140
 		   errors and we blacklist a failed dst only once) */
2142
-		dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0);
2141
+		dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
2143 2142
 	}
2144 2143
 #endif /* USE_DST_BLACKLIST */
2145 2144
 	
... ...
@@ -2220,9 +2219,8 @@ again:
2220 2220
 #ifdef USE_DST_BLACKLIST
2221 2221
 			/* blacklist only if send_retries is turned off (if on we don't
2222 2222
 			   know here if we did retry or we are at the first error) */
2223
-			if (cfg_get(core, core_cfg, use_dst_blacklist) &&
2224
-					(cfg_get(sctp, sctp_cfg, send_retries)==0))
2225
-						dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0);
2223
+			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
2224
+						dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
2226 2225
 #endif /* USE_DST_BLACKLIST */
2227 2226
 			/* no break */
2228 2227
 			goto comm_lost_cont;	/* do not increment counters for
... ...
@@ -2254,9 +2252,8 @@ comm_lost_cont:
2254 2254
 #ifdef USE_DST_BLACKLIST
2255 2255
 			/* blacklist only if send_retries is turned off (if on we don't 
2256 2256
 			   know here if we did retry or we are at the first error) */
2257
-			if (cfg_get(core, core_cfg, use_dst_blacklist) &&
2258
-					(cfg_get(sctp, sctp_cfg, send_retries)==0))
2259
-						dst_blacklist_su(BLST_ERR_CONNECT, PROTO_SCTP, su, 0);
2257
+			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
2258
+					dst_blacklist_su(BLST_ERR_CONNECT, PROTO_SCTP, su, 0, 0);
2260 2259
 #endif /* USE_DST_BLACKLIST */
2261 2260
 			break;
2262 2261
 		default:
... ...
@@ -172,7 +172,7 @@ struct tcp_connection{
172 172
 	atomic_t refcnt;
173 173
 	enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */
174 174
 	unsigned short flags; /* connection related flags */
175
-	unsigned short send_flags; /* special send flags */
175
+	snd_flags_t send_flags; /* special send flags */
176 176
 	enum tcp_conn_states state; /* connection state */
177 177
 	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
178 178
 	struct timer_ln timer;
... ...
@@ -192,9 +192,10 @@ struct tcp_connection{
192 192
 
193 193
 /* helper macros */
194 194
 
195
-#define tcpconn_set_send_flags(c, snd_flags) ((c)->send_flags|=(snd_flags))
195
+#define tcpconn_set_send_flags(c, snd_flags) \
196
+	SND_FLAGS_OR(&(c)->send_flags, &(c)->send_flags, &(snd_flags))
196 197
 
197
-#define tcpconn_close_after_send(c)	((c)->send_flags & SND_F_CON_CLOSE)
198
+#define tcpconn_close_after_send(c)	((c)->send_flags.f & SND_F_CON_CLOSE)
198 199
 
199 200
 #define TCP_RCV_INFO(c) (&(c)->rcv)
200 201
 
... ...
@@ -484,7 +484,7 @@ error:
484 484
  * if BLOCKING_USE_SELECT and HAVE_SELECT are defined it will internally
485 485
  * use select() instead of poll (bad if fd > FD_SET_SIZE, poll is preferred)
486 486
  */
487
-static int tcp_blocking_connect(int fd, int type,
487
+static int tcp_blocking_connect(int fd, int type, snd_flags_t* send_flags,
488 488
 								const struct sockaddr *servaddr,
489 489
 								socklen_t addrlen)
490 490
 {
... ...
@@ -577,18 +577,16 @@ error_errno:
577 577
 		case ENETUNREACH:
578 578
 		case EHOSTUNREACH:
579 579
 #ifdef USE_DST_BLACKLIST
580
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
581
-				dst_blacklist_su(BLST_ERR_CONNECT, type,
582
-							 (union sockaddr_union*)servaddr, 0);
580
+			dst_blacklist_su(BLST_ERR_CONNECT, type,
581
+							 (union sockaddr_union*)servaddr, send_flags, 0);
583 582
 #endif /* USE_DST_BLACKLIST */
584 583
 			TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0,
585 584
 							(union sockaddr_union*)servaddr, type);
586 585
 			break;
587 586
 		case ETIMEDOUT:
588 587
 #ifdef USE_DST_BLACKLIST
589
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
590
-				dst_blacklist_su(BLST_ERR_CONNECT, type,
591
-								 (union sockaddr_union*)servaddr, 0);
588
+			dst_blacklist_su(BLST_ERR_CONNECT, type,
589
+							 (union sockaddr_union*)servaddr, send_flags, 0);
592 590
 #endif /* USE_DST_BLACKLIST */
593 591
 			TCP_EV_CONNECT_TIMEOUT(errno, 0, 0,
594 592
 							(union sockaddr_union*)servaddr, type);
... ...
@@ -596,9 +594,8 @@ error_errno:
596 596
 		case ECONNREFUSED:
597 597
 		case ECONNRESET:
598 598
 #ifdef USE_DST_BLACKLIST
599
-			if (cfg_get(core, core_cfg, use_dst_blacklist))
600
-				dst_blacklist_su(BLST_ERR_CONNECT, type,
601
-								 (union sockaddr_union*)servaddr, 0);
599
+			dst_blacklist_su(BLST_ERR_CONNECT, type,
600
+							 (union sockaddr_union*)servaddr, send_flags, 0);
602 601
 #endif /* USE_DST_BLACKLIST */
603 602
 			TCP_EV_CONNECT_RST(errno, 0, 0,
604 603
 							(union sockaddr_union*)servaddr, type);
... ...
@@ -618,9 +615,8 @@ error_errno:
618 618
 error_timeout:
619 619
 	/* timeout */
620 620
 #ifdef USE_DST_BLACKLIST
621
-	if (cfg_get(core, core_cfg, use_dst_blacklist))
622
-		dst_blacklist_su(BLST_ERR_CONNECT, type,
623
-							(union sockaddr_union*)servaddr, 0);
621
+	dst_blacklist_su(BLST_ERR_CONNECT, type,
622
+						(union sockaddr_union*)servaddr, send_flags, 0);
624 623
 #endif /* USE_DST_BLACKLIST */
625 624
 	TCP_EV_CONNECT_TIMEOUT(0, 0, 0, (union sockaddr_union*)servaddr, type);
626 625
 	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,
673 673
 		if (q->first && TICKS_LT(q->wr_timeout, t)){
674 674
 			if (unlikely(c->state==S_CONN_CONNECT)){
675 675
 #ifdef USE_DST_BLACKLIST
676
-				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
677
-					DBG("blacklisting, state=%d\n", c->state);
678
-					dst_blacklist_su( BLST_ERR_CONNECT, c->rcv.proto,
679
-										&c->rcv.src_su, 0);
680
-				}
676
+				dst_blacklist_su( BLST_ERR_CONNECT, c->rcv.proto,
677
+										&c->rcv.src_su, &c->send_flags, 0);
681 678
 #endif /* USE_DST_BLACKLIST */
682 679
 				TCP_EV_CONNECT_TIMEOUT(0, TCP_LADDR(c), TCP_LPORT(c),
683 680
 											TCP_PSU(c), TCP_PROTO(c));
684 681
 				TCP_STATS_CONNECT_FAILED();
685 682
 			}else{
686 683
 #ifdef USE_DST_BLACKLIST
687
-				if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
688
-					DBG("blacklisting, state=%d\n", c->state);
689
-					dst_blacklist_su( BLST_ERR_SEND, c->rcv.proto,
690
-										&c->rcv.src_su, 0);
691
-				}
684
+				dst_blacklist_su( BLST_ERR_SEND, c->rcv.proto,
685
+									&c->rcv.src_su, &c->send_flags, 0);
692 686
 #endif /* USE_DST_BLACKLIST */
693 687
 				TCP_EV_SEND_TIMEOUT(0, &c->rcv);
694 688
 				TCP_STATS_SEND_TIMEOUT();
... ...
@@ -872,10 +862,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
872 872
 							case ENETUNREACH:
873 873
 							case EHOSTUNREACH: /* not posix for send() */
874 874
 #ifdef USE_DST_BLACKLIST
875
-								if (cfg_get(core, core_cfg, use_dst_blacklist))
876
-									dst_blacklist_su(BLST_ERR_CONNECT,
877
-															c->rcv.proto,
878
-															&c->rcv.src_su, 0);
875
+								dst_blacklist_su(BLST_ERR_CONNECT,
876
+													c->rcv.proto,
877
+													&c->rcv.src_su,
878
+													&c->send_flags, 0);
879 879
 #endif /* USE_DST_BLACKLIST */
880 880
 								TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
881 881
 													TCP_LPORT(c), TCP_PSU(c),
... ...
@@ -884,10 +874,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
884 884
 							case ECONNREFUSED:
885 885
 							case ECONNRESET:
886 886
 #ifdef USE_DST_BLACKLIST
887
-								if (cfg_get(core, core_cfg, use_dst_blacklist))
888
-									dst_blacklist_su(BLST_ERR_CONNECT,
889
-															c->rcv.proto,
890
-															&c->rcv.src_su, 0);
887
+								dst_blacklist_su(BLST_ERR_CONNECT,
888
+													c->rcv.proto,
889
+													&c->rcv.src_su,
890
+													&c->send_flags, 0);
891 891
 #endif /* USE_DST_BLACKLIST */
892 892
 								TCP_EV_CONNECT_RST(0, TCP_LADDR(c),
893 893
 													TCP_LPORT(c), TCP_PSU(c),
... ...
@@ -908,10 +898,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
908 908
 							case ENETUNREACH:
909 909
 							case EHOSTUNREACH: /* not posix for send() */
910 910
 #ifdef USE_DST_BLACKLIST
911
-								if (cfg_get(core, core_cfg, use_dst_blacklist))
912
-									dst_blacklist_su(BLST_ERR_SEND,
913
-														c->rcv.proto,
914
-														&c->rcv.src_su, 0);
911
+								dst_blacklist_su(BLST_ERR_SEND,
912
+													c->rcv.proto,
913
+													&c->rcv.src_su,
914
+													&c->send_flags, 0);
915 915
 #endif /* USE_DST_BLACKLIST */
916 916
 								break;
917 917
 						}
... ...
@@ -1090,6 +1080,7 @@ error:
1090 1090
 inline static int tcp_do_connect(	union sockaddr_union* server,
1091 1091
 									union sockaddr_union* from,
1092 1092
 									int type,
1093
+									snd_flags_t* send_flags,
1093 1094
 									union sockaddr_union* res_local_addr,
1094 1095
 									struct socket_info** res_si,
1095 1096
 									enum tcp_conn_states *state
... ...
@@ -1134,23 +1125,23 @@ again:
1134 1134
 					case ENETUNREACH:
1135 1135
 					case EHOSTUNREACH:
1136 1136
 #ifdef USE_DST_BLACKLIST
1137
-						if (cfg_get(core, core_cfg, use_dst_blacklist))
1138
-							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1137
+						dst_blacklist_su(BLST_ERR_CONNECT, type, server,
1138
+											send_flags, 0);
1139 1139
 #endif /* USE_DST_BLACKLIST */
1140 1140
 						TCP_EV_CONNECT_UNREACHABLE(errno, 0, 0, server, type);
1141 1141
 						break;
1142 1142
 					case ETIMEDOUT:
1143 1143
 #ifdef USE_DST_BLACKLIST
1144
-						if (cfg_get(core, core_cfg, use_dst_blacklist))
1145
-							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1144
+						dst_blacklist_su(BLST_ERR_CONNECT, type, server,
1145
+											send_flags, 0);
1146 1146
 #endif /* USE_DST_BLACKLIST */
1147 1147
 						TCP_EV_CONNECT_TIMEOUT(errno, 0, 0, server, type);
1148 1148
 						break;
1149 1149
 					case ECONNREFUSED:
1150 1150
 					case ECONNRESET:
1151 1151
 #ifdef USE_DST_BLACKLIST
1152
-						if (cfg_get(core, core_cfg, use_dst_blacklist))
1153
-							dst_blacklist_su(BLST_ERR_CONNECT, type, server,0);
1152
+						dst_blacklist_su(BLST_ERR_CONNECT, type, server,
1153
+											send_flags, 0);
1154 1154
 #endif /* USE_DST_BLACKLIST */
1155 1155
 						TCP_EV_CONNECT_RST(errno, 0, 0, server, type);
1156 1156
 						break;
... ...
@@ -1169,7 +1160,7 @@ again:
1169 1169
 		}
1170 1170
 	}else{
1171 1171
 #endif /* TCP_ASYNC */
1172
-		if (tcp_blocking_connect(s, type, &server->s,
1172
+		if (tcp_blocking_connect(s, type,  send_flags, &server->s,
1173 1173
 									sockaddru_len(*server))<0){
1174 1174
 			LOG(L_ERR, "ERROR: tcp_do_connect: tcp_blocking_connect %s"
1175 1175
 						" failed\n", su2a(server, sizeof(*server)));
... ...
@@ -1219,9 +1210,9 @@ error:
1219 1219
 
1220 1220
 
1221 1221
 
1222
-struct tcp_connection* tcpconn_connect( union sockaddr_union* server, 
1222
+struct tcp_connection* tcpconn_connect( union sockaddr_union* server,
1223 1223
 										union sockaddr_union* from,
1224
-										int type)
1224
+										int type, snd_flags_t* send_flags)
1225 1225
 {
1226 1226
 	int s;
1227 1227
 	struct socket_info* si;
... ...
@@ -1238,7 +1229,7 @@ struct tcp_connection* tcpconn_connect( union sockaddr_union* server,
1238 1238
 					cfg_get(tcp, tcp_cfg, max_connections));
1239 1239
 		goto error;
1240 1240
 	}
1241
-	s=tcp_do_connect(server, from, type, &my_name, &si, &state);
1241
+	s=tcp_do_connect(server, from, type,  send_flags, &my_name, &si, &state);
1242 1242
 	if (s==-1){
1243 1243
 		LOG(L_ERR, "ERROR: tcp_do_connect %s: failed (%d) %s\n",
1244 1244
 				su2a(server, sizeof(*server)), errno, strerror(errno));
... ...
@@ -1250,6 +1241,7 @@ struct tcp_connection* tcpconn_connect( union sockaddr_union* server,
1250 1250
 				 " socket\n", su2a(server, sizeof(*server)));
1251 1251
 		goto error;
1252 1252
 	}
1253
+	tcpconn_set_send_flags(con, *send_flags);
1253 1254
 	return con;
1254 1255
 	/*FIXME: set sock idx! */
1255 1256
 error:
... ...
@@ -1271,7 +1263,8 @@ int tcpconn_finish_connect( struct tcp_connection* c,
1271 1271
 	struct tcp_conn_alias* a;
1272 1272
 	int new_conn_alias_flags;
1273 1273
 	
1274
-	s=tcp_do_connect(&c->rcv.src_su, from, c->type, &local_addr, &si, &state);
1274
+	s=tcp_do_connect(&c->rcv.src_su, from, c->type, &c->send_flags,
1275
+						&local_addr, &si, &state);
1275 1276
 	if (unlikely(s==-1)){
1276 1277
 		LOG(L_ERR, "ERROR: tcpconn_finish_connect %s: tcp_do_connect for %p"
1277 1278
 					" 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,
1787 1787
 				c=0;
1788 1788
 			}
1789 1789
 			/* check if connect() is disabled */
1790
-			if (unlikely((dst->send_flags & SND_F_FORCE_CON_REUSE) ||
1790
+			if (unlikely((dst->send_flags.f & SND_F_FORCE_CON_REUSE) ||
1791 1791
 							cfg_get(tcp, tcp_cfg, no_connect)))
1792 1792
 				return -1;
1793 1793
 			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,
1905 1905
 						case ENETUNREACH:
1906 1906
 						case EHOSTUNREACH:  /* not posix for send() */
1907 1907
 #ifdef USE_DST_BLACKLIST
1908
-							if (cfg_get(core, core_cfg, use_dst_blacklist))
1909
-								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1908
+							dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1910 1909
 #endif /* USE_DST_BLACKLIST */
1911 1910
 							TCP_EV_CONNECT_UNREACHABLE(errno, TCP_LADDR(c),
1912 1911
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
... ...
@@ -1914,8 +1906,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1914 1914
 						case ECONNREFUSED:
1915 1915
 						case ECONNRESET:
1916 1916
 #ifdef USE_DST_BLACKLIST
1917
-							if (cfg_get(core, core_cfg, use_dst_blacklist))
1918
-								dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1917
+							dst_blacklist_add( BLST_ERR_CONNECT, dst, 0);
1919 1918
 #endif /* USE_DST_BLACKLIST */
1920 1919
 							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
1921 1920
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
... ...
@@ -1934,7 +1925,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1934 1934
 				}
1935 1935
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
1936 1936
 				TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
1937
-				if (unlikely(dst->send_flags & SND_F_CON_CLOSE)){
1937
+				if (unlikely(dst->send_flags.f & SND_F_CON_CLOSE)){