- more tcp stuff (uses locking.h, hashtables, mostly untested)
[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
29 #ifdef USE_TCP
30
31
32 #ifndef SHM_MEM
33 #error "shared memory support needed (add -DSHM_MEM to Makefile.defs)"
34 #endif
35
36 #include <sys/select.h>
37
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41
42 #include <unistd.h>
43
44 #include <errno.h>
45 #include <string.h>
46
47
48
49 #include "ip_addr.h"
50 #include "pass_fd.h"
51 #include "tcp_conn.h"
52 #include "globals.h"
53 #include "pt.h"
54 #include "locking.h"
55 #include "mem/mem.h"
56 #include "mem/shm_mem.h"
57 #include "timer.h"
58 #include "tcp_server.h"
59 #include "tcp_init.h"
60
61
62
63
64 #define local_malloc pkg_malloc
65 #define local_free   pkg_free
66
67 #define MAX_TCP_CHILDREN 100
68
69 struct tcp_child{
70         pid_t pid;
71         int unix_sock; /* unix sock fd, copied from pt*/
72         int busy;
73         int n_reqs; /* number of requests serviced so far */
74 };
75
76
77
78 /* connection hash table (after ip&port) */
79 struct tcp_connection** tcpconn_addr_hash=0;
80 /* connection hash table (after connection id) */
81 struct tcp_connection** tcpconn_id_hash=0;
82 lock_t* tcpconn_lock=0;
83
84 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
85 static int connection_id=1; /*  unique for each connection, used for 
86                                                                 quickly finding the corresponding connection
87                                                                 for a reply */
88 int unix_tcp_sock;
89
90
91
92 struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
93                                                                         struct socket_info* ba)
94 {
95         struct tcp_connection *c;
96         
97
98         c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection));
99         if (c==0){
100                 LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n");
101                 goto error;
102         }
103         c->s=sock;
104         c->fd=sock;
105         c->rcv.src_su=*su;
106         
107         c->refcnt=0;
108         su2ip_addr(&c->rcv.src_ip, su);
109         c->rcv.src_port=su_getport(su);
110         c->rcv.proto=PROTO_TCP;
111         c->rcv.bind_address=ba;
112         if (ba){
113                 c->rcv.dst_ip=ba->address;
114                 c->rcv.dst_port=ba->port_no;
115         }
116         init_tcp_req(&c->req);
117         c->timeout=get_ticks()+TCP_CON_TIMEOUT;
118         c->id=connection_id++;
119         c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/
120         c->rcv.proto_reserved2=0;
121         return c;
122         
123 error:
124         return 0;
125 }
126
127
128
129 struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
130 {
131         int s;
132
133         s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
134         if (s<0){
135                 LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
136                                 errno, strerror(errno));
137                 goto error;
138         }
139         if (connect(s, &server->s, sockaddru_len(*server))<0){
140                 LOG(L_ERR, "ERROR: tcpconn_connect: connect: (%d) %s\n",
141                                 errno, strerror(errno));
142                 goto error;
143         }
144         return tcpconn_new(s, server, 0); /*FIXME: set sock idx! */
145 error:
146         return 0;
147 }
148
149
150
151 struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
152 {
153         unsigned hash;
154
155         if (c){
156                 TCPCONN_LOCK;
157                 /* add it at the begining of the list*/
158                 hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
159                 c->addr_hash=hash;
160                 tcpconn_listadd(tcpconn_addr_hash[hash], c, next, prev);
161                 hash=tcp_id_hash(c->id);
162                 c->id_hash=hash;
163                 tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev);
164                 TCPCONN_UNLOCK;
165                 DBG("tcpconn_add: hashes: %d, %d\n", c->addr_hash, c->id_hash);
166                 return c;
167         }else{
168                 LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n");
169                 return 0;
170         }
171 }
172
173
174
175 void tcpconn_rm(struct tcp_connection* c)
176 {
177         TCPCONN_LOCK;
178         tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
179         tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
180         TCPCONN_UNLOCK;
181         shm_free(c);
182 }
183
184
185 /* finds a connection, if id=0 uses the ip addr & port
186  * WARNING: unprotected (locks) use tcpconn_get unless you really
187  * know what you are doing */
188 struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
189 {
190
191         struct tcp_connection *c;
192         unsigned hash;
193         
194         DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", ntohs(port));
195         if (id){
196                 hash=tcp_id_hash(id);
197                 for (c=tcpconn_id_hash[hash]; c; c=c->id_next){
198                         DBG("c=%p, c->id=%d, ip=",c, c->id);
199                         print_ip(&c->rcv.src_ip);
200                         DBG(" port=%d\n", ntohs(c->rcv.src_port));
201                         if (id==c->id) return c;
202                 }
203         }else if (ip){
204                 hash=tcp_addr_hash(ip, port);
205                 for (c=tcpconn_addr_hash[hash]; c; c=c->next){
206                         DBG("c=%p, c->id=%d, ip=",c, c->id);
207                         print_ip(&c->rcv.src_ip);
208                         DBG(" port=%d\n", ntohs(c->rcv.src_port));
209                         if ( (port==c->rcv.src_port) && (ip_addr_cmp(ip, &c->rcv.src_ip)) )
210                                 return c;
211                 }
212         }
213         return 0;
214 }
215
216
217
218 /* _tcpconn_find with locks */
219 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
220 {
221         struct tcp_connection* c;
222         TCPCONN_LOCK;
223         c=_tcpconn_find(id, ip, port);
224         if (c) c->refcnt++;
225         TCPCONN_UNLOCK;
226         return c;
227 }
228
229
230
231 void tcpconn_put(struct tcp_connection* c)
232 {
233         c->refcnt--; /* FIXME: atomic_dec */
234 }
235
236
237
238 /* finds a tcpconn & sends on it */
239 int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id)
240 {
241         struct tcp_connection *c;
242         struct ip_addr ip;
243         int port;
244         long response[2];
245         int n;
246         
247         port=0;
248         if (to){
249                 su2ip_addr(&ip, to);
250                 port=su_getport(to);
251                 c=tcpconn_get(id, &ip, port); /* lock ;inc refcnt; unlock */
252         }else if (id){
253                 c=tcpconn_get(id, 0, 0);
254         }else{
255                 LOG(L_CRIT, "BUG: tcp_send called with null id & to\n");
256                 return -1;
257         }
258         
259         if (id){
260                 if (c==0) {
261                         if (to){
262                                 c=tcpconn_get(0, &ip, port); /* try again w/o id */
263                                 goto no_id;
264                         }else{
265                                 LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
266                                                 id);
267                                 return -1;
268                         }
269                 }else goto get_fd;
270         }
271 no_id:
272                 if (c==0){
273                         DBG("tcp_send: no open tcp connection found, opening new one\n");
274                         /* create tcp connection */
275                         if ((c=tcpconn_connect(to))==0){
276                                 LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
277                                 return 0;
278                         }
279                         c->refcnt++;
280                         
281                         /* send the new tcpconn to "tcp main" */
282                         response[0]=(long)c;
283                         response[1]=CONN_NEW;
284                         n=write(unix_tcp_sock, response, sizeof(response));
285                         n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s);
286                         goto send_it;
287                 }
288 get_fd:
289                         DBG("tcp_send: tcp connection found, acquiring fd\n");
290                         /* get the fd */
291                         response[0]=(long)c;
292                         response[1]=CONN_GET_FD;
293                         n=write(unix_tcp_sock, response, sizeof(response));
294                         DBG("tcp_send, c= %p, n=%d\n", c, n);
295                         n=receive_fd(unix_tcp_sock, &c, sizeof(c), &c->fd);
296                         DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, c->fd);
297                 
298         
299         
300 send_it:
301         DBG("tcp_send: sending...\n");
302         n=write(c->fd, buf, len);
303         DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, c->fd);
304         close(c->fd);
305         tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */
306         return n;
307 }
308
309
310
311 /* very ineficient for now - FIXME*/
312 void tcpconn_timeout(fd_set* set)
313 {
314         struct tcp_connection *c, *next;
315         int ticks;
316         unsigned h;;
317         
318         
319         ticks=get_ticks();
320         for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
321                 c=tcpconn_addr_hash[h];
322                 while(c){
323                         next=c->next;
324                         if ((c->refcnt==0) && (ticks>c->timeout)) {
325                                 DBG("tcpconn_timeout: timeout for hash=%d - %p (%d > %d)\n",
326                                                 h, c, ticks, c->timeout);
327                                 if (c->s>0) {
328                                         FD_CLR(c->s, set);
329                                         close(c->s);
330                                 }
331                                 tcpconn_rm(c);
332                         }
333                         c=next;
334                 }
335         }
336 }
337
338
339
340 int tcp_init(struct socket_info* sock_info)
341 {
342         union sockaddr_union* addr;
343         
344         addr=&sock_info->su;
345         sock_info->proto=PROTO_TCP;
346         if (init_su(addr, &sock_info->address, htons(sock_info->port_no))<0){
347                 LOG(L_ERR, "ERROR: tcp_init: could no init sockaddr_union\n");
348                 goto error;
349         }
350         sock_info->socket=socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
351         if (sock_info->socket==-1){
352                 LOG(L_ERR, "ERROR: tcp_init: socket: %s\n", strerror(errno));
353                 goto error;
354         }
355         if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
356                 LOG(L_ERR, "ERROR: tcp_init: bind(%x, %p, %d) on %s: %s\n",
357                                 sock_info->socket, &addr->s, 
358                                 sockaddru_len(*addr),
359                                 sock_info->address_str.s,
360                                 strerror(errno));
361                 goto error;
362         }
363         if (listen(sock_info->socket, 10)==-1){
364                 LOG(L_ERR, "ERROR: tcp_init: listen(%x, %p, %d) on %s: %s\n",
365                                 sock_info->socket, &addr->s, 
366                                 sockaddru_len(*addr),
367                                 sock_info->address_str.s,
368                                 strerror(errno));
369                 goto error;
370         }
371         
372         return 0;
373 error:
374         if (sock_info->socket!=-1){
375                 close(sock_info->socket);
376                 sock_info->socket=-1;
377         }
378         return -1;
379 }
380
381
382
383 static int send2child(struct tcp_connection* tcpconn)
384 {
385         int i;
386         int min_busy;
387         int idx;
388         
389         min_busy=tcp_children[0].busy;
390         idx=0;
391         for (i=0; i<tcp_children_no; i++){
392                 if (!tcp_children[i].busy){
393                         idx=i;
394                         min_busy=0;
395                         break;
396                         return 0;
397                 }else if (min_busy>tcp_children[i].busy){
398                         min_busy=tcp_children[i].busy;
399                         idx=i;
400                 }
401         }
402         
403         tcp_children[idx].busy++;
404         tcp_children[idx].n_reqs++;
405         tcpconn->refcnt++;
406         if (min_busy){
407                 LOG(L_WARN, "WARNING: send2child:no free tcp receiver, "
408                                 " connection passed to the least busy one (%d)\n",
409                                 min_busy);
410         }
411         DBG("send2child: to child %d, %ld\n", idx, (long)tcpconn);
412         send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
413                         tcpconn->s);
414         
415         return 0; /* just to fix a warning*/
416 }
417
418
419 void tcp_main_loop()
420 {
421         int r;
422         int n;
423         fd_set master_set;
424         fd_set sel_set;
425         int maxfd;
426         int new_sock;
427         union sockaddr_union su;
428         struct tcp_connection* tcpconn;
429         unsigned h;
430         long response[2];
431         int cmd;
432         int bytes;
433         socklen_t su_len;
434         struct timeval timeout;
435
436         /*init */
437         maxfd=0;
438         FD_ZERO(&master_set);
439         /* set all the listen addresses */
440         for (r=0; r<sock_no; r++){
441                 if ((tcp_info[r].proto==PROTO_TCP) &&(tcp_info[r].socket!=-1)){
442                         FD_SET(tcp_info[r].socket, &master_set);
443                         if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
444                 }
445         }
446         /* set all the unix sockets used for child comm */
447         for (r=1; r<process_no; r++){
448                 if (pt[r].unix_sock>0){ /* we can't have 0, we never close it!*/
449                         FD_SET(pt[r].unix_sock, &master_set);
450                         if (pt[r].unix_sock>maxfd) maxfd=pt[r].unix_sock;
451                 }
452         }
453         
454         
455         /* main loop*/
456         
457         while(1){
458                 sel_set=master_set;
459                 timeout.tv_sec=TCP_MAIN_SELECT_TIMEOUT;
460                 timeout.tv_usec=0;
461                 n=select(maxfd+1, &sel_set, 0 ,0 , &timeout);
462                 if (n<0){
463                         if (errno==EINTR) continue; /* just a signal */
464                         /* errors */
465                         LOG(L_ERR, "ERROR: tcp_main_loop: select:(%d) %s\n", errno,
466                                         strerror(errno));
467                         n=0;
468                 }
469                 
470                 for (r=0; r<sock_no && n; r++){
471                         if ((FD_ISSET(tcp_info[r].socket, &sel_set))){
472                                 /* got a connection on r */
473                                 su_len=sizeof(su);
474                                 new_sock=accept(tcp_info[r].socket, &(su.s), &su_len);
475                                 n--;
476                                 if (new_sock<0){
477                                         LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
478                                                         " connection(%d): %s\n", errno, strerror(errno));
479                                         continue;
480                                 }
481                                 
482                                 /* add socket to list */
483                                 tcpconn=tcpconn_new(new_sock, &su, &tcp_info[r]);
484                                 if (tcpconn){
485                                         tcpconn_add(tcpconn);
486                                         DBG("tcp_main_loop: new connection: %p %d\n",
487                                                 tcpconn, tcpconn->s);
488                                         /* pass it to a child */
489                                         if(send2child(tcpconn)<0){
490                                                 LOG(L_ERR,"ERROR: tcp_main_loop: no children "
491                                                                 "available\n");
492                                                 close(tcpconn->s);
493                                                 tcpconn_rm(tcpconn);
494                                         }
495                                 }
496                         }
497                 }
498                 
499                 /* check all the read fds (from the tcpconn_addr_hash ) */
500                 for (h=0; h<TCP_ADDR_HASH_SIZE; h++){
501                         for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; 
502                                         tcpconn=tcpconn->next){
503                                 if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
504                                         /* new data available */
505                                         n--;
506                                         /* pass it to child, so remove it from select list */
507                                         DBG("tcp_main_loop: data available on %p [h:%d] %d\n",
508                                                         tcpconn, h, tcpconn->s);
509                                         FD_CLR(tcpconn->s, &master_set);
510                                         if (send2child(tcpconn)<0){
511                                                 LOG(L_ERR,"ERROR: tcp_main_loop: no "
512                                                                         "children available\n");
513                                                 close(tcpconn->s);
514                                                 tcpconn_rm(tcpconn);
515                                         }
516                                 }
517                         }
518                 }
519                 /* check unix sockets & listen | destroy connections */
520                 /* start from 1, the "main" process does not transmit anything*/
521                 for (r=1; r<process_no && n; r++){
522                         if ( (pt[r].unix_sock>0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
523                                 /* (we can't have a fd==0, 0 i s never closed )*/
524                                 n--;
525                                 /* errno==EINTR !!! TODO*/
526 read_again:
527                                 bytes=read(pt[r].unix_sock, response, sizeof(response));
528                                 if (bytes==0){
529                                         /* EOF -> bad, child has died */
530                                         LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
531                                         /* don't listen on it any more */
532                                         FD_CLR(pt[r].unix_sock, &master_set);
533                                         /*exit(-1)*/;
534                                 }else if (bytes<0){
535                                         if (errno==EINTR) goto read_again;
536                                         else{
537                                                 LOG(L_CRIT, "ERROR: tcp_main_loop: read from child: "
538                                                                 " %s\n", strerror(errno));
539                                                 /* try to continue ? */
540                                         }
541                                 }
542                                         
543                                 DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
544                                                 response[0], response[1], r, pt[r].pid);
545                                 cmd=response[1];
546                                 switch(cmd){
547                                         case CONN_RELEASE:
548                                                 if (pt[r].idx>=0){
549                                                         tcp_children[pt[r].idx].busy--;
550                                                 }else{
551                                                         LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
552                                                 }
553                                                 tcpconn=(struct tcp_connection*)response[0];
554                                                 if (tcpconn){
555                                                         tcpconn->refcnt--;
556                                                         DBG("tcp_main_loop: %p refcnt= %d\n", 
557                                                                         tcpconn, tcpconn->refcnt);
558                                                                 FD_SET(tcpconn->s, &master_set);
559                                                                 if (maxfd<tcpconn->s) maxfd=tcpconn->s;
560                                                                 /* update the timeout*/
561                                                                 tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
562                                                 }
563                                                 break;
564                                         case CONN_ERROR:
565                                         case CONN_DESTROY:
566                                         case CONN_EOF:
567                                                 if (pt[r].idx>=0){
568                                                         tcp_children[pt[r].idx].busy--;
569                                                 }else{
570                                                         LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
571                                                 }
572                                                 tcpconn=(struct tcp_connection*)response[0];
573                                                 if (tcpconn){
574                                                         tcpconn->refcnt--;
575                                                         if (tcpconn->refcnt==0){
576                                                                 DBG("tcp_main_loop: destroying connection\n");
577                                                                 close(tcpconn->s);
578                                                                 tcpconn_rm(tcpconn);
579                                                         }else{
580                                                                 DBG("tcp_main_loop: delaying ...\n");
581                                                         }
582                                                 }
583                                                 break;
584                                         case CONN_GET_FD:
585                                                 /* send the requested FD  */
586                                                 tcpconn=(struct tcp_connection*)response[0];
587                                                 /* WARNING: take care of setting refcnt properly to
588                                                  * avoid race condition */
589                                                 if (tcpconn){
590                                                         send_fd(pt[r].unix_sock, &tcpconn,
591                                                                         sizeof(tcpconn), tcpconn->s);
592                                                 }else{
593                                                         LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
594                                                 }
595                                                 break;
596                                         case CONN_NEW:
597                                                 /* update the fd in the requested tcpconn*/
598                                                 tcpconn=(struct tcp_connection*)response[0];
599                                                 /* WARNING: take care of setting refcnt properly to
600                                                  * avoid race condition */
601                                                 if (tcpconn){
602                                                         receive_fd(pt[r].unix_sock, &tcpconn,
603                                                                                 sizeof(tcpconn), &tcpconn->s);
604                                                         /* add tcpconn to the list*/
605                                                         tcpconn_add(tcpconn);
606                                                         FD_SET(tcpconn->s, &master_set);
607                                                         if (maxfd<tcpconn->s) maxfd=tcpconn->s;
608                                                         /* update the timeout*/
609                                                         tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
610                                                 }else{
611                                                         LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
612                                                 }
613                                                 break;
614                                         default:
615                                                         LOG(L_CRIT, "BUG: tcp_main_loop: unknown cmd %d\n",
616                                                                         cmd);
617                                 }
618                         }
619                 }
620                 
621                 /* remove old connections */
622                 tcpconn_timeout(&master_set);
623         
624         }
625 }
626
627
628
629 int init_tcp()
630 {
631         /* init lock */
632         tcpconn_lock=lock_alloc();
633         if (tcpconn_lock==0){
634                 LOG(L_CRIT, "ERROR: init_tcp: could not alloc lock\n");
635                 goto error;
636         }
637         if (lock_init(tcpconn_lock)==0){
638                 LOG(L_CRIT, "ERROR: init_tcp: could not init lock\n");
639                 lock_dealloc((void*)tcpconn_lock);
640                 tcpconn_lock=0;
641                 goto error;
642         }
643         /* alloc hashtables*/
644         tcpconn_addr_hash=(struct tcp_connection**)shm_malloc(TCP_ADDR_HASH_SIZE*
645                                                                 sizeof(struct tcp_connection*));
646
647         if (tcpconn_addr_hash==0){
648                 LOG(L_CRIT, "ERROR: init_tcp: could not alloc address hashtable\n");
649                 lock_destroy(tcpconn_lock);
650                 lock_dealloc((void*)tcpconn_lock);
651                 tcpconn_lock=0;
652                 goto error;
653         }
654         
655         tcpconn_id_hash=(struct tcp_connection**)shm_malloc(TCP_ID_HASH_SIZE*
656                                                                 sizeof(struct tcp_connection*));
657         if (tcpconn_id_hash==0){
658                 LOG(L_CRIT, "ERROR: init_tcp: could not alloc id hashtable\n");
659                 shm_free(tcpconn_addr_hash);
660                 tcpconn_addr_hash=0;
661                 lock_destroy(tcpconn_lock);
662                 lock_dealloc((void*)tcpconn_lock);
663                 tcpconn_lock=0;
664                 goto error;
665         }
666         /* init hashtables*/
667         memset((void*)tcpconn_addr_hash, 0, 
668                         TCP_ADDR_HASH_SIZE * sizeof(struct tcp_connection*));
669         memset((void*)tcpconn_id_hash, 0, 
670                         TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
671         return 0;
672 error:
673                 return -1;
674 }
675
676
677
678 /* cleanup before exit */
679 void destroy_tcp()
680 {
681         if (tcpconn_lock){
682                 lock_destroy(tcpconn_lock);
683                 lock_dealloc((void*)tcpconn_lock);
684                 tcpconn_lock=0;
685         }
686         if(tcpconn_addr_hash){
687                 shm_free(tcpconn_addr_hash);
688                 tcpconn_addr_hash=0;
689         }
690         if(tcpconn_id_hash){
691                 shm_free(tcpconn_id_hash);
692                 tcpconn_id_hash=0;
693         }
694 }
695
696
697
698 /* starts the tcp processes */
699 int tcp_init_children()
700 {
701         int r;
702         int sockfd[2];
703         pid_t pid;
704         
705         
706         /* create the tcp sock_info structures */
707         /* copy the sockets --moved to main_loop*/
708         
709         /* fork children & create the socket pairs*/
710         for(r=0; r<tcp_children_no; r++){
711                 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
712                         LOG(L_ERR, "ERROR: tcp_main: socketpair failed: %s\n",
713                                         strerror(errno));
714                         goto error;
715                 }
716                 
717                 process_no++;
718                 pid=fork();
719                 if (pid<0){
720                         LOG(L_ERR, "ERROR: tcp_main: fork failed: %s\n",
721                                         strerror(errno));
722                         goto error;
723                 }else if (pid>0){
724                         /* parent */
725                         close(sockfd[1]);
726                         tcp_children[r].pid=pid;
727                         tcp_children[r].busy=0;
728                         tcp_children[r].n_reqs=0;
729                         tcp_children[r].unix_sock=sockfd[0];
730                         pt[process_no].pid=pid;
731                         pt[process_no].unix_sock=sockfd[0];
732                         pt[process_no].idx=r;
733                         strncpy(pt[process_no].desc, "tcp receiver", MAX_PT_DESC);
734                 }else{
735                         /* child */
736                         close(sockfd[0]);
737                         unix_tcp_sock=sockfd[1];
738                         tcp_receive_loop(sockfd[1]);
739                 }
740         }
741         return 0;
742 error:
743         return -1;
744 }
745
746 #endif