e4bd5bf82a5f8ad5c29737f5dae28c365df15fa5
[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 "mem/mem.h"
55 #include "mem/shm_mem.h"
56 #include "timer.h"
57 #include "tcp_server.h"
58
59
60
61 #define local_malloc pkg_malloc
62 #define local_free   pkg_free
63
64 #define MAX_TCP_CHILDREN 100
65
66 struct tcp_child{
67         pid_t pid;
68         int unix_sock; /* unix sock fd, copied from pt*/
69         int busy;
70         int n_reqs; /* number of requests serviced so far */
71 };
72
73
74
75 struct tcp_connection** conn_list=0;
76 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
77 static int connection_id=1; /*  unique for each connection, used for 
78                                                                 quickly finding the corresponding connection
79                                                                 for a reply */
80 int unix_tcp_sock;
81
82
83
84 struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, int i)
85 {
86         struct tcp_connection *c;
87         
88
89         c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection));
90         if (c==0){
91                 LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n");
92                 goto error;
93         }
94         c->s=sock;
95         c->fd=sock;
96         c->su=*su;
97         c->sock_idx=i;
98         c->refcnt=0;
99         su2ip_addr(&c->ip, su);
100         c->port=su_getport(su);
101         init_tcp_req(&c->req);
102         c->timeout=get_ticks()+TCP_CON_TIMEOUT;
103         c->id=connection_id++;
104         return c;
105         
106 error:
107         return 0;
108 }
109
110
111
112 struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
113 {
114         int s;
115
116         s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
117         if (s<0){
118                 LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
119                                 errno, strerror(errno));
120                 goto error;
121         }
122         if (connect(s, &server->s, sockaddru_len(*server))<0){
123                 LOG(L_ERR, "ERROR: tcpconn_connect: connect: (%d) %s\n",
124                                 errno, strerror(errno));
125                 goto error;
126         }
127         return tcpconn_new(s, server, 0); /*FIXME: set sock idx! */
128 error:
129         return 0;
130 }
131
132
133
134 struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
135 {
136         TCPCONN_LOCK;
137         /* add it at the begining of the list*/
138         if (c) tcpconn_listadd(*conn_list, c, next, prev);
139         TCPCONN_UNLOCK;
140         return c;
141 }
142
143
144
145 void tcpconn_rm(struct tcp_connection* c)
146 {
147         TCPCONN_LOCK;
148         tcpconn_listrm(*conn_list, c, next, prev);
149         TCPCONN_UNLOCK;
150         shm_free(c);
151 }
152
153
154 /* finds a connection, if id=0 uses the ip addr & port */
155 struct tcp_connection* tcpconn_find(int id, struct ip_addr* ip, int port)
156 {
157
158         struct tcp_connection *c;
159         
160         DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", port);
161         for (c=*conn_list; c; c=c->next){
162                 DBG("c=%p, c->id=%d, ip=",c, c->id);
163                 print_ip(&c->ip);
164                 DBG(" port=%d\n", c->port);
165                 if (id){
166                         if (id==c->id) return c;
167                 }else if ((port==c->port)&&(ip_addr_cmp(ip, &c->ip))) return c;
168         }
169         return 0;
170 }
171
172
173
174 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
175 {
176         struct tcp_connection* c;
177         TCPCONN_LOCK;
178         c=tcpconn_find(id, ip, port);
179         if (c) c->refcnt++;
180         TCPCONN_UNLOCK;
181         return c;
182 }
183
184
185
186 void tcpconn_put(struct tcp_connection* c)
187 {
188         c->refcnt--; /* FIXME: atomic_dec */
189 }
190
191
192
193 /* finds a tcpconn & sends on it */
194 int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id)
195 {
196         struct tcp_connection *c;
197         struct ip_addr ip;
198         int port;
199         long response[2];
200         int n;
201         
202         su2ip_addr(&ip, to);
203         port=su_getport(to);
204         
205         c=tcpconn_get(id, &ip, port); /* lock ;inc refcnt; unlock */
206         if (id){
207                 if (c==0) {
208                 LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
209                                         id);
210                         return -1;
211                 }
212         }else{
213                 if (c==0){
214                         DBG("tcp_send: no open tcp connection found, opening new one\n");
215                         /* create tcp connection */
216                         if ((c=tcpconn_connect(to))==0){
217                                 LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
218                                 return 0;
219                         }
220                         c->refcnt++;
221                         
222                         /* send the new tcpconn to "tcp main" */
223                         response[0]=(long)c;
224                         response[1]=CONN_NEW;
225                         n=write(unix_tcp_sock, response, sizeof(response));
226                         n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s);
227                 }else{
228                         DBG("tcp_send: tcp connection found, acquiring fd\n");
229                         /* get the fd */
230                         response[0]=(long)c;
231                         response[1]=CONN_GET_FD;
232                         n=write(unix_tcp_sock, response, sizeof(response));
233                         n=receive_fd(unix_tcp_sock, &c, sizeof(c), &c->fd);
234                 }
235         
236         }
237         DBG("tcp_send: sending...\n");
238         n=write(c->fd, buf, len);
239         close(c->fd);
240         tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */
241         return n;
242 }
243
244
245
246 /* very ineficient for now, use hashtable some day - FIXME*/
247 void tcpconn_timeout(fd_set* set)
248 {
249         struct tcp_connection *c, *next;
250         int ticks;;
251         
252         
253         ticks=get_ticks();
254         c=*conn_list;
255         while(c){
256                 next=c->next;
257                 if ((c->refcnt==0) && (ticks>c->timeout)) {
258                         DBG("tcpconn_timeout: timeout for %p (%d > %d)\n",
259                                         c, ticks, c->timeout);
260                         if (c->s>0) {
261                                 FD_CLR(c->s, set);
262                                 close(c->s);
263                         }
264                         tcpconn_rm(c);
265                 }
266                 c=next;
267         }
268 }
269
270
271
272 int tcp_init_sock(struct socket_info* sock_info)
273 {
274         union sockaddr_union* addr;
275         
276         addr=&sock_info->su;
277         sock_info->proto=SOCKET_TCP;
278         if (init_su(addr, &sock_info->address, htons(sock_info->port_no))<0){
279                 LOG(L_ERR, "ERROR: tcp_init: could no init sockaddr_union\n");
280                 goto error;
281         }
282         sock_info->socket=socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
283         if (sock_info->socket==-1){
284                 LOG(L_ERR, "ERROR: tcp_init: socket: %s\n", strerror(errno));
285                 goto error;
286         }
287         if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
288                 LOG(L_ERR, "ERROR: tcp_init: bind(%x, %p, %d) on %s: %s\n",
289                                 sock_info->socket, &addr->s, 
290                                 sockaddru_len(*addr),
291                                 sock_info->address_str.s,
292                                 strerror(errno));
293                 goto error;
294         }
295         if (listen(sock_info->socket, 10)==-1){
296                 LOG(L_ERR, "ERROR: tcp_init: listen(%x, %p, %d) on %s: %s\n",
297                                 sock_info->socket, &addr->s, 
298                                 sockaddru_len(*addr),
299                                 sock_info->address_str.s,
300                                 strerror(errno));
301                 goto error;
302         }
303         
304         return 0;
305 error:
306         if (sock_info->socket!=-1){
307                 close(sock_info->socket);
308                 sock_info->socket=-1;
309         }
310         return -1;
311 }
312
313
314
315 static int send2child(struct tcp_connection* tcpconn)
316 {
317         int i;
318         int min_busy;
319         int idx;
320         
321         min_busy=tcp_children[0].busy;
322         idx=0;
323         for (i=0; i<tcp_children_no; i++){
324                 if (!tcp_children[i].busy){
325                         idx=i;
326                         min_busy=0;
327                         break;
328                         return 0;
329                 }else if (min_busy>tcp_children[i].busy){
330                         min_busy=tcp_children[i].busy;
331                         idx=i;
332                 }
333         }
334         
335         tcp_children[idx].busy++;
336         tcp_children[idx].n_reqs++;
337         tcpconn->refcnt++;
338         if (min_busy){
339                 LOG(L_WARN, "WARNING: send2child:no free tcp receiver, "
340                                 " connection passed to the least busy one (%d)\n",
341                                 min_busy);
342         }
343         DBG("send2child: to child %d, %ld\n", idx, (long)tcpconn);
344         send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
345                         tcpconn->s);
346         
347         return 0; /* just to fix a warning*/
348 }
349
350
351 void tcp_main_loop()
352 {
353         int r;
354         int n;
355         fd_set master_set;
356         fd_set sel_set;
357         int maxfd;
358         int new_sock;
359         union sockaddr_union su;
360         struct tcp_connection* tcpconn;
361         long response[2];
362         int cmd;
363         int bytes;
364         socklen_t su_len;
365         struct timeval timeout;
366
367         /*init */
368         maxfd=0;
369         FD_ZERO(&master_set);
370         /* set all the listen addresses */
371         for (r=0; r<sock_no; r++){
372                 if ((tcp_info[r].proto==SOCKET_TCP) &&(tcp_info[r].socket!=-1)){
373                         FD_SET(tcp_info[r].socket, &master_set);
374                         if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
375                 }
376         }
377         /* set all the unix sockets used for child comm */
378         for (r=0; r<process_no; r++){
379                 if (pt[r].unix_sock>=0){
380                         FD_SET(pt[r].unix_sock, &master_set);
381                         if (pt[r].unix_sock>maxfd) maxfd=pt[r].unix_sock;
382                 }
383         }
384         
385         
386         /* main loop*/
387         
388         while(1){
389                 sel_set=master_set;
390                 timeout.tv_sec=TCP_MAIN_SELECT_TIMEOUT;
391                 timeout.tv_usec=0;
392                 n=select(maxfd+1, &sel_set, 0 ,0 , &timeout);
393                 if (n<0){
394                         if (errno==EINTR) continue; /* just a signal */
395                         /* errors */
396                         LOG(L_ERR, "ERROR: tcp_main_loop: select:(%d) %s\n", errno,
397                                         strerror(errno));
398                         n=0;
399                 }
400                 
401                 for (r=0; r<sock_no && n; r++){
402                         if ((tcp_info[r].proto==SOCKET_TCP) &&
403                                         (FD_ISSET(tcp_info[r].socket, &sel_set))){
404                                 /* got a connection on r */
405                                 su_len=sizeof(su);
406                                 new_sock=accept(tcp_info[r].socket, &(su.s), &su_len);
407                                 n--;
408                                 if (new_sock<0){
409                                         LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
410                                                         " connection(%d): %s\n", errno, strerror(errno));
411                                         continue;
412                                 }
413                                 
414                                 /* add socket to list */
415                                 tcpconn=tcpconn_new(new_sock, &su, r);
416                                 if (tcpconn){
417                                         tcpconn_add(tcpconn);
418                                         DBG("tcp_main_loop: new connection: %p %d\n",
419                                                 tcpconn, tcpconn->s);
420                                         /* pass it to a child */
421                                         if(send2child(tcpconn)<0){
422                                                 LOG(L_ERR,"ERROR: tcp_main_loop: no children "
423                                                                 "available\n");
424                                                 close(tcpconn->s);
425                                                 tcpconn_rm(tcpconn);
426                                         }
427                                 }
428                         }
429                 }
430                 
431                 /* check all the read fds (from the tcpconn list) */
432                 
433                 for(tcpconn=*conn_list; tcpconn && n; tcpconn=tcpconn->next){
434                         if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
435                                 /* new data available */
436                                 n--;
437                                 /* pass it to child, so remove it from select list */
438                                 DBG("tcp_main_loop: data available on %p %d\n",
439                                                 tcpconn, tcpconn->s);
440                                 FD_CLR(tcpconn->s, &master_set);
441                                 if (send2child(tcpconn)<0){
442                                         LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
443                                         close(tcpconn->s);
444                                         tcpconn_rm(tcpconn);
445                                 }
446                         }
447                 }
448                 
449                 /* check unix sockets & listen | destroy connections */
450                 /* start from 1, the "main" process does not transmit anything*/
451                 for (r=1; r<process_no && n; r++){
452                         if ( (pt[r].unix_sock>=0) && FD_ISSET(pt[r].unix_sock, &sel_set)){
453                                 n--;
454                                 /* errno==EINTR !!! TODO*/
455 read_again:
456                                 bytes=read(pt[r].unix_sock, response, sizeof(response));
457                                 if (bytes==0){
458                                         /* EOF -> bad, child has died */
459                                         LOG(L_CRIT, "BUG: tcp_main_loop: dead child %d\n", r);
460                                         /* don't listen on it any more */
461                                         FD_CLR(pt[r].unix_sock, &master_set);
462                                         /*exit(-1)*/;
463                                 }else if (bytes<0){
464                                         if (errno==EINTR) goto read_again;
465                                         else{
466                                                 LOG(L_CRIT, "ERROR: tcp_main_loop: read from child: "
467                                                                 " %s\n", strerror(errno));
468                                                 /* try to continue ? */
469                                         }
470                                 }
471                                         
472                                 DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n",
473                                                 response[0], response[1], r, pt[r].pid);
474                                 cmd=response[1];
475                                 switch(cmd){
476                                         case CONN_RELEASE:
477                                                 if (pt[r].idx>=0){
478                                                         tcp_children[pt[r].idx].busy--;
479                                                 }else{
480                                                         LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
481                                                 }
482                                                 tcpconn=(struct tcp_connection*)response[0];
483                                                 if (tcpconn){
484                                                         tcpconn->refcnt--;
485                                                         DBG("tcp_main_loop: %p refcnt= %d\n", 
486                                                                         tcpconn, tcpconn->refcnt);
487                                                                 FD_SET(tcpconn->s, &master_set);
488                                                                 if (maxfd<tcpconn->s) maxfd=tcpconn->s;
489                                                                 /* update the timeout*/
490                                                                 tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
491                                                 }
492                                                 break;
493                                         case CONN_ERROR:
494                                         case CONN_DESTROY:
495                                         case CONN_EOF:
496                                                 if (pt[r].idx>=0){
497                                                         tcp_children[pt[r].idx].busy--;
498                                                 }else{
499                                                         LOG(L_CRIT, "BUG: tcp_main_loop: CONN_RELEASE\n");
500                                                 }
501                                                 tcpconn=(struct tcp_connection*)response[0];
502                                                 if (tcpconn){
503                                                         tcpconn->refcnt--;
504                                                         if (tcpconn->refcnt==0){
505                                                                 DBG("tcp_main_loop: destroying connection\n");
506                                                                 close(tcpconn->s);
507                                                                 tcpconn_rm(tcpconn);
508                                                         }else{
509                                                                 DBG("tcp_main_loop: delaying ...\n");
510                                                         }
511                                                 }
512                                                 break;
513                                         case CONN_GET_FD:
514                                                 /* send the requested FD  */
515                                                 tcpconn=(struct tcp_connection*)response[0];
516                                                 /* WARNING: take care of setting refcnt properly to
517                                                  * avoid race condition */
518                                                 if (tcpconn){
519                                                         send_fd(pt[r].unix_sock, &tcpconn,
520                                                                         sizeof(tcpconn), tcpconn->s);
521                                                 }else{
522                                                         LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
523                                                 }
524                                                 break;
525                                         case CONN_NEW:
526                                                 /* update the fd in the requested tcpconn*/
527                                                 tcpconn=(struct tcp_connection*)response[0];
528                                                 /* WARNING: take care of setting refcnt properly to
529                                                  * avoid race condition */
530                                                 if (tcpconn){
531                                                         receive_fd(pt[r].unix_sock, &tcpconn,
532                                                                                 sizeof(tcpconn), &tcpconn->s);
533                                                         /* add tcpconn to the list*/
534                                                         tcpconn_add(tcpconn);
535                                                         FD_SET(tcpconn->s, &master_set);
536                                                         if (maxfd<tcpconn->s) maxfd=tcpconn->s;
537                                                         /* update the timeout*/
538                                                         tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
539                                                 }else{
540                                                         LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n");
541                                                 }
542                                                 break;
543                                         default:
544                                                         LOG(L_CRIT, "BUG: tcp_main_loop: unknown cmd %d\n",
545                                                                         cmd);
546                                 }
547                         }
548                 }
549                 
550                 /* remove old connections */
551                 tcpconn_timeout(&master_set);
552         
553         }
554 }
555
556
557
558 int init_tcp()
559 {
560         /* allocate list head*/
561         conn_list=shm_malloc(sizeof(struct tcp_connection*));
562         if (conn_list==0){
563                 LOG(L_CRIT, "ERROR: tcp_init: memory allocation failure\n");
564                 goto error;
565         }
566         *conn_list=0;
567         return 0;
568 error:
569                 return -1;
570 }
571
572
573
574 /* starts the tcp processes */
575 int tcp_init_children()
576 {
577         int r;
578         int sockfd[2];
579         pid_t pid;
580         
581         
582         /* create the tcp sock_info structures */
583         /* copy the sockets*/
584         for (r=0; r<sock_no ; r++){
585                 tcp_info[r]=sock_info[r];
586                 tcp_init_sock(&tcp_info[r]);
587         }
588         
589         /* fork children & create the socket pairs*/
590         for(r=0; r<tcp_children_no; r++){
591                 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)<0){
592                         LOG(L_ERR, "ERROR: tcp_main: socketpair failed: %s\n",
593                                         strerror(errno));
594                         goto error;
595                 }
596                 
597                 process_no++;
598                 pid=fork();
599                 if (pid<0){
600                         LOG(L_ERR, "ERROR: tcp_main: fork failed: %s\n",
601                                         strerror(errno));
602                         goto error;
603                 }else if (pid>0){
604                         /* parent */
605                         close(sockfd[1]);
606                         tcp_children[r].pid=pid;
607                         tcp_children[r].busy=0;
608                         tcp_children[r].n_reqs=0;
609                         tcp_children[r].unix_sock=sockfd[0];
610                         pt[process_no].pid=pid;
611                         pt[process_no].unix_sock=sockfd[0];
612                         pt[process_no].idx=r;
613                         strncpy(pt[process_no].desc, "tcp receiver", MAX_PT_DESC);
614                 }else{
615                         /* child */
616                         close(sockfd[0]);
617                         unix_tcp_sock=sockfd[1];
618                         tcp_receive_loop(sockfd[1]);
619                 }
620         }
621         return 0;
622 error:
623         return -1;
624 }
625
626 #endif