Browse code

bugfixes:

Non critical:
- BUG message for CONN_ERROR (it's not a bug)
- find_tls_si will be called now for tls connection (tcp_connect), it will
probably fix SUBST_RCV_* proto (tcp set also for tls). Very unlikely to
hit this (but possible: e.g. RR on tls to something and a request is rr'ed
which is received on a tls connection opened _by_ _us_, very unlikely without
the new tcp aliasing ).

Critical:
- non atomic unix sock read
- tcp refcnt non-atomic dec
- tls lock read & writes on the same connection are now mutually exclusive
to avoid stealing the fds

Andrei Pelinescu-Onciul authored on 04/11/2003 18:01:03
Showing 5 changed files
... ...
@@ -43,7 +43,7 @@ export makefile_defs
43 43
 VERSION = 0
44 44
 PATCHLEVEL = 8
45 45
 SUBLEVEL =   12
46
-EXTRAVERSION = testing-20
46
+EXTRAVERSION = testing-22
47 47
 
48 48
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
49 49
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
... ...
@@ -29,6 +29,8 @@
29 29
   * --------
30 30
   *  2002-11-29  created by andrei
31 31
   *  2003-02-20  added solaris support (! HAVE_MSGHDR_MSG_CONTROL) (andrei)
32
+  *  2003-11-03  added send_all, recv_all  and updated send/get_fd
33
+  *               to handle signals  (andrei)
32 34
   */
33 35
 
34 36
 #ifdef USE_TCP
... ...
@@ -37,10 +39,55 @@
37 39
 #include <sys/socket.h>
38 40
 #include <sys/uio.h>
39 41
 #include <stdlib.h> /* for NULL definition on openbsd */
42
+#include <errno.h>
43
+#include <string.h>
40 44
 
41 45
 #include "dprint.h"
42 46
 
43 47
 
48
+
49
+/* receive all the data or returns error (handles EINTR etc.)
50
+ * returns: bytes read or error (<0)
51
+ * can return < data_len if EOF */
52
+int recv_all(int socket, void* data, int data_len)
53
+{
54
+	int b_read;
55
+	int n;
56
+	
57
+	b_read=0;
58
+	do{
59
+		n=recv(socket, data+b_read, data_len-b_read, MSG_WAITALL);
60
+		if (n<0){
61
+			/* error */
62
+			if (errno==EINTR) continue; /* signal, try again */
63
+			LOG(L_CRIT, "ERROR: recv_all: recv on %d failed: %s\n",
64
+					socket, strerror(errno));
65
+			return n;
66
+		}
67
+		b_read+=n;
68
+	}while( (b_read!=data_len) && (n));
69
+	return b_read;
70
+}
71
+
72
+
73
+/* sends all data (takes care of signals)
74
+ * returns number of bytes sent or < 0 for an error */
75
+int send_all(int socket, void* data, int data_len)
76
+{
77
+	int n;
78
+	
79
+again:
80
+	n=send(socket, data, data_len, 0);
81
+	if (n<0){
82
+			/* error */
83
+		if (errno==EINTR) goto again; /* signal, try again */
84
+		LOG(L_CRIT, "ERROR: send_all: send on %d failed: %s\n",
85
+					socket, strerror(errno));
86
+	}
87
+	return n;
88
+}
89
+
90
+
44 91
 /* at least 1 byte must be sent! */
45 92
 int send_fd(int unix_socket, void* data, int data_len, int fd)
46 93
 {
... ...
@@ -76,8 +123,13 @@ int send_fd(int unix_socket, void* data, int data_len, int fd)
76 123
 	msg.msg_iov=iov;
77 124
 	msg.msg_iovlen=1;
78 125
 	
79
-	
126
+again:
80 127
 	ret=sendmsg(unix_socket, &msg, 0);
128
+	if (ret<0){
129
+		if (errno==EINTR) goto again;
130
+		LOG(L_CRIT, "ERROR: send_fd: sendmsg failed on %d: %s\n",
131
+				unix_socket, strerror(errno));
132
+	}
81 133
 	
82 134
 	return ret;
83 135
 }
... ...
@@ -90,6 +142,7 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd)
90 142
 	struct iovec iov[1];
91 143
 	int new_fd;
92 144
 	int ret;
145
+	int n;
93 146
 #ifdef HAVE_MSGHDR_MSG_CONTROL
94 147
 	struct cmsghdr* cmsg;
95 148
 	union{
... ...
@@ -112,26 +165,47 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd)
112 165
 	msg.msg_iov=iov;
113 166
 	msg.msg_iovlen=1;
114 167
 	
