- fixed port byte order bugs introduced last night
[sip-router] / tcp_main.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 Fhg Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 /*
28  * History:
29  * --------
30  *  2002-11-29  created by andrei
31  *  2002-12-11  added tcp_send (andrei)
32  *  2003-01-20  locking fixes, hashtables (andrei)
33  *  2003-02-20  s/lock_t/gen_lock_t/ to avoid a conflict on solaris (andrei)
34  *  2003-02-25  Nagle is disabled if -DDISABLE_NAGLE (andrei)
35  *  2003-03-29  SO_REUSEADDR before calling bind to allow
36  *              server restart, Nagle set on the (hopefuly) 
37  *              correct socket (jiri)
38  *  2003-03-31  always try to find the corresponding tcp listen socket for
39  *               a temp. socket and store in in *->bind_address: added
40  *               find_tcp_si, modified tcpconn_connect (andrei)
41  */
42
43
44 #ifdef USE_TCP
45
46
47 #ifndef SHM_MEM
48 #error "shared memory support needed (add -DSHM_MEM to Makefile.defs)"
49 #endif
50
51
52 #include <sys/time.h>
53 #include <sys/types.h>
54 #include <sys/select.h>
55 #include <sys/socket.h>
56 #include <netinet/tcp.h>
57 #include <sys/uio.h>  /* writev*/
58 #include <netdb.h>
59
60 #include <unistd.h>
61
62 #include <errno.h>
63 #include <string.h>
64
65
66
67 #include "ip_addr.h"
68 #include "pass_fd.h"
69 #include "tcp_conn.h"
70 #include "globals.h"
71 #include "pt.h"
72 #include "locking.h"
73 #include "mem/mem.h"
74 #include "mem/shm_mem.h"
75 #include "timer.h"
76 #include "sr_module.h"
77 #include "tcp_server.h"
78 #include "tcp_init.h"
79
80
81
82
83 #define local_malloc pkg_malloc
84 #define local_free   pkg_free
85
86 #define MAX_TCP_CHILDREN 100
87
88 struct tcp_child{
89         pid_t pid;
90         int unix_sock; /* unix sock fd, copied from pt*/
91         int busy;
92         int n_reqs; /* number of requests serviced so far */
93 };
94
95
96
97 /* connection hash table (after ip&port) */
98 struct tcp_connection** tcpconn_addr_hash=0;
99 /* connection hash table (after connection id) */
100 struct tcp_connection** tcpconn_id_hash=0;
101 gen_lock_t* tcpconn_lock=0;
102
103 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
104 static int connection_id=1; /*  unique for each connection, used for 
105                                                                 quickly finding the corresponding connection
106                                                                 for a reply */
107 int unix_tcp_sock;
108
109 int tcp_proto_no=-1; /* tcp protocol number as returned by getprotobyname */
110
111
112 struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
113                                                                         struct socket_info* ba)
114 {
115         struct tcp_connection *c;
116         
117
118         c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection));
119         if (c==0){
120                 LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n");
121                 goto error;
122         }
123         c->s=sock;
124         c->fd=-1; /* not initialized */
125         if (lock_init(&c->write_lock)==0){
126                 LOG(L_ERR, "ERROR: tcpconn_add: init lock failed\n");
127                 goto error;
128         }
129         
130         c->rcv.src_su=*su;
131         
132         c->refcnt=0;
133         c->bad=0;
134         su2ip_addr(&c->rcv.src_ip, su);
135         c->rcv.src_port=su_getport(su);
136         c->rcv.proto=PROTO_TCP;
137         c->rcv.bind_address=ba;
138         if (ba){
139                 c->rcv.dst_ip=ba->address;
140                 c->rcv.dst_port=ba->port_no;
141         }
142         init_tcp_req(&c->req);
143         c->timeout=get_ticks()+TCP_CON_TIMEOUT;
144         c->id=connection_id++;
145         c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/
146         c->rcv.proto_reserved2=0;
147         return c;
148         
149 error:
150         return 0;
151 }
152
153
154
155
156 struct socket_info* find_tcp_si(union sockaddr_union* s)
157 {
158         int r;
159         struct ip_addr ip;
160         
161         su2ip_addr(&ip, s);
162         for (r=0; r<sock_no; r++)
163                 if (ip_addr_cmp(&ip, &tcp_info[r].address)){
164                         /* found it, we use first match */
165                         return &tcp_info[r];
166                 }
167         return 0; /* no match */
168 }
169
170
171 struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
172 {
173         int s;
174         struct socket_info* si;
175         union sockaddr_union my_name;
176         int my_name_len;
177 #ifdef DISABLE_NAGLE
178         int flag;
179 #endif
180
181         s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
182         if (s<0){
183                 LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
184                                 errno, strerror(errno));
185                 goto error;
186         }
187 #ifdef DISABLE_NAGLE
188         flag=1;
189         if ( (tcp_proto_no!=-1) && 
190 /* fix: I used to get here 
191  * ERROR: tcp_connect: could not disable Nagle: Protocol not available    
192  *                      (setsockopt(sock_info->socket, tcp_proto_no , TCP_NODELAY, */
193                           (setsockopt(s, tcp_proto_no , TCP_NODELAY,
194                                         &flag, sizeof(flag))<0) ){
195                 LOG(L_ERR, "ERROR: tcp_connect: could not disable Nagle: %s\n",
196                                 strerror(errno));
197         }
198 #endif
199         if (connect(s, &server->s, sockaddru_len(*server))<0){
200                 LOG(L_ERR, "ERROR: tcpconn_connect: connect: (%d) %s\n",
201                                 errno, strerror(errno));
202                 goto error;
203         }
204         my_name_len=sizeof(my_name);
205         if (getsockname(s, &my_name.s, &my_name_len)!=0){
206                 LOG(L_ERR, "ERROR: tcp_connect: getsockname failed: %s(%d)\n",
207                                 strerror(errno), errno);
208                 si=0; /* try to go on */
209         }
210         si=find_tcp_si(&my_name);
211         if (si==0){
212                 LOG(L_ERR, "ERROR: tcp_connect: could not find coresponding"
213                                 " listening socket, using default...\n");
214                 if (server->s.sa_family==AF_INET) si=sendipv4_tcp;
215 #ifdef USE_IPV6
216                 else si=sendipv6_tcp;
217 #endif
218         }
219         return tcpconn_new(s, server, si); /*FIXME: set sock idx! */
220 error:
221         return 0;
222 }
223
224
225
226 struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
227 {
228         unsigned hash;
229
230         if (c){
231                 TCPCONN_LOCK;
232                 /* add it at the begining of the list*/
233                 hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
234                 c->addr_hash=hash;
235                 tcpconn_listadd(tcpconn_addr_hash[hash], c, next, prev);
236                 hash=tcp_id_hash(c->id);
237                 c->id_hash=hash;
238                 tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev);
239                 TCPCONN_UNLOCK;
240                 DBG("tcpconn_add: hashes: %d, %d\n", c->addr_hash, c->id_hash);
241                 return c;
242         }else{
243                 LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n");
244                 return 0;
245         }
246 }
247
248
249 /* unsafe tcpconn_rm version (nolocks) */
250 void _tcpconn_rm(struct tcp_connection* c)
251 {
252         tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
253         tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
254         lock_destroy(&c->write_lock);
255         shm_free(c);
256 }
257
258
259
260 void tcpconn_rm(struct tcp_connection* c)
261 {
262         TCPCONN_LOCK;
263         tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
264         tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
265         TCPCONN_UNLOCK;
266         lock_destroy(&c->write_lock);
267         shm_free(c);
268 }
269
270
271 /* finds a connection, if id=0 uses the ip addr & port (host byte order)
272  * WARNING: unprotected (locks) use tcpconn_get unless you really
273  * know what you are doing */
274 struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
275 {
276
277         struct tcp_connection *c;
278         unsigned hash;
279         
280         DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", port);
281         if (id){
282                 hash=tcp_id_hash(id);
283                 for (c=tcpconn_id_hash[hash]; c; c=c->id_next){
284                         DBG("c=%p, c->id=%d, ip=",c, c->id);
285                         print_ip(&c->rcv.src_ip);
286                         DBG(" port=%d\n", c->rcv.src_port);
287                         if ((id==c->id)&&(!c->bad)) return c;
288                 }
289         }else if (ip){
290                 hash=tcp_addr_hash(ip, port);
291                 for (c=tcpconn_addr_hash[hash]; c; c=c->next){
292                         DBG("c=%p, c->id=%d, ip=",c, c->id);
293                         print_ip(&c->rcv.src_ip);
294                         DBG(" port=%d\n", c->rcv.src_port);
295                         if ( (!c->bad) && (port==c->rcv.src_port) &&
296                                         (ip_addr_cmp(ip, &c->rcv.src_ip)) )
297                                 return c;
298                 }
299         }
300         return 0;
301 }
302
303
304
305 /* _tcpconn_find with locks and timeout */
306 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port,
307                                                                         int timeout)
308 {
309         struct tcp_connection* c;
310         TCPCONN_LOCK;
311         c=_tcpconn_find(id, ip, port);
312         if (c){ 
313                         c->refcnt++;
314                         c->timeout=get_ticks()+timeout;
315         }
316         TCPCONN_UNLOCK;
317         return c;
318 }
319
320
321
322 void tcpconn_put(struct tcp_connection* c)
323 {
324         c->refcnt--; /* FIXME: atomic_dec */
325 }
326
327
328
329 /* finds a tcpconn & sends on it */
330 int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id)
331 {
332         struct tcp_connection *c;
333         struct ip_addr ip;
334         int port;
335         int fd;
336         long response[2];
337         int n;
338         
339         port=0;
340         if (to){
341                 su2ip_addr(&ip, to);
342                 port=su_getport(to);
343                 c=tcpconn_get(id, &ip, port, TCP_CON_SEND_TIMEOUT); 
344         }else if (id){
345                 c=tcpconn_get(id, 0, 0, TCP_CON_SEND_TIMEOUT);
346         }else{
347                 LOG(L_CRIT, "BUG: tcp_send called with null id & to\n");
348                 return -1;
349         }
350         
351         if (id){
352                 if (c==0) {
353                         if (to){
354                                 /* try again w/o id */
355                                 c=tcpconn_get(0, &ip, port, TCP_CON_SEND_TIMEOUT);
356                                 goto no_id;
357                         }else{
358                                 LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
359                                                 id);
360                                 return -1;
361                         }
362                 }else goto get_fd;
363         }
364 no_id:
365                 if (c==0){
366                         DBG("tcp_send: no open tcp connection found, opening new one\n");
367                         /* create tcp connection */
368                         if ((c=tcpconn_connect(to))==0){
369                                 LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
370                                 return -1;
371                         }
372                         c->refcnt++;
373                         fd=c->s;
374                         
375                         /* send the new tcpconn to "tcp main" */
376                         response[0]=(long)c;
377                         response[1]=CONN_NEW;
378                         n=write(unix_tcp_sock, response, sizeof(response));
379                         if (n<0){
380                                 LOG(L_ERR, "BUG: tcp_send: failed write: %s (%d)\n",
381                                                 strerror(errno), errno);
382                                 goto end;
383                         }       
384                         n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s);
385                         if (n<0){
386                                 LOG(L_ERR, "BUG: tcp_send: failed send_fd: %s (%d)\n",
387                                                 strerror(errno), errno);
388                                 goto end;
389                         }
390                         goto send_it;
391                 }
392 get_fd:
393                         /* todo: see if this is not the same process holding
394                          *  c  and if so send directly on c->fd */
395                         DBG("tcp_send: tcp connection found, acquiring fd\n");
396                         /* get the fd */
397                         response[0]=(long)c;
398                         response[1]=CONN_GET_FD;
399                         n=write(unix_tcp_sock, response, sizeof(response));
400                         if (n<0){
401                                 LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n",
402                                                 strerror(errno), errno);
403                                 goto release_c;
404                         }
405                         DBG("tcp_send, c= %p, n=%d\n", c, n);
406                         n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd);
407                         if (n<0){
408                                 LOG(L_ERR, "BUG: tcp_send: failed to get fd(receive_fd):"
409                                                         " %s (%d)\n", strerror(errno), errno);
410                                 goto release_c;
411                         }
412                         DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd);
413                 
414         
415         
416 send_it:
417         DBG("tcp_send: sending...\n");
418         lock_get(&c->write_lock);
419         n=send(fd, buf, len,
420 #ifdef HAVE_MSG_NOSIGNAL
421                         MSG_NOSIGNAL
422 #else
423                         0
424 #endif
425                         );
426         lock_release(&c->write_lock);
427         DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd);
428         DBG("tcp_send: buf=\n%.*s\n", (int)len, buf);
429         if (n<0){
430                 LOG(L_ERR, "ERROR: tcpsend: failed to send, n=%d: %s (%d)\n",
431                                 n, strerror(errno), errno);
432                 /* error on the connection , mark it as bad and set 0 timeout */
433                 c->bad=1;
434                 c->timeout=0;
435                 /* tell "main" it should drop this (optional it will t/o anyway?)*/
436                 response[0]=(long)c;
437                 response[1]=CONN_ERROR;
438                 n=write(unix_tcp_sock, response, sizeof(response));
439                 if (n<0){
440                         LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n",
441                                         strerror(errno), errno);
442                         goto release_c;
443                 }
444         }
445 end:
446         close(fd);
447 release_c:
448         tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */
449         return n;
450 }
451
452
453
454 /* very ineficient for now - FIXME*/
455 void tcpconn_timeout(fd_set* set)
456 {
457         struct tcp_connection *c, *next;
458         int ticks;
459         unsigned h;;
460         
461         
462         ticks=get_ticks();
463         TCPCONN_LOCK; /* fixme: we can lock only on delete IMO */
464         for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
465                 c=tcpconn_addr_hash[h];
466                 while(c){
467                         next=c->next;
468                         if ((c->refcnt==0) && (ticks>c->timeout)) {
469                                 DBG("tcpconn_timeout: timeout for hash=%d - %p (%d > %d)\n",
470                                                 h, c, ticks, c->timeout);
471                                 if (c->s>0) {
472                                         FD_CLR(c->s, set);
473                                         close(c->s);
474                                 }
475                                 _tcpconn_rm(c);
476                         }
477                         c=next;
478                 }
479         }
480         TCPCONN_UNLOCK;
481 }
482
483
484
485 int tcp_init(struct socket_info* sock_info)
486 {
487         union sockaddr_union* addr;
488 #if defined(SO_REUSEADDR) && !defined(TCP_DONT_REUSEADDR) 
489         int optval;
490 #endif
491 #ifdef DISABLE_NAGLE
492         int flag;
493         struct protoent* pe;
494
495         if (tcp_proto_no==-1){ /* if not already set */
496                 pe=getprotobyname("tcp");
497                 if (pe==0){
498                         LOG(L_ERR, "ERROR: tcp_init: could not get TCP protocol number\n");
499                         tcp_proto_no=-1;
500                 }else{
501                         tcp_proto_no=pe->p_proto;
502                 }
503         }
504 #endif
505         
506         addr=&sock_info->su;
507         sock_info->proto=PROTO_TCP;
508         if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
509                 LOG(L_ERR, "ERROR: tcp_init: could no init sockaddr_union\n");
510                 goto error;
511         }
512         sock_info->socket=socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
513         if (sock_info->socket==-1){
514                 LOG(L_ERR, "ERROR: tcp_init: socket: %s\n", strerror(errno));
515                 goto error;
516         }
517 #ifdef DISABLE_NAGLE
518         flag=1;
519         if ( (tcp_proto_no!=-1) &&
520                  (setsockopt(sock_info->socket, tcp_proto_no , TCP_NODELAY,
521                                          &flag, sizeof(flag))<0) ){
522                 LOG(L_ERR, "ERROR: tcp_init: could not disable Nagle: %s\n",
523                                 strerror(errno));
524         }
525 #endif
526
527
528 #if defined(SO_REUSEADDR) && !defined(TCP_DONT_REUSEADDR) 
529         /* Stevens, "Network Programming", Section 7.5, "Generic Socket
530      * Options": "...server started,..a child continues..on existing
531          * connection..listening server is restarted...call to bind fails
532          * ... ALL TCP servers should specify the SO_REUSEADDRE option 
533          * to allow the server to be restarted in this situation
534          *
535          * Indeed, without this option, the server can't restart.
536          *   -jiri
537          */
538         optval=1;
539         if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR,
540                                 (void*)&optval, sizeof(optval))==-1) {
541                 LOG(L_ERR, "ERROR: tcp_init: setsockopt %s\n",
542                         strerror(errno));
543                 goto error;
544         }
545 #endif
546
547         if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
548                 LOG(L_ERR, "ERROR: tcp_init: bind(%x, %p, %d) on %s: %s\n",
549                                 sock_info->socket, &addr->s, 
550                                 sockaddru_len(*addr),
551                                 sock_info->address_str.s,
552                                 strerror(errno));
553                 goto error;
554         }
555         if (listen(sock_info->socket, 10)==-1){
556                 LOG(L_ERR, "ERROR: tcp_init: listen(%x, %p, %d) on %s: %s\n",
557                                 sock_info->socket, &addr->s, 
558                                 sockaddru_len(*addr),
559                                 sock_info->address_str.s,
560                                 strerror(errno));
561                 goto error;
562         }
563         
564         return 0;
565 error:
566         if (sock_info->socket!=-1){
567                 close(sock_info->socket);
568                 sock_info->socket=-1;
569         }
570         return -1;
571 }
572
573
574
575 static int send2child(struct tcp_connection* tcpconn)
576 {
577         int i;
578         int min_busy;
579         int idx;
580         
581         min_busy=tcp_children[0].busy;
582         idx=0;
583         for (i=0; i<tcp_children_no; i++){
584                 if (!tcp_children[i].busy){
585                         idx=i;
586                         min_busy=0;
587                         break;
588                 }else if (min_busy>tcp_children[i].busy){
589                         min_busy=tcp_children[i].busy;
590                         idx=i;
591                 }
592         }
593         
594         tcp_children[idx].busy++;
595         tcp_children[idx].n_reqs++;
596         tcpconn->refcnt++;
597         if (min_busy){
598                 LOG(L_WARN, "WARNING: send2child:no free tcp receiver, "
599                                 " connection passed to the least busy one (%d)\n",
600                                 min_busy);
601         }
602         DBG("send2child: to child %d, %ld\n", idx, (long)tcpconn);
603         send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
604                         tcpconn->s);
605         
606         return 0; /* just to fix a warning*/
607 }
608
609
610 void tcp_main_loop()
611 {
612         int r;
613         int n;
614         fd_set master_set;
615         fd_set sel_set;
616         int maxfd;
617         int new_sock;
618         union sockaddr_union su;
619         struct tcp_connection* tcpconn;
620         unsigned h;
621         long response[2];
622         int cmd;
623         int bytes;
624         socklen_t su_len;
625         struct timeval timeout;
626
627         /*init */
628         maxfd=0;
629         FD_ZERO(&master_set);
630         /* set all the listen addresses */
631         for (r=0; r<sock_no; r++){
632                 if ((tcp_info[r].proto==PROTO_TCP) &&(tcp_info[r].socket!=-1)){
633                         FD_SET(tcp_info[r].socket, &master_set);
634                         if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
635                 }
636         }
637         /* set all the unix sockets used for child comm */
638         for (r=1; r<process_no; r++){
639                 if (pt[r].unix_sock>0){ /* we can't have 0, we never close it!*/
640                         FD_SET(pt[r].unix_sock, &master_set);
641                         if (pt[r].unix_sock>maxfd) maxfd=pt[r].unix_sock;
642                 }
643         }
644         
645         
646         /* main loop*/
647         
648         while(1){
649                 sel_set=master_set;
650                 timeout.tv_sec=TCP_MAIN_SELECT_TIMEOUT;
651                 timeout.tv_usec=0;
652                 n=select(maxfd+1, &sel_set, 0 ,0 , &timeout);
653                 if (n<0){
654                         if (errno==EINTR) continue; /* just a signal */
655                         /* errors */
656                         LOG(L_ERR, "ERROR: tcp_main_loop: select:(%d) %s\n", errno,
657                                         strerror(errno));
658                         n=0;
659                 }
660                 
661                 for (r=0; r<sock_no && n; r++){
662                         if ((FD_ISSET(tcp_info[r].socket, &sel_set))){
663                                 /* got a connection on r */
664                                 su_len=sizeof(su);
665                                 new_sock=accept(tcp_info[r].socket, &(su.s), &su_len);
666                                 n--;
667                                 if (new_sock<0){
668                                         LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
669                                                         " connection(%d): %s\n", errno, strerror(errno));
670                                         continue;
671                                 }
672                                 
673                                 /* add socket to list */
674                                 tcpconn=tcpconn_new(new_sock, &su, &tcp_info[r]);
675                                 if (tcpconn){
676                                         tcpconn_add(tcpconn);
677                                         DBG("tcp_main_loop: new connection: %p %d\n",
678                                                 tcpconn, tcpconn->s);
679                                         /* pass it to a child */
680                                         if(send2child(tcpconn)<0){
681                                                 LOG(L_ERR,"ERROR: tcp_main_loop: no children "
682                                                                 "available\n");
683                                                 TCPCONN_LOCK;
684                                                 if (tcpconn->refcnt==0){
685                                                         close(tcpconn->s);
686                                                         _tcpconn_rm(tcpconn);
687                                                 }else tcpconn->timeout=0; /* force expire */
688                                                 TCPCONN_UNLOCK;
689                                         }
690                                 }
691                         }
692                 }
693                 
694                 /* check all the read fds (from the tcpconn_addr_hash ) */
695                 for (h=0; h<TCP_ADDR_HASH_SIZE; h++){
696                         for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; 
697                                         tcpconn=tcpconn->next){
698                                 if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
699                                         /* new data available */
700                                         n--;
701                                         /* pass it to child, so remove it from select list */
702                                         DBG("tcp_main_loop: data available on %p [h:%d] %d\n",
703                                                         tcpconn, h, tcpconn->s);
704                                         FD_CLR(tcpconn->s, &master_set);
705                                         if (send2child(tcpconn)<0){
706                                                 LOG(L_ERR,"ERROR: tcp_main_loop: no "
707                                                                         "children available\n");
708                                                 TCPCONN_LOCK;
709                                                 if (tcpconn->refcnt==0){
710                                                         close(tcpconn->s);
711                                                         _tcpconn_rm(tcpconn);
712                                                 }else tcpconn->timeout=0; /* force expire*/
713                                                 TCPCONN_UNLOCK;
714                                         }
715                                 }
716                         }
717                 }
718                 /* check unix sockets & listen | destroy connections */
719                 /* start from 1, the "main" process does not transmit anything*/
720                 for (r=1; r<process_no && n; r++){
721                         if ( (pt[r].unix_sock>0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
722                                 /* (we can't have a fd==0, 0 i s never closed )*/
723                                 n--;
724                                 /* errno==EINTR !!! TODO*/
725 read_again:
726                                 bytes=read(pt[r].unix_sock, response, sizeof(response));
727                                 if (bytes==0){
728                                         /* EOF -> bad, child has died */
729                                         LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
730                                         /* don't listen on it any more */
731                                         FD_CLR(pt[r].unix_sock, &master_set);
732                                         /*exit(-1)*/;
733                                 }else if (bytes<0){
734                                         if (errno==EINTR) goto read_again;
735                                         else{
736                                                 LOG(L_CRIT, "ERROR: tcp_main_loop: read from child: "
737                                                                 " %s\n", strerror(errno));
738                                                 /* try to continue ? */
739                                         }
740                                 }
741                                         
742                                 DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
743                                                 response[0], response[1], r, pt[r].pid);
744                                 cmd=response[1];
745                                 switch(cmd){
746                                         case CONN_RELEASE:
747                                                 if (pt[r].idx>=0){
748                                                         tcp_children[pt[r].idx].busy--;
749                                                 }else{
750                                                         LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
751                                                 }
752                                                 tcpconn=(struct tcp_connection*)response[0];
753                                                 if (tcpconn){
754                                                                 if (tcpconn->bad) goto tcpconn_destroy;
755                                                                 FD_SET(tcpconn->s, &master_set);
756                                                                 if (maxfd<tcpconn->s) maxfd=tcpconn->s;
757                                                                 /* update the timeout*/
758                                                                 tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
759                                                                 tcpconn_put(tcpconn);
760                                                                 DBG("tcp_main_loop: %p refcnt= %d\n", 
761                                                                         tcpconn, tcpconn->refcnt);
762                                                 }
763                                                 break;
764                                         case CONN_ERROR:
765                                         case CONN_DESTROY:
766                                         case CONN_EOF:
767                                                 if (pt[r].idx>=0){
768                                                         tcp_children[pt[r].idx].busy--;
769                                                 }else{
770                                                         LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
771                                                 }
772                                                 tcpconn=(struct tcp_connection*)response[0];
773                                                 if (tcpconn){
774                                                         if (tcpconn->s!=-1)
775                                                                 FD_CLR(tcpconn->s, &master_set);
776                 tcpconn_destroy:
777                                                         TCPCONN_LOCK; /*avoid races w/ tcp_send*/
778                                                         tcpconn->refcnt--;
779                                                         if (tcpconn->refcnt==0){ 
780                                                                 DBG("tcp_main_loop: destroying connection\n");
781                                                                 close(tcpconn->s);
782                                                                 _tcpconn_rm(tcpconn);
783                                                         }else{
784                                                                 /* force timeout */
785                                                                 tcpconn->timeout=0;
786                                                                 tcpconn->bad=1;
787                                                                 DBG("tcp_main_loop: delaying ...\n");
788                                                                 
789                                                         }
790                                                         TCPCONN_UNLOCK;
791                                                 }
792                                                 break;
793                                         case CONN_GET_FD:
794                                                 /* send the requested FD  */
795                                                 tcpconn=(struct tcp_connection*)response[0];
796                                                 /* WARNING: take care of setting refcnt properly to
797                                                  * avoid race condition */
798                                                 if (tcpconn){
799                                                         send_fd(pt[r].unix_sock, &tcpconn,
800                                                                         sizeof(tcpconn), tcpconn->s);
801                                                 }else{
802                                                         LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
803                                                 }
804                                                 break;
805                                         case CONN_NEW:
806                                                 /* update the fd in the requested tcpconn*/
807                                                 tcpconn=(struct tcp_connection*)response[0];
808                                                 /* WARNING: take care of setting refcnt properly to
809                                                  * avoid race condition */
810                                                 if (tcpconn){
811                                                         receive_fd(pt[r].unix_sock, &tcpconn,
812                                                                                 sizeof(tcpconn), &tcpconn->s);
813                                                         /* add tcpconn to the list*/
814                                                         tcpconn_add(tcpconn);
815                                                         FD_SET(tcpconn->s, &master_set);
816                                                         if (maxfd<tcpconn->s) maxfd=tcpconn->s;
817                                                         /* update the timeout*/
818                                                         tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
819                                                 }else{
820                                                         LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
821                                                 }
822                                                 break;
823                                         default:
824                                                         LOG(L_CRIT, "BUG: tcp_main_loop: unknown cmd %d\n",
825                                                                         cmd);
826                                 }
827                         }
828                 }
829                 
830                 /* remove old connections */
831                 tcpconn_timeout(&master_set);
832         
833         }
834 }
835
836
837
838 int init_tcp()
839 {
840         /* init lock */
841         tcpconn_lock=lock_alloc();
842         if (tcpconn_lock==0){
843                 LOG(L_CRIT, "ERROR: init_tcp: could not alloc lock\n");
844                 goto error;
845         }
846         if (lock_init(tcpconn_lock)==0){
847                 LOG(L_CRIT, "ERROR: init_tcp: could not init lock\n");
848                 lock_dealloc((void*)tcpconn_lock);
849                 tcpconn_lock=0;
850                 goto error;
851         }
852         /* alloc hashtables*/
853         tcpconn_addr_hash=(struct tcp_connection**)shm_malloc(TCP_ADDR_HASH_SIZE*
854                                                                 sizeof(struct tcp_connection*));
855
856         if (tcpconn_addr_hash==0){
857                 LOG(L_CRIT, "ERROR: init_tcp: could not alloc address hashtable\n");
858                 lock_destroy(tcpconn_lock);
859                 lock_dealloc((void*)tcpconn_lock);
860                 tcpconn_lock=0;
861                 goto error;
862         }
863         
864         tcpconn_id_hash=(struct tcp_connection**)shm_malloc(TCP_ID_HASH_SIZE*
865                                                                 sizeof(struct tcp_connection*));
866         if (tcpconn_id_hash==0){
867                 LOG(L_CRIT, "ERROR: init_tcp: could not alloc id hashtable\n");
868                 shm_free(tcpconn_addr_hash);
869                 tcpconn_addr_hash=0;
870                 lock_destroy(tcpconn_lock);
871                 lock_dealloc((void*)tcpconn_lock);
872                 tcpconn_lock=0;
873                 goto error;
874         }
875         /* init hashtables*/
876         memset((void*)tcpconn_addr_hash, 0, 
877                         TCP_ADDR_HASH_SIZE * sizeof(struct tcp_connection*));
878         memset((void*)tcpconn_id_hash, 0, 
879                         TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
880         return 0;
881 error:
882                 return -1;
883 }
884
885
886
887 /* cleanup before exit */
888 void destroy_tcp()
889 {
890         if (tcpconn_lock){
891                 lock_destroy(tcpconn_lock);
892                 lock_dealloc((void*)tcpconn_lock);
893                 tcpconn_lock=0;
894         }
895         if(tcpconn_addr_hash){
896                 shm_free(tcpconn_addr_hash);
897                 tcpconn_addr_hash=0;
898         }
899         if(tcpconn_id_hash){
900                 shm_free(tcpconn_id_hash);
901                 tcpconn_id_hash=0;
902         }
903 }
904
905
906
907 /* starts the tcp processes */
908 int tcp_init_children()
909 {
910         int r;
911         int sockfd[2];
912         pid_t pid;
913         
914         
915         /* create the tcp sock_info structures */
916         /* copy the sockets --moved to main_loop*/
917         
918         /* fork children & create the socket pairs*/
919         for(r=0; r<tcp_children_no; r++){
920                 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
921                         LOG(L_ERR, "ERROR: tcp_main: socketpair failed: %s\n",
922                                         strerror(errno));
923                         goto error;
924                 }
925                 
926                 process_no++;
927                 pid=fork();
928                 if (pid<0){
929                         LOG(L_ERR, "ERROR: tcp_main: fork failed: %s\n",
930                                         strerror(errno));
931                         goto error;
932                 }else if (pid>0){
933                         /* parent */
934                         close(sockfd[1]);
935                         tcp_children[r].pid=pid;
936                         tcp_children[r].busy=0;
937                         tcp_children[r].n_reqs=0;
938                         tcp_children[r].unix_sock=sockfd[0];
939                         pt[process_no].pid=pid;
940                         pt[process_no].unix_sock=sockfd[0];
941                         pt[process_no].idx=r;
942                         strncpy(pt[process_no].desc, "tcp receiver", MAX_PT_DESC);
943                 }else{
944                         /* child */
945                         close(sockfd[0]);
946                         unix_tcp_sock=sockfd[1];
947                         bind_address=0; /* force a SEGFAULT if someone uses a non-init.
948                                                            bind address on tcp */
949                         bind_idx=0;
950                         if (init_child(r+children_no) < 0) {
951                                 LOG(L_ERR, "init_child failed\n");
952                                 goto error;
953                         }
954                         tcp_receive_loop(sockfd[1]);
955                 }
956         }
957         return 0;
958 error:
959         return -1;
960 }
961
962 #endif