Browse code

- dns cache support (ser will cache both positive and negative responses if turned on, see doc/dns.txt for more details & config options) - dns failover support: when a name resolves to more then 1 ip (either multiple A or AAAA records or multiple SRVs) and sending to the first ip fails, ser will retry with the others. By default is off. See doc/dns.txt for more details/config options a.s.o. - destination blacklist: when sending to some destination (defined by ip:port and protocol) fails, ser will temporarily add this destination in a blacklist giving future sends the opportunity of immediately failing. Destination are also added to the blacklist on tm invite timeouts (when no response is received in the fr_timer interval). By default is off, see doc/dst_blacklist.txt form more details/config options. - small makefile fixes (in mode=debug) - resolver get_record api changes (updated enum)

WARNING: there are a lot of changes in tm

Andrei Pelinescu-Onciul authored on 15/09/2006 10:37:44
Showing 37 changed files
... ...
@@ -66,7 +66,7 @@ MAIN_NAME=ser
66 66
 VERSION = 0
67 67
 PATCHLEVEL = 10
68 68
 SUBLEVEL =   99
69
-EXTRAVERSION = -dev42
69
+EXTRAVERSION = -dev43-dns_cache
70 70
 
71 71
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
72 72
 			$(SUBLEVEL) )
... ...
@@ -339,6 +339,14 @@ endif
339 339
 #		compiles in checks and use for maddr parameter in uri.
340 340
 #		Required to support Windows Messenger 5.x over TCP connection
341 341
 #		which (mis)uses this parameter.
342
+# -DUSE_DNS_CACHE
343
+#		use an internal dns cache instead of making dns requests each time
344
+# -DUSE_DNS_FAILOVER
345
+#		if the destination resolves to multiple ips, on send error fall back
346
+#		to the others
347
+# -DUSE_DST_BLACKLIST
348
+#		blacklist bad destination (timeout, failed to connect, error sending
349
+#        a.s.o)
342 350
 
343 351
 # Sometimes is needes correct non-quoted $OS. HACK: gcc translates known OS to number ('linux'), so there is added underscore
344 352
 
... ...
@@ -356,6 +364,9 @@ DEFS+= $(extra_defs) \
356 364
 	 -DDISABLE_NAGLE \
357 365
 	 -DHAVE_RESOLV_RES \
358 366
 	 -DDBG_QM_MALLOC \
367
+	 -DUSE_DNS_CACHE \
368
+	 -DUSE_DNS_FAILOVER \
369
+	 -DUSE_DST_BLACKLIST \
359 370
 	 #-DF_MALLOC \
360 371
 	 #-DDBG_F_MALLOC \
361 372
 	 #-DNO_DEBUG \
... ...
@@ -1092,7 +1103,6 @@ $(error 			Unsupported compiler ($(CC):$(CC_NAME)), try gcc)
1092 1103
 endif		#CC_NAME, gcc
1093 1104
 endif	#ARCH, ppc 
1094 1105
 
1095
-CFLAGS+= $(CC_EXTRA_OPTS)
1096 1106
 
1097 1107
 
1098 1108
 # setting LDFLAGS
... ...
@@ -1122,6 +1132,7 @@ endif
1122 1132
 else	#mode,release
1123 1133
 ifeq	($(CC_NAME), gcc)
1124 1134
 		CFLAGS=-g -Wcast-align $(PROFILE)
1135
+		DEFS+=-DCC_GCC_LIKE_ASM
1125 1136
 ifeq		($(ARCH), sparc64)
1126 1137
 			DEFS+=SPARC64_MODE
1127 1138
 			CFLAGS+= -mcpu=ultrasparc -m64
... ...
@@ -1138,6 +1149,7 @@ else
1138 1149
 endif
1139 1150
 endif
1140 1151
 ifeq	($(CC_NAME), icc)
1152
+		DEFS+=-DCC_GCC_LIKE_ASM
1141 1153
 		CFLAGS=-g  $(PROFILE)
1142 1154
 		LDFLAGS+=-g -Wl,-E $(PROFILE)
1143 1155
 		MOD_LDFLAGS=-shared $(LDFLAGS)
... ...
@@ -1150,6 +1162,7 @@ endif
1150 1162
 
1151 1163
 endif #mode=release
1152 1164
 
1165
+CFLAGS+= $(CC_EXTRA_OPTS)
1153 1166
 
1154 1167
 #*FLAGS used for compiling the modules
1155 1168
 ifeq	($(CC_NAME), gcc)
... ...
@@ -24,7 +24,8 @@ modules:
24 24
                 hashing after an uri (to, from or request uri)
25 25
               - improved uri hashing (password is ignored, port is used only
26 26
                 if != 5060 or 5061)
27
- - tm        - migrated to the new timers (tm timers completely rewritten)
27
+ - tm        - dns failover and dst blacklist support
28
+             - migrated to the new timers (tm timers completely rewritten)
28 29
              - improved speed and less memory usage
29 30
              - much more precise reptransmissions timing
30 31
              - params: - retr_timer1p1, retr_timer1p2, retr_timer1p3 removed
... ...
@@ -49,6 +50,11 @@ modules:
49 50
               Vias a.s.o) and not on the original message
50 51
  
51 52
 core:
53
+ - dns cache and dns failover support added (see doc/dns.txt)
54
+ - destination blacklist added -- destinations to which forwarding fails
55
+   (send error, tm timeout a.s.o) are temporarily added to a blacklist which 
56
+    is consulted before each send => faster send error detection
57
+    in the near future (see doc/dst_blacklist.txt)
52 58
  - default log level switched to 0 (only messages < L_WARN will be printed
53 59
    by default)
54 60
  - separate memdbg log level which controls the memory/malloc related
... ...
@@ -113,7 +119,7 @@ core:
113 119
  - tcp: - improved  performance (io event handling), using OS specific
114 120
            optimizations
115 121
         - 1024 connections limit removed (see tcp_max_connections)
116
--  resolver: - timeouts, retries a.s.o can no be set from ser.cfg
122
+-  resolver: - timeouts, retries a.s.o can now be set from ser.cfg
117 123
              (see below dns_* and man resolv.conf(6)).
118 124
              The maximum time a dns request can take (before failing) is:
119 125
               (dns_retr_time*dns_retr_no)*(search_list_domains)
... ...
@@ -130,6 +136,21 @@ core:
130 136
    are available (see tm docs)
131 137
 - avps directly accessible from script with %avp_name (variable style)
132 138
 new config variables:
139
+   use_dns_cache = on | off  (default on)  
140
+   use_dns_failover = on | off (default off)
141
+   dns_cache_flags = number (default 0)
142
+   dns_cache_negative_ttl = number in seconds (default 60)
143
+   dns_cache_min_ttl = time in seconds (default 0)
144
+   dns_cache_max_ttl = time in seconds (default MAXINT)
145
+   dns_cache_mem = maximum memory used for the dns cache in Kb (default 500 K)
146
+   dns_cache_gc_interval = interval in seconds after which the dns cache is
147
+      garbage collected (default: 120 s)
148
+   use_dst_blacklist = on | off (default off)
149
+   dst_blacklist_expire = time in s (default 60)
150
+   dst_blacklist_mem = maximum memory used for the blacklist in Kb (default 250
151
+      K)
152
+   dst_blacklist_gc_interval = interval in seconds after which the destination 
153
+      blacklist is garbage collected (default 60)
133 154
    tos = number  - ip type of service (TOS) value
134 155
    dns_try_ipv6 = yes/no - if yes and a dns lookup fails, it will retry it
135 156
       for ipv6 (AAAA record). Default: yes
... ...
@@ -138,7 +159,7 @@ new config variables:
138 159
       (usually 5s).
139 160
    dns_retr_no = no. - number of dns retransmissions before giving up.
140 161
       Default: see above (usually 4)
141
-   dns_server_no = no. - how many dns servers from the ones defined in 
162
+   dns_servers_no = no. - how many dns servers from the ones defined in 
142 163
       /etc/resolv.conf will be used. Default: all of them.