115
-	ret=recvmsg(unix_socket, &msg, 0);
116
-	if (ret<=0) goto error;
168
+again:
169
+	ret=recvmsg(unix_socket, &msg, MSG_WAITALL);
170
+	if (ret<0){
171
+		if (errno==EINTR) goto again;
172
+		LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n",
173
+				unix_socket, strerror(errno));
174
+		goto error;
175
+	}
176
+	if (ret==0){
177
+		/* EOF */
178
+		LOG(L_CRIT, "ERROR: receive_fd: EOF on %d\n", unix_socket);
179
+		goto error;
180
+	}
181
+	if (ret<data_len){
182
+		LOG(L_WARN, "WARNING: receive_fd: too few bytes read (%d from %d)"
183
+				    "trying to fix...\n", ret, data_len);
184
+		n=recv_all(unix_socket, (char*)data+ret, data_len-ret);
185
+		if (n>=0) ret+=n;
186
+		else{
187
+			ret=n;
188
+			goto error;
189
+		}
190
+	}
117 191
 	
118 192
 #ifdef HAVE_MSGHDR_MSG_CONTROL
119 193
 	cmsg=CMSG_FIRSTHDR(&msg);
120 194
 	if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
121 195
 		if (cmsg->cmsg_type!= SCM_RIGHTS){
122
-			LOG(L_ERR, "receive_fd: msg control type != SCM_RIGHTS\n");
196
+			LOG(L_ERR, "ERROR: receive_fd: msg control type != SCM_RIGHTS\n");
123 197
 			ret=-1;
124 198
 			goto error;
125 199
 		}
126 200
 		if (cmsg->cmsg_level!= SOL_SOCKET){
127
-			LOG(L_ERR, "receive_fd: msg level != SOL_SOCKET\n");
201
+			LOG(L_ERR, "ERROR: receive_fd: msg level != SOL_SOCKET\n");
128 202
 			ret=-1;
129 203
 			goto error;
130 204
 		}
131 205
 		*fd=*((int*) CMSG_DATA(cmsg));
132 206
 	}else{
133
-		LOG(L_ERR, "receive_fd: no descriptor passed, cmsg=%p, len=%d\n",
134
-				cmsg, cmsg->cmsg_len);
207
+		LOG(L_ERR, "ERROR: receive_fd: no descriptor passed, cmsg=%p,"
208
+				"len=%d\n", cmsg, cmsg->cmsg_len);
135 209
 		*fd=-1;
136 210
 		/* it's not really an error */
137 211
 	}
... ...
@@ -139,8 +213,8 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd)
139 213
 	if (msg.msg_accrightslen==sizeof(int)){
140 214
 		*fd=new_fd;
141 215
 	}else{
142
-		LOG(L_ERR, "receive_fd: no descriptor passed, accrightslen=%d\n",
143
-				msg.msg_accrightslen);
216
+		LOG(L_ERR, "ERROR: receive_fd: no descriptor passed,"
217
+				" accrightslen=%d\n", msg.msg_accrightslen);
144 218
 		*fd=-1;
145 219
 	}
146 220
 #endif
... ...
@@ -148,5 +222,4 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd)
148 222
 error:
149 223
 	return ret;
150 224
 }
151
-
152 225
 #endif
... ...
@@ -32,6 +32,8 @@
32 32
 int send_fd(int unix_socket, void* data, int data_len, int fd);
33 33
 int receive_fd(int unix_socket, void* data, int data_len, int* fd);
34 34
 
35
+int recv_all(int socket, void* data, int data_len);
36
+int send_all(int socket, void* data, int data_len);
35 37
 
36 38
 
37 39
 #endif
... ...
@@ -42,8 +42,8 @@
42 42
  *  2003-06-30  moved tcp new connect checking & handling to
43 43
  *               handle_new_connect (andrei)
44 44
  *  2003-07-09  tls_close called before closing the tcp connection (andrei)
45
- *  2003-10-24  converted to the new socket_info lists (andrei)
46
- *  2003-10-27  tcp port aliases support added (andrei)
45
+ *  2003-11-04  always lock before manipulating refcnt; sendchild
46
+ *              does not inc refcnt by itself anymore (andrei)
47 47
  */
48 48
 
49 49
 
... ...
@@ -106,10 +106,9 @@ struct tcp_child{
106 106
 };
107 107
 
108 108
 
109
-int tcp_accept_aliases=0; /* by default don't accept aliases */
110 109
 
111
-/* connection hash table (after ip&port) , includes also aliases */
112
-struct tcp_conn_alias** tcpconn_aliases_hash=0;
110
+/* connection hash table (after ip&port) */
111
+struct tcp_connection** tcpconn_addr_hash=0;
113 112
 /* connection hash table (after connection id) */
114 113
 struct tcp_connection** tcpconn_id_hash=0;
115 114
 gen_lock_t* tcpconn_lock=0;
... ...
@@ -134,7 +133,6 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
134 133
 		LOG(L_ERR, "ERROR: tcpconn_new: mem. allocation failure\n");
135 134
 		goto error;
136 135
 	}
137
-	memset(c, 0, sizeof(struct tcp_connection)); /* zero init */
138 136
 	c->s=sock;
139 137
 	c->fd=-1; /* not initialized */
