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