143 164
    dns_use_search_list= yes/no - if no, the search list in /etc/resolv.conf
144 165
       will be ignored (=> fewer lookups => gives up faster). Default: yes.
... ...
@@ -41,6 +41,7 @@
41 41
  *  2005-12-12  return & drop/exit differentiation (andrei)
42 42
  *  2005-12-19  select framework (mma)
43 43
  *  2006-04-12  updated *_send() calls to use a struct dest_info (andrei)
44
+ *  2006-07-27  dns cache and dns based send address failover support (andrei)
44 45
  */
45 46
 
46 47
 
... ...
@@ -107,6 +108,7 @@ int do_action(struct action* a, struct sip_msg* msg)
107 108
 	unsigned short port;
108 109
 	unsigned short flags;
109 110
 	int_str name, value;
111
+	str* dst_host;
110 112
 
111 113
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
112 114
 	   functions to return with error (status<0) and not setting it
... ...
@@ -208,32 +210,24 @@ int do_action(struct action* a, struct sip_msg* msg)
208 210
 #endif
209 211
 				}
210 212
 
211
-#ifdef HONOR_MADDR
212
-				if (u->maddr_val.s && u->maddr_val.len) {
213
-					if (sip_hostport2su(&dst.to, &u->maddr_val, port, dst.proto)<0){
214
-						LOG(L_ERR, "ERROR:  bad maddr param in uri,"
215
-								" dropping packet\n");
216
-						ret=E_BAD_ADDRESS;
217
-						goto error_fwd_uri;
218
-					}
219
-				} else
213
+#ifdef HONOR_MADDR				
214
+				if (u->maddr_val.s && u->maddr_val.len)
215
+					dst_host=&u->maddr_val;
216
+				else
220 217
 #endif
221
-				if (sip_hostport2su(&dst.to, &u->host, port, dst.proto)<0){
222
-					LOG(L_ERR, "ERROR:  bad host name in uri,"
223
-							" dropping packet\n");
224
-					ret=E_BAD_ADDRESS;
225
-					goto error_fwd_uri;
226
-				}
218
+					dst_host=&u->host;
227 219
 #ifdef USE_COMP
228 220
 				dst.comp=u->comp;
229 221
 #endif