140 138
 	if (lock_init(&c->write_lock)==0){
... ...
@@ -185,14 +183,14 @@ error:
185 183
 
186 184
 struct socket_info* find_tcp_si(union sockaddr_union* s)
187 185
 {
186
+	int r;
188 187
 	struct ip_addr ip;
189
-	struct socket_info* si;
190 188
 	
191 189
 	su2ip_addr(&ip, s);
192
-	for (si=tcp_listen; si; si=si->next)
193
-		if (ip_addr_cmp(&ip, &si->address)){
190
+	for (r=0; r<sock_no; r++)
191
+		if (ip_addr_cmp(&ip, &tcp_info[r].address)){
194 192
 			/* found it, we use first match */
195
-			return si;
193
+			return &tcp_info[r];
196 194
 		}
197 195
 	return 0; /* no match */
198 196
 }
... ...
@@ -242,7 +240,13 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
242 240
 				strerror(errno), errno);
243 241
 		si=0; /* try to go on */
244 242
 	}
245
-	si=find_tcp_si(&my_name);
243
+#ifdef USE_TLS
244
+	if (type==PROTO_TLS)
245
+		si=find_tls_si(&my_name);
246
+	else
247
+#endif
248
+		si=find_tcp_si(&my_name);
249
+
246 250
 	if (si==0){
247 251
 		LOG(L_ERR, "ERROR: tcp_connect: could not find coresponding"
248 252
 				" listening socket, using default...\n");
... ...
@@ -266,20 +270,14 @@ struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
266 270
 	if (c){
267 271
 		TCPCONN_LOCK;
268 272
 		/* add it at the begining of the list*/
273
+		hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
274
+		c->addr_hash=hash;
275
+		tcpconn_listadd(tcpconn_addr_hash[hash], c, next, prev);
269 276
 		hash=tcp_id_hash(c->id);
270 277
 		c->id_hash=hash;
271 278
 		tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev);
272
-		
273
-		hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
274
-		/* set the first alias */
275
-		c->con_aliases[0].port=c->rcv.src_port;
276
-		c->con_aliases[0].hash=hash;
277
-		c->con_aliases[0].parent=c;
278
-		tcpconn_listadd(tcpconn_aliases_hash[hash], &c->con_aliases[0],
279
-						next, prev);
280
-		c->aliases++;
281 279
 		TCPCONN_UNLOCK;
282
-		DBG("tcpconn_add: hashes: %d, %d\n", hash, c->id_hash);
280
+		DBG("tcpconn_add: hashes: %d, %d\n", c->addr_hash, c->id_hash);
283 281
 		return c;
284 282
 	}else{
285 283
 		LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n");
... ...
@@ -291,12 +289,8 @@ struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
291 289
 /* unsafe tcpconn_rm version (nolocks) */
292 290
 void _tcpconn_rm(struct tcp_connection* c)
293 291
 {
294
-	int r;
292
+	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
295 293
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
296
-	/* remove all the aliases */
297
-	for (r=0; r<c->aliases; r++)
298
-		tcpconn_listrm(tcpconn_aliases_hash[c->con_aliases[r].hash], 
299
-						&c->con_aliases[r], next, prev);
300 294
 	lock_destroy(&c->write_lock);
301 295
 #ifdef USE_TLS
302 296
 	if (c->type==PROTO_TLS) tls_tcpconn_clean(c);
... ...
@@ -308,13 +302,9 @@ void _tcpconn_rm(struct tcp_connection* c)
308 302
 
309 303
 void tcpconn_rm(struct tcp_connection* c)
310 304
 {
311
-	int r;
312 305
 	TCPCONN_LOCK;
306
+	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
313 307
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
314
-	/* remove all the aliases */
315
-	for (r=0; r<c->aliases; r++)
316
-		tcpconn_listrm(tcpconn_aliases_hash[c->con_aliases[r].hash], 
317
-						&c->con_aliases[r], next, prev);
318 308
 	TCPCONN_UNLOCK;
319 309
 	lock_destroy(&c->write_lock);
320 310
 #ifdef USE_TLS
... ...
@@ -331,12 +321,11 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
331 321
 {
332 322
 
333 323
 	struct tcp_connection *c;
334
-	struct tcp_conn_alias* a;
335 324
 	unsigned hash;
336 325
 	
337 326
 #ifdef EXTRA_DEBUG
338 327
 	DBG("tcpconn_find: %d  port %d\n",id, port);
339
-	if (ip) print_ip("tcpconn_find: ip ", ip, "\n");
328
+	print_ip("tcpconn_find: ip ", ip, "\n");
340 329
 #endif
341 330
 	if (id){
342 331
 		hash=tcp_id_hash(id);
... ...
@@ -349,15 +338,14 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
349 338
 		}
350 339
 	}else if (ip){
351 340
 		hash=tcp_addr_hash(ip, port);
352
-		for (a=tcpconn_aliases_hash[hash]; a; a=a->next){
341
+		for (c=tcpconn_addr_hash[hash]; c; c=c->next){
353 342
 #ifdef EXTRA_DEBUG
354
-			DBG("a=%p, c=%p, c->id=%d, alias port= %d port=%d\n", a, a->parent,
355
-					a->parent->id, a->port, a->parent->rcv.src_port);
356
-			print_ip("ip=",&a->parent->rcv.src_ip,"\n");
343
+			DBG("c=%p, c->id=%d, port=%d\n",c, c->id, c->rcv.src_port);
344
+			print_ip("ip=",&c->rcv.src_ip,"\n");
357 345
 #endif
358
-			if ( (a->parent->state!=S_CONN_BAD) && (port==a->port) &&
359
-					(ip_addr_cmp(ip, &a->parent->rcv.src_ip)) )
360
-				return a->parent;
346
+			if ( (c->state!=S_CONN_BAD) && (port==c->rcv.src_port) &&
347
+					(ip_addr_cmp(ip, &c->rcv.src_ip)) )
348
+				return c;
361 349
 		}
362 350
 	}
363 351
 	return 0;
... ...
@@ -382,70 +370,20 @@ struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port,
382 370
 
383 371
 
384 372
 
385
-/* add port as an alias for the "id" connection
386
- * returns 0 on success,-1 on failure */
387
-int tcpconn_add_alias(int id, int port, int proto)
373
+void tcpconn_ref(struct tcp_connection* c)
388 374
 {
389
-	struct tcp_connection* c;
390
-	unsigned hash;
391
-	struct tcp_conn_alias* a;
392
-	
393
-	a=0;
394
-	/* fix the port */
395
-	port=port?port:((proto==PROTO_TLS)?SIPS_PORT:SIP_PORT);
396 375
 	TCPCONN_LOCK;
397
-	/* check if alias already exists */
398
-	c=_tcpconn_find(id, 0, 0);
399
-	if (c){
400
-		hash=tcp_addr_hash(&c->rcv.src_ip, port);
401
-		/* search the aliases for an already existing one */
402
-		for (a=tcpconn_aliases_hash[hash]; a; a=a->next){
403
-			if ( (a->parent->state!=S_CONN_BAD) && (port==a->port) &&
404
-					(ip_addr_cmp(&c->rcv.src_ip, &a->parent->rcv.src_ip)) ){
405
-				/* found */
406
-				if (a->parent!=c) goto error_sec;
407
-				else goto ok;
408
-			}
409
-		}
410
-		if (c->aliases>=TCP_CON_MAX_ALIASES) goto error_aliases;
411
-		c->con_aliases[c->aliases].parent=c;
412
-		c->con_aliases[c->aliases].port=port;
413
-		c->con_aliases[c->aliases].hash=hash;
414
-		tcpconn_listadd(tcpconn_aliases_hash[hash], 
415
-								&c->con_aliases[c->aliases], next, prev);
416
-		c->aliases++;
417
-	}else goto error_not_found;
418
-ok:
419
-	TCPCONN_UNLOCK;
420
-#ifdef EXTRA_DEBUG
421
-	if (a) DBG("tcpconn_add_alias: alias already present\n");
422
-	else   DBG("tcpconn_add_alias: alias port %d for hash %d, id %d\n",
423
-			port, hash, c->id);
424
-#endif
425
-	return 0;
426
-error_aliases:
427
-	TCPCONN_UNLOCK;
428
-	LOG(L_ERR, "ERROR: tcpconn_add_alias: too many aliases for connection %p"
429
-				" (%d)\n", c, c->id);
430
-	return -1;
431
-error_not_found:
376
+	c->refcnt++; /* FIXME: atomic_dec */
432 377
 	TCPCONN_UNLOCK;
433
-	LOG(L_ERR, "ERROR: tcpconn_add_alias: no connection found for id %d\n",id);
434
-	return -1;
435
-error_sec:
436
-	TCPCONN_UNLOCK;
437
-	LOG(L_ERR, "ERROR: tcpconn_add_alias: possible port hijack attemp\n");
438
-	LOG(L_ERR, "ERROR: tcpconn_add_alias: alias already present and points"
439
-			" to another connection (%d : %d and %d : %d)\n",
440
-			a->parent->id,  port, c->id, port);
441
-	return -1;
442 378
 }
443 379
 
444 380
 
445 381
 
446 382
 void tcpconn_put(struct tcp_connection* c)
447 383
 {
384
+	TCPCONN_LOCK;
448 385
 	c->refcnt--; /* FIXME: atomic_dec */
386
+	TCPCONN_UNLOCK;
449 387
 }
450 388
 
451 389
 
... ...
@@ -494,22 +432,25 @@ no_id:
494 432
 				LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
495 433
 				return -1;
496 434
 			}
497
-			c->refcnt++;
435
+			c->refcnt++; /* safe to do it w/o locking, it's not yet
436
+							available to the rest of the world */
498 437
 			fd=c->s;
499 438
 			
500 439
 			/* send the new tcpconn to "tcp main" */
501 440
 			response[0]=(long)c;
502 441
 			response[1]=CONN_NEW;
503
-			n=write(unix_tcp_sock, response, sizeof(response));
504
-			if (n<0){
442
+			n=send_all(unix_tcp_sock, response, sizeof(response));
443
+			if (n<=0){
505 444
 				LOG(L_ERR, "BUG: tcp_send: failed write: %s (%d)\n",
506 445
 						strerror(errno), errno);
446
+				n=-1;
507 447
 				goto end;
508 448
 			}	
509 449
 			n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s);
510
-			if (n<0){
450
+			if (n<=0){
511 451
 				LOG(L_ERR, "BUG: tcp_send: failed send_fd: %s (%d)\n",
512 452
 						strerror(errno), errno);
453
+				n=-1;
513 454
 				goto end;
514 455
 			}
515 456
 			goto send_it;
... ...
@@ -517,21 +458,23 @@ no_id:
517 458
 get_fd:
518 459
 			/* todo: see if this is not the same process holding
519 460
 			 *  c  and if so send directly on c->fd */
520
-			DBG("tcp_send: tcp connection found, acquiring fd\n");
461
+			DBG("tcp_send: tcp connection found (%p), acquiring fd\n", c);
521 462
 			/* get the fd */
522 463
 			response[0]=(long)c;
523 464
 			response[1]=CONN_GET_FD;
524
-			n=write(unix_tcp_sock, response, sizeof(response));
525
-			if (n<0){
465
+			n=send_all(unix_tcp_sock, response, sizeof(response));
466
+			if (n<=0){
526 467
 				LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n",
527 468
 						strerror(errno), errno);
469
+				n=-1;
528 470
 				goto release_c;
529 471
 			}
530 472
 			DBG("tcp_send, c= %p, n=%d\n", c, n);
531 473
 			n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd);
532
-			if (n<0){
474
+			if (n<=0){
533 475
 				LOG(L_ERR, "BUG: tcp_send: failed to get fd(receive_fd):"
534 476
 							" %s (%d)\n", strerror(errno), errno);
477
+				n=-1;
535 478
 				goto release_c;
536 479
 			}
537 480
 			DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd);
... ...
@@ -567,11 +510,12 @@ send_it:
567 510
 		/* tell "main" it should drop this (optional it will t/o anyway?)*/
568 511
 		response[0]=(long)c;
569 512
 		response[1]=CONN_ERROR;
570
-		n=write(unix_tcp_sock, response, sizeof(response));
571
-		/* CONN_ERROR wil auto-dec refcnt => we must not call tcpconn_put !!*/
572
-		if (n<0){
513
+		n=send_all(unix_tcp_sock, response, sizeof(response));
514
+		/* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/
515
+		if (n<=0){
573 516
 			LOG(L_ERR, "BUG: tcp_send: error return failed (write):%s (%d)\n",
574 517
 					strerror(errno), errno);
518
+			n=-1;
575 519
 		}
576 520
 		close(fd);
577 521
 		return n; /* error return, no tcpconn_put */
... ...
@@ -596,10 +540,10 @@ void tcpconn_timeout(fd_set* set)
596 540
 	
597 541
 	ticks=get_ticks();
598 542
 	TCPCONN_LOCK; /* fixme: we can lock only on delete IMO */
599
-	for(h=0; h<TCP_ID_HASH_SIZE; h++){
600
-		c=tcpconn_id_hash[h];
543
+	for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
544
+		c=tcpconn_addr_hash[h];
601 545
 		while(c){
602
-			next=c->id_next;
546
+			next=c->next;
603 547
 			if ((c->refcnt==0) && (ticks>c->timeout)) {
604 548
 				DBG("tcpconn_timeout: timeout for hash=%d - %p (%d > %d)\n",
605 549
 						h, c, ticks, c->timeout);
... ...
@@ -642,7 +586,7 @@ int tcp_init(struct socket_info* sock_info)
642 586
 #endif
643 587
 	
644 588
 	addr=&sock_info->su;
645
-	/* sock_info->proto=PROTO_TCP; */
589
+	sock_info->proto=PROTO_TCP;
646 590
 	if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
647 591
 		LOG(L_ERR, "ERROR: tcp_init: could no init sockaddr_union\n");
648 592
 		goto error;
... ...
@@ -737,17 +681,19 @@ static int send2child(struct tcp_connection* tcpconn)
737 681
 	
738 682
 	tcp_children[idx].busy++;
739 683
 	tcp_children[idx].n_reqs++;
740
-	tcpconn->refcnt++;
741 684
 	if (min_busy){
742
-		LOG(L_WARN, "WARNING: send2child:no free tcp receiver, "
685
+		LOG(L_WARN, "WARNING: send2child: no free tcp receiver, "
743 686
 				" connection passed to the least busy one (%d)\n",
744 687
 				min_busy);
745 688
 	}
746 689
 	DBG("send2child: to tcp child %d %d(%d), %p\n", idx, 
747 690
 					tcp_children[idx].proc_no,
748 691
 					tcp_children[idx].pid, tcpconn);
749
-	send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
750
-			tcpconn->s);
692
+	if (send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
693
+			tcpconn->s)<=0){
694
+		LOG(L_ERR, "ERROR: send2child: send_fd failed\n");
695
+		return -1;
696
+	}
751 697
 	
752 698
 	return 0; /* just to fix a warning*/
753 699
 }
... ...
@@ -776,6 +722,8 @@ static inline void handle_new_connect(struct socket_info* si,
776 722
 		/* add socket to list */
777 723
 		tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT);
778 724
 		if (tcpconn){
725
+			tcpconn->refcnt++; /* safe, not yet available to the
726
+								  outside world */
779 727
 			tcpconn_add(tcpconn);
780 728
 			DBG("tcp_main_loop: new connection: %p %d\n",
781 729
 				tcpconn, tcpconn->s);
... ...
@@ -784,6 +732,7 @@ static inline void handle_new_connect(struct socket_info* si,
784 732
 				LOG(L_ERR,"ERROR: tcp_main_loop: no children "
785 733
 						"available\n");
786 734
 				TCPCONN_LOCK;
735
+				tcpconn->refcnt--;
787 736
 				if (tcpconn->refcnt==0){
788 737
 					close(tcpconn->s);
789 738
 					_tcpconn_rm(tcpconn);
... ...
@@ -809,33 +758,24 @@ void tcp_main_loop()
809 758
 	int bytes;
810 759
 	struct timeval timeout;
811 760
 	int fd;
812
-	struct socket_info* si;
813 761
 
814 762
 	/*init */
815 763
 	maxfd=0;
816 764
 	FD_ZERO(&master_set);
817 765
 	/* set all the listen addresses */
818
-	for (si=tcp_listen; si; si=si->next){
819
-		if ((si->proto==PROTO_TCP) &&(si->socket!=-1)){
820
-			FD_SET(si->socket, &master_set);
821
-			if (si->socket>maxfd) maxfd=si->socket;
822
-		}else{
823
-			LOG(L_CRIT, "BUG: tcp_main_loop: non tcp address in tcp_listen\n");
766
+	for (r=0; r<sock_no; r++){
767
+		if ((tcp_info[r].proto==PROTO_TCP) &&(tcp_info[r].socket!=-1)){
768
+			FD_SET(tcp_info[r].socket, &master_set);
769
+			if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
824 770
 		}
825
-	}
826 771
 #ifdef USE_TLS
827
-	if (!tls_disable){
828
-		for (si=tls_listen; si; si=si->next){
829
-			if ((si->proto==PROTO_TLS) && (si->socket!=-1)){
830
-				FD_SET(si->socket, &master_set);
831
-				if (si->socket>maxfd) maxfd=si->socket;
832
-			}else{
833
-				LOG(L_CRIT, "BUG: tcp_main_loop: non tls address"
834
-						" in tls_listen\n");
835
-			}
772
+		if ((!tls_disable)&&(tls_info[r].proto==PROTO_TLS) &&
773
+				(tls_info[r].socket!=-1)){
774
+			FD_SET(tls_info[r].socket, &master_set);
775
+			if (tls_info[r].socket>maxfd) maxfd=tls_info[r].socket;
836 776
 		}
837
-	}
838 777
 #endif
778
+	}
839 779
 	/* set all the unix sockets used for child comm */
840 780
 	for (r=1; r<process_no; r++){
841 781
 		if (pt[r].unix_sock>0){ /* we can't have 0, we never close it!*/
... ...
@@ -860,18 +800,19 @@ void tcp_main_loop()
860 800
 			n=0;
861 801
 		}
862 802
 		
863
-		for (si=tcp_listen; si && n; si=si->next)
864
-			handle_new_connect(si, &sel_set, &n);
803
+		for (r=0; r<sock_no && n; r++){
804
+			handle_new_connect(&tcp_info[r], &sel_set, &n);
865 805
 #ifdef USE_TLS
866 806
 			if (!tls_disable)
867
-				for (si=tls_listen; si && n; si=si->next)
868
-					handle_new_connect(si, &sel_set, &n);
807
+				handle_new_connect(&tls_info[r], &sel_set, &n);
869 808
 #endif
809
+		}
870 810
 		
871 811
 		/* check all the read fds (from the tcpconn_addr_hash ) */
872
-		for (h=0; h<TCP_ID_HASH_SIZE; h++){
873
-			for(tcpconn=tcpconn_id_hash[h]; tcpconn && n; 
874
-					tcpconn=tcpconn->id_next){
812
+		for (h=0; h<TCP_ADDR_HASH_SIZE; h++){
813
+			for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; 
814
+					tcpconn=tcpconn->next){
815
+				/* FIXME: is refcnt==0 really necessary? */
875 816
 				if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
876 817
 					/* new data available */
877 818
 					n--;
... ...
@@ -879,10 +820,12 @@ void tcp_main_loop()
879 820
 					DBG("tcp_main_loop: data available on %p [h:%d] %d\n",
880 821
 							tcpconn, h, tcpconn->s);
881 822
 					FD_CLR(tcpconn->s, &master_set);
823
+					tcpconn_ref(tcpconn); /* refcnt ++ */
882 824
 					if (send2child(tcpconn)<0){
883 825
 						LOG(L_ERR,"ERROR: tcp_main_loop: no "
884 826
 									"children available\n");
885 827
 						TCPCONN_LOCK;
828
+						tcpconn->refcnt--;
886 829
 						if (tcpconn->refcnt==0){
887 830
 							fd=tcpconn->s;
888 831
 							_tcpconn_rm(tcpconn);
... ...
@@ -899,24 +842,21 @@ void tcp_main_loop()
899 842
 			if ( (pt[r].unix_sock>0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
900 843
 				/* (we can't have a fd==0, 0 is never closed )*/
901 844
 				n--;
902
-				/* errno==EINTR !!! TODO*/
903
-read_again:
904
-				bytes=read(pt[r].unix_sock, response, sizeof(response));
845
+				/* read until sizeof(response)
846
+				 * (this is a SOCK_STREAM so read is not atomic */
847
+				bytes=recv_all(pt[r].unix_sock, response, sizeof(response));
905 848
 				if (bytes==0){
906 849
 					/* EOF -> bad, child has died */
907 850
 					LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
908 851
 					/* don't listen on it any more */
909 852
 					FD_CLR(pt[r].unix_sock, &master_set);
910 853
 					/*exit(-1);*/
911
-					continue;
854
+					continue; /* skip this and try the next one */
912 855
 				}else if (bytes<0){
913
-					if (errno==EINTR) goto read_again;
914
-					else{
915
-						LOG(L_CRIT, "ERROR: tcp_main_loop: read from child: "
916
-								" %s\n", strerror(errno));
917
-						/* try to continue ? */
918
-						continue;
919
-					}
856
+					LOG(L_CRIT, "ERROR: tcp_main_loop: read from child:  %s\n",
857
+							strerror(errno));
858
+					/* try to ignore ? */
859
+					continue; /* skip this and try the next one */
920 860
 				}
921 861
 					
922 862
 				DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
... ...
@@ -949,7 +889,11 @@ read_again:
949 889
 						if (pt[r].idx>=0){
950 890
 							tcp_children[pt[r].idx].busy--;
951 891
 						}else{
952
-							LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
892
+							/* CON_ERROR is ok, since we can get it from
893
+							 * any process using tcp_send */
894
+							if (cmd!=CONN_ERROR)
895
+								LOG(L_CRIT, "BUG: tcp_main_loop:"
896
+											"CONN_EOF/DESTROY\n");
953 897
 						}
954 898
 						tcpconn=(struct tcp_connection*)response[0];
955 899
 						if (tcpconn){
... ...
@@ -962,6 +906,7 @@ read_again:
962 906
 								DBG("tcp_main_loop: destroying connection\n");
963 907
 								fd=tcpconn->s;
964 908
 #ifdef USE_TLS
909
+								/*FIXME: lock ->writelock ? */
965 910
 								if (tcpconn->type==PROTO_TLS)
966 911
 									tls_close(tcpconn, fd);
967 912
 #endif
... ...
@@ -983,8 +928,11 @@ read_again:
983 928
 						/* WARNING: take care of setting refcnt properly to
984 929
 						 * avoid race condition */
985 930
 						if (tcpconn){
986
-							send_fd(pt[r].unix_sock, &tcpconn,
987
-									sizeof(tcpconn), tcpconn->s);
931
+							if (send_fd(pt[r].unix_sock, &tcpconn,
932
+										sizeof(tcpconn), tcpconn->s)<=0){
933
+								LOG(L_ERR, "ERROR: tcp_main_loop:"
934
+										"send_fd failed\n");
935
+							}
988 936
 						}else{
989 937
 							LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
990 938
 						}
... ...
@@ -995,8 +943,20 @@ read_again:
995 943
 						/* WARNING: take care of setting refcnt properly to
996 944
 						 * avoid race condition */
997 945
 						if (tcpconn){
998
-							receive_fd(pt[r].unix_sock, &tcpconn,
999
-										sizeof(tcpconn), &tcpconn->s);
946
+							bytes=receive_fd(pt[r].unix_sock, &tcpconn,
947
+									sizeof(tcpconn), &tcpconn->s);
948
+								if (bytes<sizeof(tcpconn)){
949
+									if (bytes<0){
950
+										LOG(L_CRIT, "BUG: tcp_main_loop:"
951
+												" CONN_NEW: receive_fd "
952
+												"failed\n");
953
+									}else{
954
+										LOG(L_CRIT, "BUG: tcp_main_loop:"
955
+												" CONN_NEW: to few bytes "
956
+												"received (%d)\n", bytes );
957
+									}
958
+									break; /* try to ignore */
959
+								}
1000 960
 							/* add tcpconn to the list*/
1001 961
 							tcpconn_add(tcpconn);
1002 962
 							FD_SET(tcpconn->s, &master_set);
... ...
@@ -1012,7 +972,7 @@ read_again:
1012 972
 									cmd);
1013 973
 				}
1014 974
 			}
1015
-		}
975
+		} /* for */
1016 976
 		
1017 977
 		/* remove old connections */
1018 978
 		tcpconn_timeout(&master_set);
... ...
@@ -1047,9 +1007,10 @@ int init_tcp()
1047 1007
 	}
1048 1008
 	*connection_id=1;
1049 1009
 	/* alloc hashtables*/
1050
-	tcpconn_aliases_hash=(struct tcp_conn_alias**)
1051
-			shm_malloc(TCP_ALIAS_HASH_SIZE* sizeof(struct tcp_conn_alias*));
1052
-	if (tcpconn_aliases_hash==0){
1010
+	tcpconn_addr_hash=(struct tcp_connection**)shm_malloc(TCP_ADDR_HASH_SIZE*
1011
+								sizeof(struct tcp_connection*));
1012
+
1013
+	if (tcpconn_addr_hash==0){
1053 1014
 		LOG(L_CRIT, "ERROR: init_tcp: could not alloc address hashtable\n");
1054 1015
 		shm_free(connection_id);
1055 1016
 		connection_id=0;
... ...
@@ -1065,16 +1026,16 @@ int init_tcp()
1065 1026
 		LOG(L_CRIT, "ERROR: init_tcp: could not alloc id hashtable\n");
1066 1027
 		shm_free(connection_id);
1067 1028
 		connection_id=0;
1068
-		shm_free(tcpconn_aliases_hash);
1069
-		tcpconn_aliases_hash=0;
1029
+		shm_free(tcpconn_addr_hash);
1030
+		tcpconn_addr_hash=0;
1070 1031
 		lock_destroy(tcpconn_lock);
1071 1032
 		lock_dealloc((void*)tcpconn_lock);
1072 1033
 		tcpconn_lock=0;
1073 1034
 		goto error;
1074 1035
 	}
1075 1036
 	/* init hashtables*/
1076
-	memset((void*)tcpconn_aliases_hash, 0, 
1077
-			TCP_ALIAS_HASH_SIZE * sizeof(struct tcp_conn_alias*));
1037
+	memset((void*)tcpconn_addr_hash, 0, 
1038
+			TCP_ADDR_HASH_SIZE * sizeof(struct tcp_connection*));
1078 1039
 	memset((void*)tcpconn_id_hash, 0, 
1079 1040
 			TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
1080 1041
 	return 0;
... ...
@@ -1092,9 +1053,9 @@ void destroy_tcp()
1092 1053
 		lock_dealloc((void*)tcpconn_lock);
1093 1054
 		tcpconn_lock=0;
1094 1055
 	}
1095
-	if(tcpconn_aliases_hash){
1096
-		shm_free(tcpconn_aliases_hash);
1097
-		tcpconn_aliases_hash=0;
1056
+	if(tcpconn_addr_hash){
1057
+		shm_free(tcpconn_addr_hash);
1058
+		tcpconn_addr_hash=0;
1098 1059
 	}
1099 1060
 	if(tcpconn_id_hash){
1100 1061
 		shm_free(tcpconn_id_hash);
... ...
@@ -1152,6 +1113,7 @@ int tcp_init_children()
1152 1113
 			unix_tcp_sock=sockfd[1];
1153 1114
 			bind_address=0; /* force a SEGFAULT if someone uses a non-init.
1154 1115
 							   bind address on tcp */
1116
+			bind_idx=0;
1155 1117
 			if (init_child(r+children_no+1) < 0) {
1156 1118
 				LOG(L_ERR, "init_children failed\n");
1157 1119
 				goto error;
... ...
@@ -547,7 +547,8 @@ void release_tcpconn(struct tcp_connection* c, long state, int unix_sock)
547 547
 		/* errno==EINTR, EWOULDBLOCK a.s.o todo */
548 548
 		response[0]=(long)c;
549 549
 		response[1]=state;
550
-		write(unix_sock, response, sizeof(response));
550
+		if (send_all(unix_sock, response, sizeof(response))<=0)
551
+			LOG(L_ERR, "ERROR: release_tcpconn: send_all failed\n");
551 552
 }
552 553
 
553 554
 
... ...
@@ -625,9 +626,6 @@ void tcp_receive_loop(int unix_sock)
625 626
 					release_tcpconn(con, resp, unix_sock);
626 627
 					goto skip;
627 628
 				}
628
-#ifdef USE_TLS
629
-				if (con->type==PROTO_TLS) tls_tcpconn_update_fd(con, s);
630
-#endif
631 629
 				con->timeout=get_ticks()+TCP_CHILD_TIMEOUT;
632 630
 				FD_SET(s, &master_set);
633 631
 				if (maxfd<s) maxfd=s;
... ...
@@ -646,7 +644,21 @@ skip:
646 644
 					DBG("tcp receive: match, fd:isset\n");
647 645
 #endif
648 646
 					nfds--;
649
-					resp=tcp_read_req(con);
647
+#ifdef USE_TLS
648
+					if (con->type==PROTO_TLS){
649
+						/* we have to avoid to run in the same time 
650
+						 * with a tls_write becasue of the 
651
+						 * update_fd stuff  (we don't want a write
652
+						 * stealing the fd under us or vice versa)
653
+						 * => lock on con->write_lock (ugly hack) */
654
+						lock_get(&con->write_lock);
655
+						tls_tcpconn_update_fd(con, s);
656
+						resp=tcp_read_req(con);
657
+						lock_release(&con->write_lock);
658
+					}else
659
+#else
660
+						resp=tcp_read_req(con);
661
+#endif
650 662
 					if (resp<0){
651 663
 						FD_CLR(con->fd, &master_set);
652 664
 						tcpconn_listrm(list, con, c_next, c_prev);