230
-				ret=forward_request(msg, &dst);
231
-				if (ret>=0) ret=1;
222
+				ret=forward_request(msg, dst_host, port, &dst);
223
+				if (ret>=0){
224
+					ret=1;
225
+				}
232 226
 			}else if ((a->val[0].type==PROXY_ST) && (a->val[1].type==NUMBER_ST)){
233 227
 				if (dst.proto==PROTO_NONE)
234 228
 					dst.proto=msg->rcv.proto;
235 229
 				proxy2su(&dst.to,  (struct proxy_l*)a->val[0].u.data);
236
-				ret=forward_request(msg, &dst);
230
+				ret=forward_request(msg, 0, 0, &dst);
237 231
 				if (ret>=0){
238 232
 					ret=1;
239 233
 					proxy_mark((struct proxy_l*)a->val[0].u.data, ret);
... ...
@@ -60,6 +60,8 @@
60 60
  *              to_{ip,port} (andrei)
61 61
  *  2005-12-12  separated drop, exit, break, return, added RETCODE (andrei)
62 62
  *  2005-12-19  select framework (mma)
63
+ * 2006-09-11  added dns cache (use, flags, ttls, mem ,gc) & dst blacklist
64
+ *              options (andrei)
63 65
  */
64 66
 
65 67
 
... ...
@@ -228,6 +230,22 @@ DNS_RETR_TIME	dns_retr_time
228 230
 DNS_RETR_NO		dns_retr_no
229 231
 DNS_SERVERS_NO	dns_servers_no
230 232
 DNS_USE_SEARCH	dns_use_search_list
233
+/* dns cache */
234
+DNS_USE_CACHE	use_dns_cache
235
+DNS_USE_FAILOVER	use_dns_failover
236
+DNS_CACHE_FLAGS		dns_cache_flags
237
+DNS_CACHE_NEG_TTL	dns_cache_negative_ttl
238
+DNS_CACHE_MIN_TTL	dns_cache_min_ttl
239
+DNS_CACHE_MAX_TTL	dns_cache_max_ttl
240
+DNS_CACHE_MEM		dns_cache_mem
241
+DNS_CACHE_GC_INT	dns_cache_gc_interval
242
+/* blacklist */
243
+USE_DST_BLST		use_dst_blacklist
244
+DST_BLST_MEM		dst_blacklist_mem
245
+DST_BLST_TTL		dst_blacklist_expire|dst_blacklist_ttl
246
+DST_BLST_GC_INT		dst_blacklist_gc_interval
247
+
248
+
231 249
 PORT	port
232 250
 STAT	statistics
233 251
 MAXBUFFER maxbuffer
... ...
@@ -422,6 +440,30 @@ EAT_ABLE	[\ \t\b\r]
422 440
 								return DNS_SERVERS_NO; }
423 441
 <INITIAL>{DNS_USE_SEARCH}	{ count(); yylval.strval=yytext;
424 442
 								return DNS_USE_SEARCH; }
443
+<INITIAL>{DNS_USE_CACHE}	{ count(); yylval.strval=yytext;
444
+								return DNS_USE_CACHE; }
445
+<INITIAL>{DNS_USE_FAILOVER}	{ count(); yylval.strval=yytext;
446
+								return DNS_USE_FAILOVER; }
447
+<INITIAL>{DNS_CACHE_FLAGS}	{ count(); yylval.strval=yytext;
448
+								return DNS_CACHE_FLAGS; }
449
+<INITIAL>{DNS_CACHE_NEG_TTL}	{ count(); yylval.strval=yytext;
450
+								return DNS_CACHE_NEG_TTL; }
451
+<INITIAL>{DNS_CACHE_MIN_TTL}	{ count(); yylval.strval=yytext;
452
+								return DNS_CACHE_MIN_TTL; }
453
+<INITIAL>{DNS_CACHE_MAX_TTL}	{ count(); yylval.strval=yytext;
454
+								return DNS_CACHE_MAX_TTL; }
455
+<INITIAL>{DNS_CACHE_MEM}	{ count(); yylval.strval=yytext;
456
+								return DNS_CACHE_MEM; }
457
+<INITIAL>{DNS_CACHE_GC_INT}	{ count(); yylval.strval=yytext;
458
+								return DNS_CACHE_GC_INT; }
459
+<INITIAL>{USE_DST_BLST}	{ count(); yylval.strval=yytext;
460
+								return USE_DST_BLST; }
461
+<INITIAL>{DST_BLST_MEM}	{ count(); yylval.strval=yytext;
462
+								return DST_BLST_MEM; }
463
+<INITIAL>{DST_BLST_TTL}	{ count(); yylval.strval=yytext;
464
+								return DST_BLST_TTL; }
465
+<INITIAL>{DST_BLST_GC_INT}	{ count(); yylval.strval=yytext;
466
+								return DST_BLST_GC_INT; }
425 467
 <INITIAL>{PORT}	{ count(); yylval.strval=yytext; return PORT; }
426 468
 <INITIAL>{STAT}	{ count(); yylval.strval=yytext; return STAT; }
427 469
 <INITIAL>{MAXBUFFER}	{ count(); yylval.strval=yytext; return MAXBUFFER; }
... ...
@@ -72,6 +72,8 @@
72 72
  * 2006-02-02  named flags support (andrei)
73 73
  * 2006-02-06  named routes support (andrei)
74 74
  * 2006-05-30  avp flags (tma)
75
+ * 2006-09-11  added dns cache (use, flags, ttls, mem ,gc) & dst blacklist
76
+ *              options (andrei)
75 77
  */
76 78
 
77 79
 %{
... ...
@@ -117,6 +119,26 @@
117 119
 		if (rt!=ONSEND_ROUTE) yyerror( s " allowed only in onsend_routes");\
118 120
 	}while(0)
119 121
 
122
+
123
+#ifdef USE_DNS_CACHE
124
+	#define IF_DNS_CACHE(x) x
125
+#else
126
+	#define IF_DNS_CACHE(x) warn("dns cache support not compiled in")
127
+#endif
128
+
129
+#ifdef USE_DNS_FAILOVER
130
+	#define IF_DNS_FAILOVER(x) x
131
+#else
132
+	#define IF_DNS_FAILOVER(x) warn("dns failover support not compiled in")
133
+#endif
134
+
135
+#ifdef USE_DST_BLACKLIST
136
+	#define IF_DST_BLACKLIST(x) x
137
+#else
138
+	#define IF_DST_BLACKLIST(x) warn("dst blacklist support not compiled in")
139
+#endif
140
+
141
+
120 142
 extern int yylex();
121 143
 static void yyerror(char* s);
122 144
 static char* tmp;
... ...
@@ -234,6 +256,20 @@ static struct socket_id* mk_listen_id(char*, int, int);
234 256
 %token DNS_RETR_NO
235 257
 %token DNS_SERVERS_NO
236 258
 %token DNS_USE_SEARCH
259
+%token DNS_USE_CACHE
260
+%token DNS_USE_FAILOVER
261
+%token DNS_CACHE_FLAGS
262
+%token DNS_CACHE_NEG_TTL
263
+%token DNS_CACHE_MIN_TTL
264
+%token DNS_CACHE_MAX_TTL
265
+%token DNS_CACHE_MEM
266
+%token DNS_CACHE_GC_INT
267
+/*blacklist*/
268
+%token USE_DST_BLST
269
+%token DST_BLST_MEM
270
+%token DST_BLST_TTL
271
+%token DST_BLST_GC_INT
272
+
237 273
 %token PORT
238 274
 %token STAT
239 275
 %token CHILDREN
... ...
@@ -512,6 +548,30 @@ assign_stm:
512 548
 	| DNS_SERVERS_NO error { yyerror("number expected"); }
513 549
 	| DNS_USE_SEARCH EQUAL NUMBER   { dns_search_list=$3; }
514 550
 	| DNS_USE_SEARCH error { yyerror("boolean value expected"); }
551
+	| DNS_USE_CACHE EQUAL NUMBER   { IF_DNS_CACHE(use_dns_cache=$3); }
552
+	| DNS_USE_CACHE error { yyerror("boolean value expected"); }
553
+	| DNS_USE_FAILOVER EQUAL NUMBER   { IF_DNS_FAILOVER(use_dns_failover=$3);}
554
+	| DNS_USE_FAILOVER error { yyerror("boolean value expected"); }
555
+	| DNS_CACHE_FLAGS EQUAL NUMBER   { IF_DNS_CACHE(dns_flags=$3); }
556
+	| DNS_CACHE_FLAGS error { yyerror("boolean value expected"); }
557
+	| DNS_CACHE_NEG_TTL EQUAL NUMBER   { IF_DNS_CACHE(dns_neg_cache_ttl=$3); }
558
+	| DNS_CACHE_NEG_TTL error { yyerror("boolean value expected"); }
559
+	| DNS_CACHE_MAX_TTL EQUAL NUMBER   { IF_DNS_CACHE(dns_cache_max_ttl=$3); }
560
+	| DNS_CACHE_MAX_TTL error { yyerror("boolean value expected"); }
561
+	| DNS_CACHE_MIN_TTL EQUAL NUMBER   { IF_DNS_CACHE(dns_cache_min_ttl=$3); }
562
+	| DNS_CACHE_MIN_TTL error { yyerror("boolean value expected"); }
563
+	| DNS_CACHE_MEM EQUAL NUMBER   { IF_DNS_CACHE(dns_cache_max_mem=$3); }
564
+	| DNS_CACHE_MEM error { yyerror("boolean value expected"); }
565
+	| DNS_CACHE_GC_INT EQUAL NUMBER   { IF_DNS_CACHE(dns_timer_interval=$3); }
566
+	| DNS_CACHE_GC_INT error { yyerror("boolean value expected"); }
567
+	| USE_DST_BLST EQUAL NUMBER   { IF_DST_BLACKLIST(use_dst_blacklist=$3); }
568
+	| USE_DST_BLST error { yyerror("boolean value expected"); }
569
+	| DST_BLST_MEM EQUAL NUMBER   { IF_DST_BLACKLIST(blst_max_mem=$3); }
570
+	| DST_BLST_MEM error { yyerror("boolean value expected"); }
571
+	| DST_BLST_TTL EQUAL NUMBER   { IF_DST_BLACKLIST(blst_timeout=$3); }
572
+	| DST_BLST_TTL error { yyerror("boolean value expected"); }
573
+	| DST_BLST_GC_INT EQUAL NUMBER { IF_DST_BLACKLIST(blst_timer_interval=$3);}
574
+	| DST_BLST_GC_INT error { yyerror("boolean value expected"); }
515 575
 	| PORT EQUAL NUMBER   { port_no=$3; }
516 576
 	| STAT EQUAL STRING {
517 577
 		#ifdef STATS
... ...
@@ -1828,7 +1888,7 @@ static void warn(char* s)
1828 1888
 {
1829 1889
 	LOG(L_WARN, "cfg. warning: (%d,%d-%d): %s\n", line, startcolumn,
1830 1890
 			column, s);
1831
-	cfg_errors++;
1891
+	cfg_warnings++;
1832 1892
 }
1833 1893
 
1834 1894
 static void yyerror(char* s)
... ...
@@ -46,6 +46,10 @@
46 46
 
47 47
 /* adds an entire sublist { s,e } (including s & e )
48 48
  * after head
49
+ * WARNING: clist_insert_sublist(head, n, n->prev) won't work,
50
+ *          same for clist_insert_sublist(head, n->next, n)
51
+ *  (macro!), use  e=n->prev; clist_insert_sublist(head, n, e, ...)
52
+ *  instead!
49 53
  */
50 54
 #define clist_insert_sublist(head, s, e, next, prev) \
51 55
 	do{ \
... ...
@@ -59,6 +63,9 @@
59 63
 
60 64
 /* appends an entire sublist { s,e } (including s & e )
61 65
  * at the end of the list
66
+ * WARNING: clist_append_sublist(head, n, n->prev, ...) won't work,
67
+ *  (macro!), use  e=n->prev; clist_append_sublist(head, n, e, ...)
68
+ *  instead!
62 69
  */
63 70
 #define clist_append_sublist(head, s, e, next, prev) \
64 71
 	do{ \
... ...
@@ -70,9 +77,13 @@
70 77
 
71 78
 
72 79
 
80
+
73 81
 /* remove sublist { s,e } (including s & e )
74 82
  * always, if start is the beginning of the list use
75
- * clist_rm_sublist(head->next, e, next, prev ) */
83
+ * clist_rm_sublist(head->next, e, next, prev )
84
+ * WARNING: clist_rm_sublist(n, n->prev, ...) won't work,
85
+ *  (macro!), use  e=n->prev; clist_rm_sublist(n, e, ...)
86
+ *  instead! */
76 87
 #define clist_rm_sublist(s, e, next, prev) \
77 88
 	do{\
78 89
 		(s)->prev->next=(e)->next;  \
... ...
@@ -39,6 +39,40 @@
39 39
 #include "tcp_info.h"
40 40
 #include "core_cmd.h"
41 41
 
42
+#ifdef USE_DNS_CACHE
43
+void dns_cache_debug(rpc_t* rpc, void* ctx);
44
+void dns_cache_debug_all(rpc_t* rpc, void* ctx);
45
+void dns_cache_mem_info(rpc_t* rpc, void* ctx);
46
+
47
+static const char* dns_cache_mem_info_doc[] = {
48
+	"dns cache memory info.",    /* Documentation string */
49
+	0                      /* Method signature(s) */
50
+};
51
+static const char* dns_cache_debug_doc[] = {
52
+	"dns debug  info.",    /* Documentation string */
53
+	0                      /* Method signature(s) */
54
+};
55
+
56
+static const char* dns_cache_debug_all_doc[] = {
57
+	"complete dns debug  dump",    /* Documentation string */
58
+	0                              /* Method signature(s) */
59
+};
60
+#endif
61
+#ifdef USE_DST_BLACKLIST
62
+void dst_blst_debug(rpc_t* rpc, void* ctx);
63
+void dst_blst_mem_info(rpc_t* rpc, void* ctx);
64
+
65
+static const char* dst_blst_mem_info_doc[] = {
66
+	"dst blacklist memory usage info.",  /* Documentation string */
67
+	0                                    /* Method signature(s) */
68
+};
69
+static const char* dst_blst_debug_doc[] = {
70
+	"dst blacklist  debug  info.",  /* Documentation string */
71
+	0                               /* Method signature(s) */
72
+};
73
+#endif
74
+
75
+
42 76
 
43 77
 #define MAX_CTIME_LEN 128
44 78
 
... ...
@@ -312,6 +346,15 @@ rpc_export_t core_rpc_methods[] = {
312 346
 	{"core.kill",              core_kill,              core_kill_doc,              0        },
313 347
 	{"core.shmmem",            core_shmmem,            core_shmmem_doc,            0	},
314 348
 	{"core.tcp_info",          core_tcpinfo,           core_tcpinfo_doc,          0	},
349
+#ifdef USE_DNS_CACHE
350
+	{"dns.mem_info",          dns_cache_mem_info,     dns_cache_mem_info_doc,     0	},
351
+	{"dns.debug",          dns_cache_debug,           dns_cache_debug_doc,        0	},
352
+	{"dns.debug_all",      dns_cache_debug_all,       dns_cache_debug_all_doc,        0	},
353
+#endif
354
+#ifdef USE_DST_BLACKLIST
355
+	{"dst_blacklist.mem_info",  dst_blst_mem_info,     dst_blst_mem_info_doc,     0	},
356
+	{"dst_blacklist.debug",    dst_blst_debug,         dst_blst_debug_doc,        0	},
357
+#endif
315 358
 	{0, 0, 0, 0}
316 359
 };
317 360
 
318 361
new file mode 100644
... ...
@@ -0,0 +1,2436 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * resolver related functions
5
+ *
6
+ * Copyright (C) 2006 iptelorg GmbH
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ */
29
+/* History:
30
+ * --------
31
+ *  2006-07-13  created by andrei
32
+ */
33
+
34
+#ifdef USE_DNS_CACHE
35
+
36
+#include "globals.h"
37
+#include "dns_cache.h"
38
+#include "dns_wrappers.h"
39
+#include "mem/shm_mem.h"
40
+#include "hashes.h"
41
+#include "clist.h"
42
+#include "locking.h"
43
+#include "atomic_ops.h"
44
+#include "ut.h"
45
+#include "timer.h"
46
+#include "timer_ticks.h"
47
+#include "error.h"
48
+#include "rpc.h"
49
+
50
+
51
+
52
+#define DNS_CACHE_DEBUG /* extra sanity checks and debugging */
53
+
54
+
55
+#ifndef MAX
56
+	#define MAX(a,b) ( ((a)>(b))?(a):(b))
57
+#endif
58
+
59
+#define MAX_DNS_RECORDS 255  /* maximum dns records number  received in a 
60
+							   dns answer*/
61
+
62
+#define DNS_HASH_SIZE	1024 /* must be <= 65535 */
63
+#define DEFAULT_DNS_NEG_CACHE_TTL 60 /* 1 min. */
64
+#define DEFAULT_DNS_CACHE_MIN_TTL 0 /* (disabled) */
65
+#define DEFAULT_DNS_CACHE_MAX_TTL ((unsigned int)(-1)) /* (maxint) */
66
+#define DEFAULT_DNS_MAX_MEM 500 /* 500 Kb */
67
+#define DEFAULT_DNS_TIMER_INTERVAL 120  /* 2 min. */
68
+#define DNS_HE_MAX_ADDR 10  /* maxium addresses returne in a hostent struct */
69
+#define MAX_CNAME_CHAIN  10 
70
+
71
+
72
+static gen_lock_t* dns_hash_lock=0;
73
+static volatile unsigned int *dns_cache_mem_used=0; /* current mem. use */
74
+unsigned int dns_cache_max_mem=DEFAULT_DNS_MAX_MEM; /* maximum memory used for
75
+													 the cached entries */
76
+unsigned int dns_neg_cache_ttl=DEFAULT_DNS_NEG_CACHE_TTL; /* neg. cache ttl */
77
+unsigned int dns_cache_max_ttl=DEFAULT_DNS_CACHE_MAX_TTL; /* maximum ttl */
78
+unsigned int dns_cache_min_ttl=DEFAULT_DNS_CACHE_MIN_TTL; /* minimum ttl */
79
+unsigned int dns_timer_interval=DEFAULT_DNS_TIMER_INTERVAL; /* in s */
80
+int dns_flags=0; /* default flags used for the  dns_*resolvehost 
81
+                    (compatibility wrappers) */
82
+
83
+#define LOCK_DNS_HASH()		lock_get(dns_hash_lock)
84
+#define UNLOCK_DNS_HASH()	lock_release(dns_hash_lock)
85
+
86
+#define FIX_TTL(t)  (((t)<dns_cache_min_ttl)?dns_cache_min_ttl: \
87
+						(((t)>dns_cache_max_ttl)?dns_cache_max_ttl:(t)))
88
+
89
+
90
+struct dns_hash_head{
91
+	struct dns_hash_entry* next;
92
+	struct dns_hash_entry* prev;
93
+};
94
+
95
+#ifdef DNS_LU_LST
96
+struct dns_lu_lst* dns_last_used_lst=0;
97
+#endif
98
+
99
+static struct dns_hash_head* dns_hash=0;
100
+
101
+
102
+static struct timer_ln* dns_timer_h=0;
103
+
104
+
105
+
106
+static const char* dns_str_errors[]={
107
+	"no error",
108
+	"no more records", /* not an error, but and end condition */
109
+	"unknown error",
110
+	"internal error",
111
+	"bad SRV entry",
112
+	"unresolvable SRV request",
113
+	"bad A or AAAA entry",
114
+	"unresovlable A or AAAA request",
115
+	"invalid ip in A or AAAA record",
116
+	"blacklisted ip",
117
+	"name too long ", /* try again with a shorter name */
118
+	"ip AF mismatch", /* address family mismatch */
119
+	"bug - critical error"
120
+};
121
+
122
+
123
+
124
+/* param: err (negative error number) */
125
+const char* dns_strerror(int err)
126
+{
127
+	err=-err;
128
+	if ((err>=0) && (err<sizeof(dns_str_errors)/sizeof(char*)))
129
+		return dns_str_errors[err];
130
+	return "bug -- bad error number";
131
+}
132
+
133
+
134
+
135
+/* "internal" only, don't use unless you really know waht you're doing */
136
+inline static void dns_destroy_entry(struct dns_hash_entry* e)
137
+{
138
+#ifdef DNS_CACHE_DEBUG
139
+	memset(e, 0, e->total_size);
140
+#endif
141
+	shm_free(e); /* nice having it in one block isn't it? :-) */
142
+}
143
+
144
+
145
+/* "internal" only, same as above, asumes shm_lock() held (tm optimization) */
146
+inline static void dns_destroy_entry_shm_unsafe(struct dns_hash_entry* e)
147
+{
148
+#ifdef DNS_CACHE_DEBUG
149
+	memset(e, 0, e->total_size);
150
+#endif
151
+	shm_free_unsafe(e); /* nice having it in one block isn't it? :-) */
152
+}
153
+
154
+
155
+
156
+/* dec. the internal refcnt and if 0 deletes the entry */
157
+void dns_hash_put(struct dns_hash_entry* e)
158
+{
159
+	if(e && atomic_dec_and_test(&e->refcnt)){
160
+		/* atomic_sub_long(dns_cache_total_used, e->total_size); */
161
+		dns_destroy_entry(e);
162
+	}
163
+}
164
+
165
+
166
+
167
+/* same as above but uses dns_destroy_unsafe (assumes shm_lock held -- tm
168
+ *  optimization) */
169
+void dns_hash_put_shm_unsafe(struct dns_hash_entry* e)
170
+{
171
+	if(e && atomic_dec_and_test(&e->refcnt)){
172
+		/* atomic_sub_long(dns_cache_total_used, e->total_size); */
173
+		dns_destroy_entry_shm_unsafe(e);
174
+	}
175
+}
176
+
177
+
178
+inline static int dns_cache_clean(unsigned int no, int expired_only);
179
+inline static int dns_cache_free_mem(unsigned int target, int expired_only);
180
+
181
+static ticks_t dns_timer(ticks_t ticks, struct timer_ln* tl, void* data)
182
+{
183
+	if (*dns_cache_mem_used>12*(dns_cache_max_mem/16)){ /* ~ 75% used */
184
+		dns_cache_free_mem(dns_cache_max_mem/2, 1); 
185
+	}else{
186
+		dns_cache_clean(-1, 1); /* all the table, only expired entries */
187
+		/* TODO: better strategy? */
188
+	}
189
+	return (ticks_t)(-1);
190
+}
191
+
192
+
193
+
194
+void destroy_dns_cache()
195
+{
196
+	if (dns_timer_h){
197
+		timer_del(dns_timer_h);
198
+		timer_free(dns_timer_h);
199
+		dns_timer_h=0;
200
+	}
201
+	if (dns_hash_lock){
202
+		lock_destroy(dns_hash_lock);
203
+		lock_dealloc(dns_hash_lock);
204
+		dns_hash_lock=0;
205
+	}
206
+	if (dns_hash){
207
+		shm_free(dns_hash);
208
+		dns_hash=0;
209
+	}
210
+#ifdef DNS_LU_LST
211
+	if (dns_last_used_lst){
212
+		shm_free(dns_last_used_lst);
213
+		dns_last_used_lst=0;
214
+	}
215
+#endif
216
+	if (dns_cache_mem_used){
217
+		shm_free((void*)dns_cache_mem_used);
218
+		dns_cache_mem_used=0;
219
+	}
220
+}
221
+
222
+
223
+
224
+int init_dns_cache()
225
+{
226
+	int r;
227
+	int ret;
228
+	
229
+	ret=0;
230
+	/* sanity check */
231
+	if (E_DNS_CRITICAL>=sizeof(dns_str_errors)/sizeof(char*)){
232
+		LOG(L_CRIT, "BUG: dns_cache_init: bad dns error table\n");
233
+		ret=E_BUG;
234
+		goto error;
235
+	}
236
+	dns_cache_mem_used=shm_malloc(sizeof(*dns_cache_mem_used));
237
+	if (dns_cache_mem_used==0){
238
+		ret=E_OUT_OF_MEM;
239
+		goto error;
240
+	}
241
+#ifdef DNS_LU_LST
242
+	dns_last_used_lst=shm_malloc(sizeof(*dns_last_used_lst));
243
+	if (dns_last_used_lst==0){
244
+		ret=E_OUT_OF_MEM;
245
+		goto error;
246
+	}
247
+	clist_init(dns_last_used_lst, next, prev);
248
+#endif
249
+	dns_hash=shm_malloc(sizeof(struct dns_hash_head)*DNS_HASH_SIZE);
250
+	if (dns_hash==0){
251
+		ret=E_OUT_OF_MEM;
252
+		goto error;
253
+	}
254
+	for (r=0; r<DNS_HASH_SIZE; r++)
255
+		clist_init(&dns_hash[r], next, prev);
256
+	
257
+	dns_hash_lock=lock_alloc();
258
+	if (dns_hash_lock==0){
259
+		ret=E_OUT_OF_MEM;
260
+		goto error;
261
+	}
262
+	if (lock_init(dns_hash_lock)==0){
263
+		lock_dealloc(dns_hash_lock);
264
+		dns_hash_lock=0;
265
+		ret=-1;
266
+		goto error;
267
+	}
268
+	
269
+	/* fix options */
270
+	dns_cache_max_mem<<=10; /* Kb */ /* TODO: test with 0 */
271
+	/* fix flags */
272
+	if (dns_try_ipv6==0){
273
+		dns_flags|=DNS_IPV4_ONLY;
274
+	}
275
+	if (dns_flags & DNS_IPV4_ONLY){
276
+		dns_flags&=~(DNS_IPV6_ONLY|DNS_IPV6_FIRST);
277
+	}
278
+			;
279
+	dns_timer_h=timer_alloc();
280
+	if (dns_timer_h==0){
281
+		ret=E_OUT_OF_MEM;
282
+		goto error;
283
+	}
284
+	if (dns_timer_interval){
285
+		timer_init(dns_timer_h, dns_timer, 0, 0); /* "slow" timer */
286
+		if (timer_add(dns_timer_h, S_TO_TICKS(dns_timer_interval))<0){
287
+			LOG(L_CRIT, "BUG: dns_cache_init: failed to add the timer\n");
288
+			timer_free(dns_timer_h);
289
+			dns_timer_h=0;
290
+			goto error;
291
+		}
292
+	}
293
+	
294
+	return 0;
295
+error:
296
+	destroy_dns_cache();
297
+	return ret;
298
+}
299
+
300
+
301
+/* hash function, based on get_hash1_raw, but case insensitive
302
+ * type is not used (obsolete)
303
+ * returns the hash value
304
+ */
305
+inline static unsigned int dns_hash_no(char* s, int len, int type)
306
+{
307
+	char* p;
308
+	char* end;
309
+	
310
+	register unsigned v;
311
+	register unsigned h;
312
+	
313
+	h=0;
314
+	
315
+	hash_update_str(s, s+len, p, v, h);
316
+	end=s+len;
317
+	for (p=s; p<=(end-4); p+=4){
318
+		v=((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3])|0x20202020;
319
+		h+=v^(v>>3);
320
+	}
321
+	v=0;
322
+	for (;p<end; p++){ v<<=8; v+=*p|0x20;}
323
+	h+=v^(v>>3);
324
+	return hash_finish(h) % DNS_HASH_SIZE;
325
+}
326
+
327
+
328
+
329
+#ifdef DNS_CACHE_DEBUG
330
+#define DEBUG_LU_LST
331
+#ifdef DEBUG_LU_LST
332
+
333
+#include <stdlib.h> /* abort() */
334
+#define check_lu_lst(l) ((((l)->next==(l)) || ((l)->prev==(l))) && \
335
+							((l)!=dns_last_used_lst))
336
+
337
+#define dbg_lu_lst(txt, l) \
338
+		LOG(L_CRIT, "BUG: %s: crt(%p, %p, %p)," \
339
+					" prev(%p, %p, %p), next(%p, %p, %p)\n", txt, \
340
+					(l), (l)->next, (l)->prev, \
341
+					(l)->prev, (l)->prev->next, (l)->prev->prev, \
342
+					(l)->next, (l)->next->next, (l)->next->prev \
343
+				) 
344
+
345
+#define debug_lu_lst( txt, l) \
346
+	do{ \
347
+		if (check_lu_lst((l))){  \
348
+			dbg_lu_lst(txt  " crt:", (l)); \
349
+			abort(); \
350
+		} \
351
+		if (check_lu_lst((l)->next)){ \
352
+			dbg_lu_lst(txt  " next:",  (l)); \
353
+			abort(); \
354
+		} \
355
+		if (check_lu_lst((l)->prev)){ \
356
+			dbg_lu_lst(txt  " prev:", (l)); \
357
+			abort(); \
358
+		} \
359
+	}while(0)
360
+
361
+#endif
362
+#endif /* DNS_CACHE_DEBUG */
363
+
364
+
365
+/* must be called with the DNS_LOCK hold
366
+ * remove and entry from the hash, dec. its refcnt and if not referenced
367
+ * anymore deletes it */
368
+void _dns_hash_remove(struct dns_hash_entry* e)
369
+{
370
+	clist_rm(e, next, prev);
371
+#ifdef DNS_CACHE_DEBUG
372
+	e->next=e->prev=0;
373
+#endif
374
+#ifdef DNS_LU_LST
375
+#ifdef DEBUG_LU_LST
376
+	debug_lu_lst("_dns_hash_remove: pre rm:", &e->last_used_lst);
377
+#endif
378
+	clist_rm(&e->last_used_lst, next, prev);
379
+#ifdef DEBUG_LU_LST
380
+	debug_lu_lst("_dns_hash_remove: post rm:", &e->last_used_lst);
381
+#endif
382
+#ifdef DNS_CACHE_DEBUG
383
+	e->last_used_lst.next=e->last_used_lst.prev=0;
384
+#endif
385
+#endif
386
+	*dns_cache_mem_used-=e->total_size;
387
+	dns_hash_put(e);
388
+}
389
+
390
+
391
+
392
+/* non locking  version (the dns hash must _be_ locked externally)
393
+ * returns 0 when not found, or the entry on success (an entry with a
394
+ * similar name but with a CNAME type will always match).
395
+ * it doesn't increase the internal refcnt
396
+ * returns the entry when found, 0 when not found and sets *err to !=0
397
+ *  on error (e.g. recursive cnames)
398
+ * WARNING: - internal use only
399
+ *          - always check if the returned entry type is CNAME */
400
+inline static struct dns_hash_entry* _dns_hash_find(str* name, int type,
401
+														int* h, int* err)
402
+{
403
+	struct dns_hash_entry* e;
404
+	struct dns_hash_entry* tmp;
405
+	struct dns_hash_entry* ret;
406
+	ticks_t now;
407
+	int cname_chain;
408
+	str cname;
409
+	
410
+	cname_chain=0;
411
+	ret=0;
412
+	now=get_ticks_raw();
413
+	*err=0;
414
+again:
415
+	*h=dns_hash_no(name->s, name->len, type);
416
+	DBG("dns_hash_find(%.*s(%d), %d), h=%d\n", name->len, name->s,
417
+												name->len, type, *h);
418
+	clist_foreach_safe(&dns_hash[*h], e, tmp, next){
419
+		/* automatically remove expired elements */
420
+		if ((s_ticks_t)(now-e->expire)>=0){
421
+				_dns_hash_remove(e);
422
+		}else if ((e->type==type) && (e->name_len==name->len) &&
423
+			(strncasecmp(e->name, name->s, e->name_len)==0)){
424
+			e->last_used=now;
425
+#ifdef DNS_LU_LST
426
+			/* add it at the end */
427
+#ifdef DEBUG_LU_LST
428
+			debug_lu_lst("_dns_hash_find: pre rm:", &e->last_used_lst);
429
+#endif
430
+			clist_rm(&e->last_used_lst, next, prev);
431
+			clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
432
+#ifdef DEBUG_LU_LST
433
+			debug_lu_lst("_dns_hash_find: post append:", &e->last_used_lst);
434
+#endif
435
+#endif
436
+			return e;
437
+		}else if ((e->type==T_CNAME) && (e->name_len==name->len) &&
438
+			(strncasecmp(e->name, name->s, e->name_len)==0)){
439
+			e->last_used=now;
440
+#ifdef DNS_LU_LST
441
+			/* add it at the end */
442
+#ifdef DEBUG_LU_LST
443
+			debug_lu_lst("_dns_hash_find: cname: pre rm:", &e->last_used_lst);
444
+#endif
445
+			clist_rm(&e->last_used_lst, next, prev);
446
+			clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
447
+#ifdef DEBUG_LU_LST
448
+			debug_lu_lst("_dns_hash_find: cname: post append:",
449
+							&e->last_used_lst);
450
+#endif
451
+#endif		
452
+			ret=e; /* if this is an unfinished cname chain, we try to
453
+					  return the last cname */
454
+			/* this is a cname => retry using its value */
455
+			if (cname_chain> MAX_CNAME_CHAIN){
456
+				LOG(L_ERR, "ERROR: _dns_hash_find: cname chain too long "
457
+						"or recursive (\"%.*s\")\n", name->len, name->s);
458
+				ret=0; /* error*/
459
+				*err=-1;
460
+				break;
461
+			}
462
+			cname_chain++;
463
+			cname.s=((struct cname_rdata*)e->rr_lst->rdata)->name;
464
+			cname.len= ((struct cname_rdata*)e->rr_lst->rdata)->name_len;
465
+			name=&cname;
466
+			goto again;
467
+		}
468
+	}
469
+	return ret;
470
+}
471
+
472
+
473
+
474
+/* frees cache entries, if expired_only=0 only expired entries will be 
475
+ * removed, else all of them
476
+ * it will process maximum no entries (to process all of them use -1)
477
+ * returns the number of deleted entries
478
+ * This should be called from a timer process*/
479
+inline static int dns_cache_clean(unsigned int no, int expired_only)
480
+{
481
+	struct dns_hash_entry* e;
482
+	ticks_t now;
483
+	unsigned int n;
484
+	unsigned int deleted;
485
+#ifdef DNS_LU_LST
486
+	struct dns_lu_lst* l;
487
+	struct dns_lu_lst* tmp;
488
+#else
489
+	struct dns_hash_entry* t;
490
+	unsigned int h;
491
+	static unsigned int start=0;
492
+#endif
493
+	
494
+	n=0;
495
+	deleted=0;
496
+	now=get_ticks_raw();
497
+	LOCK_DNS_HASH();
498
+#ifdef DNS_LU_LST
499
+	clist_foreach_safe(dns_last_used_lst, l, tmp, next){
500
+		e=(struct dns_hash_entry*)(((char*)l)-
501
+				(char*)&((struct dns_hash_entry*)(0))->last_used_lst);
502
+		if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){
503
+				_dns_hash_remove(e);
504
+				deleted++;
505
+		}
506
+		n++;
507
+		if (n>=no) break;
508
+	}
509
+#else
510
+	for(h=start; h!=(start+DNS_HASH_SIZE); h++){
511
+		clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
512
+			if  ((s_ticks_t)(now-e->expire)>=0){
513
+				_dns_hash_remove(e);
514
+				deleted++;
515
+			}
516
+			n++;
517
+			if (n>=no) break;
518
+		}
519
+	}
520
+	/* not fair, but faster then random() */
521
+	if (!expired_only){
522
+		for(h=start; h!=(start+DNS_HASH_SIZE); h++){
523
+			clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
524
+				if  ((s_ticks_t)(now-e->expire)>=0){
525
+					_dns_hash_remove(e);
526
+					deleted++;
527
+				}
528
+				n++;
529
+				if (n>=no) goto skip;
530
+			}
531
+		}
532
+	}
533
+skip:
534
+	start=h;
535
+#endif
536
+	UNLOCK_DNS_HASH();
537
+	return deleted;
538
+}
539
+
540
+
541
+
542
+/* frees cache entries, if expired_only=0 only expired entries will be 
543
+ * removed, else all of them
544
+ * it will stop when the dns cache used memory reaches target (to process all 
545
+ * of them use 0)
546
+ * returns the number of deleted entries */
547
+inline static int dns_cache_free_mem(unsigned int target, int expired_only)
548
+{
549
+	struct dns_hash_entry* e;
550
+	ticks_t now;
551
+	unsigned int deleted;
552
+#ifdef DNS_LU_LST
553
+	struct dns_lu_lst* l;
554
+	struct dns_lu_lst* tmp;
555
+#else
556
+	struct dns_hash_entry* t;
557
+	unsigned int h;
558
+	static unsigned int start=0;
559
+#endif
560
+	
561
+	deleted=0;
562
+	now=get_ticks_raw();
563
+	LOCK_DNS_HASH();
564
+#ifdef DNS_LU_LST
565
+	clist_foreach_safe(dns_last_used_lst, l, tmp, next){
566
+		if (*dns_cache_mem_used<=target) break;
567
+		e=(struct dns_hash_entry*)(((char*)l)-
568
+				(char*)&((struct dns_hash_entry*)(0))->last_used_lst);
569
+		if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){
570
+				_dns_hash_remove(e);
571
+				deleted++;
572
+		}
573
+	}
574
+#else
575
+	for(h=start; h!=(start+DNS_HASH_SIZE); h++){
576
+		clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
577
+			if (*dns_cache_mem_used<=target) 
578
+				goto skip;
579
+			if  ((s_ticks_t)(now-e->expire)>=0){
580
+				_dns_hash_remove(e);
581
+				deleted++;
582
+			}
583
+		}
584
+	}
585
+	/* not fair, but faster then random() */
586
+	if (!expired_only){
587
+		for(h=start; h!=(start+DNS_HASH_SIZE); h++){
588
+			clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
589
+				if (*dns_cache_mem_used<=target) 
590
+					goto skip;
591
+				if  ((s_ticks_t)(now-e->expire)>=0){
592
+					_dns_hash_remove(e);
593
+					deleted++;
594
+				}
595
+			}
596
+		}
597
+	}
598
+skip:
599
+	start=h;
600
+#endif
601
+	UNLOCK_DNS_HASH();
602
+	return deleted;
603
+}
604
+
605
+
606
+
607
+/* locking  version (the dns hash must _not_be locked externally)
608
+ * returns 0 when not found, the searched entry on success (with CNAMEs
609
+ *  followed) or the last CNAME entry from an unfinished CNAME chain, 
610
+ *  if the search matches a CNAME. On error sets *err (e.g. recursive CNAMEs).
611
+ * it increases the internal refcnt => when finished dns_hash_put() must
612
+ *  be called on the returned entry
613
+ *  WARNING: - the return might be a CNAME even if type!=CNAME, see above */
614
+inline static struct dns_hash_entry* dns_hash_get(str* name, int type, int* h,
615
+													int* err)
616
+{
617
+	struct dns_hash_entry* e;
618
+	
619
+	LOCK_DNS_HASH();
620
+	e=_dns_hash_find(name, type, h, err);
621
+	if (e){
622
+		atomic_inc(&e->refcnt);
623
+	}
624
+	UNLOCK_DNS_HASH();
625
+	return e;
626
+}
627
+
628
+
629
+
630
+/* adds a fully created and init. entry (see dns_cache_mk_entry()) to the hash
631
+ * table
632
+ * returns 0 on success, -1 on error */
633
+inline static int dns_cache_add(struct dns_hash_entry* e)
634
+{
635
+	int h;
636
+	
637
+	/* check space */
638
+	/* atomic_add_long(dns_cache_total_used, e->size); */
639
+	if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){
640
+		LOG(L_WARN, "WARNING: dns_cache_add: cache full, trying to free...\n");
641
+		/* free ~ 12% of the cache */
642
+		dns_cache_free_mem(*dns_cache_mem_used/16*14, 1);
643
+		if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){
644
+			LOG(L_ERR, "ERROR: dns_cache_add: max. cache mem size exceeded\n");
645
+			return -1;
646
+		}
647
+	}
648
+	atomic_inc(&e->refcnt);
649
+	h=dns_hash_no(e->name, e->name_len, e->type);
650
+	DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n",
651
+			e->name_len, e->name, e->name_len, e->type, e->err_flags, h);
652
+	LOCK_DNS_HASH();
653
+		*dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written
654
+										 only from within a lock */
655
+		clist_append(&dns_hash[h], e, next, prev);
656
+#ifdef DNS_LU_LST
657
+		clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
658
+#endif
659
+	UNLOCK_DNS_HASH();
660
+	return 0;
661
+}
662
+
663
+
664
+
665
+/* same as above, but it must be called with the dns hash lock held
666
+ * returns 0 on success, -1 on error */
667
+inline static int dns_cache_add_unsafe(struct dns_hash_entry* e)
668
+{
669
+	int h;
670
+	
671
+	/* check space */
672
+	/* atomic_add_long(dns_cache_total_used, e->size); */
673
+	if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){
674
+		LOG(L_WARN, "WARNING: dns_cache_add: cache full, trying to free...\n");
675
+		/* free ~ 12% of the cache */
676
+		UNLOCK_DNS_HASH();
677
+		dns_cache_free_mem(*dns_cache_mem_used/16*14, 1);
678
+		LOCK_DNS_HASH();
679
+		if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){
680
+			LOG(L_ERR, "ERROR: dns_cache_add: max. cache mem size exceeded\n");
681
+			return -1;
682
+		}
683
+	}
684
+	atomic_inc(&e->refcnt);
685
+	h=dns_hash_no(e->name, e->name_len, e->type);
686
+	DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n",
687
+			e->name_len, e->name, e->name_len, e->type, e->err_flags, h);
688
+	*dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written
689
+										 only from within a lock */
690
+	clist_append(&dns_hash[h], e, next, prev);
691
+#ifdef DNS_LU_LST
692
+	clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
693
+#endif
694
+	return 0;
695
+}
696
+
697
+
698
+
699
+/* creates a "negative" entry which will be valid for ttl seconds */
700
+inline static struct dns_hash_entry* dns_cache_mk_bad_entry(str* name,
701
+															int type,
702
+															int ttl,
703
+															int flags)
704
+{
705
+	struct dns_hash_entry* e;
706
+	int size;
707
+	ticks_t now;
708
+	
709
+	DBG("dns_cache_mk_bad_entry(%.*s, %d, %d, %d)\n", name->len, name->s,
710
+									type, ttl, flags);
711
+	size=sizeof(struct dns_hash_entry)+name->len-1+1;
712
+	e=shm_malloc(size);
713
+	if (e==0){
714
+		LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
715
+		return 0;
716
+	}
717
+	memset(e, 0, size); /* init with 0*/
718
+	e->total_size=size;
719
+	e->name_len=name->len;
720
+	e->type=type;
721
+	now=get_ticks_raw();
722
+	e->last_used=now;
723
+	e->expire=now+S_TO_TICKS(ttl);
724
+	memcpy(e->name, name->s, name->len);
725
+	e->err_flags=flags;
726
+	return e;
727
+}
728
+
729
+
730
+
731
+/* create a a/aaaa hash entry from a name and ip address
732
+ * returns 0 on error */
733
+inline static struct dns_hash_entry* dns_cache_mk_ip_entry(str* name,
734
+															struct ip_addr* ip)
735
+{
736
+	struct dns_hash_entry* e;
737
+	int size;
738
+	ticks_t now;
739
+	
740
+	/* everything is allocated in one block: dns_hash_entry + name +
741
+	 * + dns_rr + rdata;  dns_rr must start at an aligned adress,
742
+	 * hence we need to round dns_hash_entry+name size to a sizeof(long)
743
+	 * multiple.
744
+	 * Memory image:
745
+	 * struct dns_hash_entry
746
+	 * name (name_len+1 bytes)
747
+	 * padding to multiple of sizeof(long)
748
+	 * dns_rr
749
+	 * rdata  (no padding needed, since for ip is just an array of chars)
750
+	  */
751
+	size=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1)+ 
752
+			sizeof(struct dns_rr)+ ip->len;
753
+	e=shm_malloc(size);
754
+	if (e==0){
755
+		LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
756
+		return 0;
757
+	}
758
+	memset(e, 0, size); /* init with 0*/
759
+	e->total_size=size;
760
+	e->name_len=name->len;
761
+	e->type=(ip->af==AF_INET)?T_A:T_AAAA;
762
+	now=get_ticks_raw();
763
+	e->last_used=now;
764
+	e->expire=now-1; /* maximum expire */
765
+	memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */
766
+	e->rr_lst=(void*)((char*)e+
767
+				ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1));
768
+	e->rr_lst->rdata=(void*)((char*)e->rr_lst+sizeof(struct dns_rr));
769
+	e->rr_lst->expire=now-1; /* maximum expire */
770
+	/* no need to align rr_lst->rdata for a or aaaa records */
771
+	memcpy(e->rr_lst->rdata, ip->u.addr, ip->len);
772
+	return e;
773
+}
774
+
775
+
776
+
777
+/* create a dns hash entry from a name and a rdata list (pkg_malloc'ed)
778
+ * (it will use only the type records with the name "name" from the
779
+ *  rdata list with one exception: if a matching CNAME with the same
780
+ *  name is found, the search will stop and this will be the record used)
781
+ * returns 0 on error and removes the used elements from the rdata list*/
782
+inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type,
783
+														struct rdata** rd_lst)
784
+{
785
+	struct dns_hash_entry* e;
786
+	struct dns_rr* rr;
787
+	struct dns_rr** tail_rr;
788
+	struct rdata** p;
789
+	struct rdata* tmp_lst;
790
+	struct rdata** tail;
791
+	struct rdata* l;
792
+	int size;
793
+	ticks_t now;
794
+	unsigned int max_ttl;
795
+	unsigned int ttl;
796
+	
797
+#define rec_matches(rec, t, n) /*(struct rdata* record, int type, str* name)*/\
798
+	(	((rec)->name_len==(n)->len) && ((rec)->type==(t)) && \
799
+		(strncasecmp((rec)->name, (n)->s, (n)->len)==0))
800
+	/* init */
801
+	tmp_lst=0;
802
+	tail=&tmp_lst;
803
+	
804
+	
805
+	/* everything is allocated in one block: dns_hash_entry + name +
806
+	 * + dns_rr + rdata_raw+ ....;  dns_rr must start at an aligned adress,
807
+	 * hence we need to round dns_hash_entry+name size to a sizeof(long)
808
+	 * multiple. If rdata type requires it, rdata_raw might need to be also
809
+	 * aligned.
810
+	 * Memory image:
811
+	 * struct dns_hash_entry  (e)
812
+	 * name (name_len+1 bytes)  (&e->name[0])
813
+	 * padding to multiple of sizeof(char*)
814
+	 * dns_rr1 (e->rr_lst)
815
+	 * possible padding: no padding for a_rdata or aaaa_rdata, 
816
+	 *                   multipe of sizeof(short) for srv_rdata,
817
+	 *                   multiple of sizeof(long) for naptr_rdata and others
818
+	 * dns_rr1->rdata  (e->rr_lst->rdata)
819
+	 * padding to multipe of sizeof long
820
+	 * dns_rr2 (e->rr_lst->next)
821
+	 * ....
822
+	 *
823
+	 */
824
+	size=0;
825
+	if (*rd_lst==0)
826
+		return 0;
827
+	/* find the first matching rr, if it's a CNAME use CNAME as type,
828
+	 * if not continue with the original type */
829
+	for(p=rd_lst; *p; p=&(*p)->next){
830
+		if (((*p)->name_len==name->len) &&
831
+				(((*p)->type==type) || ((*p)->type==T_CNAME)) &&
832
+				(strncasecmp((*p)->name, name->s, name->len)==0)){
833
+			type=(*p)->type;
834
+			break;
835
+		}
836
+	}
837
+	/* continue, we found the type we are looking for */
838
+	switch(type){
839
+		case T_A:
840
+			for(; *p;){
841
+				if (!rec_matches((*p), type, name)){ 
842
+					/* skip this record */
843
+					p=&(*p)->next; /* advance */
844
+					continue;
845
+				}
846
+				size+=ROUND_POINTER(sizeof(struct dns_rr)+
847
+										sizeof(struct a_rdata));
848
+				/* add it to our tmp. lst */
849
+				*tail=*p;
850
+				tail=&(*p)->next;
851
+				/* detach it from the rd list */
852
+				*p=(*p)->next;
853
+				/* don't advance p, because the crt. elem. has
854
+				 * just been elimintated */
855
+			}
856
+			break;
857
+		case T_AAAA:
858
+			for(; *p;){
859
+				if (!rec_matches((*p), type, name)){ 
860
+					/* skip this record */
861
+					p=&(*p)->next; /* advance */
862
+					continue;
863
+				}
864
+				/* no padding */
865
+				size+=ROUND_POINTER(sizeof(struct dns_rr)+
866
+											sizeof(struct aaaa_rdata));
867
+				/* add it to our tmp. lst */
868
+				*tail=*p;
869
+				tail=&(*p)->next;
870
+				/* detach it from the rd list */
871
+				*p=(*p)->next;
872
+				/* don't advance p, because the crt. elem. has
873
+				 * just been elimintated */
874
+			}
875
+			break;
876
+		case T_SRV:
877
+			for(; *p;){
878
+				if (!rec_matches((*p), type, name)){ 
879
+					/* skip this record */
880
+					p=&(*p)->next; /* advance */
881
+					continue;
882
+				}
883
+				/* padding to short */
884
+				size+=ROUND_POINTER(ROUND_SHORT(sizeof(struct dns_rr))+
885
+						SRV_RDATA_SIZE(*(struct srv_rdata*)(*p)->rdata));
886
+				/* add it to our tmp. lst */
887
+				*tail=*p;
888
+				tail=&(*p)->next;
889
+				/* detach it from the rd list */
890
+				*p=(*p)->next;
891
+				/* don't advance p, because the crt. elem. has
892
+				 * just been elimintated */
893
+			}
894
+			break;
895
+		case T_NAPTR:
896
+			for(; *p;){
897
+				if (!rec_matches((*p), type, name)){ 
898
+					/* skip this record */
899
+					p=&(*p)->next; /* advance */
900
+					continue;
901
+				}
902
+				/* padding to char* */
903
+				size+=ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
904
+						NAPTR_RDATA_SIZE(*(struct naptr_rdata*)(*p)->rdata));
905
+				/* add it to our tmp. lst */
906
+				*tail=*p;
907
+				tail=&(*p)->next;
908
+				/* detach it from the rd list */
909
+				*p=(*p)->next;
910
+				/* don't advance p, because the crt. elem. has
911
+				 * just been elimintated */
912
+			}
913
+			break;
914
+		case T_CNAME:
915
+			for(; *p;){
916
+				if (!rec_matches((*p), type, name)){ 
917
+					/* skip this record */
918
+					p=&(*p)->next; /* advance */
919
+					continue;
920
+				}
921
+				/* no padding */
922
+				size+=ROUND_POINTER(sizeof(struct dns_rr)+
923
+						CNAME_RDATA_SIZE(*(struct cname_rdata*)(*p)->rdata));
924
+				/* add it to our tmp. lst */
925
+				*tail=*p;
926
+				tail=&(*p)->next;
927
+				/* detach it from the rd list */
928
+				*p=(*p)->next;
929
+				/* don't advance p, because the crt. elem. has
930
+				 * just been elimintated */
931
+			}
932
+			break;
933
+		default:
934
+			LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: type %d not "
935
+							"supported\n", type);
936
+			/* we don't know what to do with it, so don't
937
+			 * add it to the tmp_lst */
938
+			return 0; /* error */
939
+	}
940
+	*tail=0; /* mark the end of our tmp_lst */
941
+	if (size==0){
942
+		DBG("dns_cache_mk_rd_entry: entry %.*s (%d) not found\n",
943
+				name->len, name->s, type);
944
+		return 0;
945
+	}
946
+	/* compute size */
947
+	size+=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1);
948
+	e=shm_malloc(size);
949
+	if (e==0){
950
+		LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
951
+		return 0;
952
+	}
953
+	memset(e, 0, size); /* init with 0 */
954
+	e->total_size=size;
955
+	e->name_len=name->len;
956
+	e->type=type;
957
+	now=get_ticks_raw();
958
+	e->last_used=now;
959
+	memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */
960
+	e->rr_lst=(struct dns_rr*)((char*)e+
961
+				ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1));
962
+	tail_rr=&(e->rr_lst);
963
+	rr=e->rr_lst;
964
+	max_ttl=0;
965
+	/* copy the actual data */
966
+	switch(type){
967
+		case T_A:
968
+			for(l=tmp_lst; l; l=l->next){
969
+				ttl=FIX_TTL(l->ttl);