]> arthur.barton.de Git - netatalk.git/blob - libatalk/asp/asp_getsess.c
unblock signals in children (cf previous commit for RH9 )
[netatalk.git] / libatalk / asp / asp_getsess.c
1 /*
2  * $Id: asp_getsess.c,v 1.7.8.2 2003-11-13 15:39:02 didg Exp $
3  *
4  * Copyright (c) 1990,1996 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <signal.h>
17
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif /* HAVE_UNISTD_H */
21
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/uio.h>
25 #include <sys/socket.h>
26 #include <sys/param.h>
27 #ifdef HAVE_SYS_WAIT_H
28 #include <sys/wait.h>
29 #endif /* HAVE_SYS_WAIT_H */
30
31 #include <netatalk/at.h>
32 #include <atalk/logger.h>
33 #include <atalk/compat.h>
34 #include <atalk/atp.h>
35 #include <atalk/asp.h>
36 #include <atalk/server_child.h>
37
38 #include "asp_child.h"
39
40 #ifndef WEXITSTATUS
41 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
42 #endif /* ! WEXITSTATUS */
43 #ifndef WIFEXITED
44 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
45 #endif /* ! WIFEXITED */
46
47 static ASP server_asp;
48 static struct server_child *children = NULL;
49 static struct asp_child    **asp_ac = NULL;
50
51 /* send tickles and check tickle status of connections
52  * thoughts on using a hashed list:
53  * + child_cleanup, finding slots 
54  * - tickle_handler, freeing, tickles 
55  * if setup for a large number of connections,
56  * + space: if actual connections < potential
57  * - space: actual connections ~ potential
58  */
59 static void tickle_handler()
60 {
61   int sid;
62   
63   /* check status */
64   for (sid = 0; sid < children->nsessions; sid++) {
65     if (asp_ac[sid] == NULL || asp_ac[sid]->ac_state == ACSTATE_DEAD) 
66       continue;
67     
68     if (++asp_ac[sid]->ac_state >= ACSTATE_BAD) {
69       /* kill. if already dead, just continue */
70       if (kill( asp_ac[ sid ]->ac_pid, SIGTERM) == 0)
71         LOG(log_info, logtype_default, "asp_alrm: %d timed out",
72                 asp_ac[ sid ]->ac_pid );
73
74       asp_ac[ sid ]->ac_state = ACSTATE_DEAD;
75       continue;
76     }
77
78     /* send off a tickle */
79     asp_tickle(server_asp, sid, &asp_ac[sid]->ac_sat);
80   }
81 }
82
83 static void child_cleanup(const pid_t pid)
84 {
85   int i;
86
87   for (i = 0; i < children->nsessions; i++)
88     if (asp_ac[i] && (asp_ac[i]->ac_pid == pid)) {
89       asp_ac[i]->ac_state = ACSTATE_DEAD;
90       break;
91     }
92 }
93
94
95 /* kill children */
96 void asp_kill(int sig)
97 {
98   if (children) 
99     server_child_kill(children, CHILD_ASPFORK, sig);
100 }
101
102
103 /*
104  * This call handles open, tickle, and getstatus requests. On a
105  * successful open, it forks a child process. 
106  * It returns an ASP to the child and parent and NULL if there is
107  * an error.
108  */
109 static void set_asp_ac(int sid, struct asp_child *tmp);
110
111 ASP asp_getsession(ASP asp, server_child *server_children, 
112                    const int tickleval)
113 {
114     struct sigaction action;
115     struct itimerval timer;
116     struct sockaddr_at  sat;
117     struct atp_block    atpb;
118     ATP                 atp;
119     struct iovec        iov[ 8 ];
120     pid_t               pid;
121     int                 i, sid;
122     u_int16_t           asperr;
123
124     if (!asp->inited) {
125       if (!(children = server_children))
126         return NULL;
127
128       if ((asp_ac = (struct asp_child **) 
129            calloc(server_children->nsessions, sizeof(struct asp_child *)))
130            == NULL)
131         return NULL;
132
133       server_asp = asp;
134
135       /* install cleanup pointer */
136       server_child_setup(children, CHILD_ASPFORK, child_cleanup);
137
138       /* install tickle handler 
139        * we are the parent process
140        */
141       memset(&action, 0, sizeof(action));
142       action.sa_handler = tickle_handler;
143       sigemptyset(&action.sa_mask);
144       sigaddset(&action.sa_mask, SIGHUP);
145       sigaddset(&action.sa_mask, SIGTERM);
146       sigaddset(&action.sa_mask, SIGCHLD);
147       action.sa_flags = SA_RESTART;
148
149       timer.it_interval.tv_sec = timer.it_value.tv_sec = tickleval;
150       timer.it_interval.tv_usec = timer.it_value.tv_usec = 0;
151       if ((sigaction(SIGALRM, &action, NULL) < 0) ||
152           (setitimer(ITIMER_REAL, &timer, NULL) < 0)) {
153         free(asp_ac);
154         return NULL;
155       }
156
157       asp->inited = 1;
158     }
159                     
160     memset( &sat, 0, sizeof( struct sockaddr_at ));
161 #ifdef BSD4_4
162     sat.sat_len = sizeof( struct sockaddr_at );
163 #endif /* BSD4_4 */
164     sat.sat_family = AF_APPLETALK;
165     sat.sat_addr.s_net = ATADDR_ANYNET;
166     sat.sat_addr.s_node = ATADDR_ANYNODE;
167     sat.sat_port = ATADDR_ANYPORT;
168     atpb.atp_saddr = &sat;
169     atpb.atp_rreqdata = asp->cmdbuf;
170     atpb.atp_rreqdlen = sizeof( asp->cmdbuf );
171     while ( atp_rreq( asp->asp_atp, &atpb ) < 0 ) {
172       if ( errno == EINTR || errno == EAGAIN ) {
173         continue;
174       }
175       return( NULL );
176     }
177     
178     switch ( asp->cmdbuf[ 0 ] ) {
179     case ASPFUNC_TICKLE:
180       sid = asp->cmdbuf[1];
181       if ((asp_ac[sid] != NULL) && (asp_ac[sid]->ac_state != ACSTATE_DEAD))
182         asp_ac[sid]->ac_state = ACSTATE_OK;
183       break;
184
185     case ASPFUNC_STAT :
186 #ifdef EBUG
187       printf( "asp stat\n" );
188 #endif /* EBUG */
189       if ( asp->asp_slen > 0 ) {
190         asp->cmdbuf[0] = 0;
191         memcpy( asp->cmdbuf + 4, asp->asp_status, asp->asp_slen );
192         iov[ 0 ].iov_base = asp->cmdbuf;
193         iov[ 0 ].iov_len = 4 + asp->asp_slen;
194         atpb.atp_sresiov = iov;
195         atpb.atp_sresiovcnt = 1;
196         atp_sresp( asp->asp_atp, &atpb );
197       }
198       break;
199
200     case ASPFUNC_OPEN :
201       if (children->count < children->nsessions) {
202       struct asp_child    *asp_ac_tmp;
203
204         /* find a slot */
205         for (sid = 0; sid < children->nsessions; sid++) {
206           if (asp_ac[sid] == NULL)
207             break;
208
209           if (asp_ac[sid]->ac_state == ACSTATE_DEAD) {
210             free(asp_ac[sid]);
211             asp_ac[sid] = NULL;
212             break;
213           }
214         }
215
216         if ((atp = atp_open(ATADDR_ANYPORT, 
217                             &(atp_sockaddr(asp->asp_atp)->sat_addr))) == NULL) 
218           return NULL;
219
220         switch ((pid = fork())) {
221         case 0 : /* child */
222           server_reset_signal();
223           /* free/close some things */
224           for (i = 0; i < children->nsessions; i++ ) {
225             if ( asp_ac[i] != NULL )
226               free( asp_ac[i] );
227           }
228           free(asp_ac);
229           
230           server_child_free(children);
231           children = NULL;
232           atp_close(asp->asp_atp);
233
234           asp->child = 1;
235           asp->asp_atp = atp;
236           asp->asp_sat = sat;
237           asp->asp_wss = asp->cmdbuf[1];
238           asp->asp_seq = 0;
239           asp->asp_sid = sid;
240           asp->asp_flags = ASPFL_SSS;
241           return asp;
242           
243         case -1 : /* error */
244           asp->cmdbuf[ 0 ] = 0;
245           asp->cmdbuf[ 1 ] = 0;
246           asperr = ASPERR_SERVBUSY;
247           break;
248           
249         default : /* parent process */
250           /* we need atomic setting or pb with tickle_handler 
251           */ 
252           switch (server_child_add(children, CHILD_ASPFORK, pid)) {
253           case 0: /* added child */
254             if ((asp_ac_tmp = (struct asp_child *) 
255                  malloc(sizeof(struct asp_child)))) {
256               asp_ac_tmp->ac_pid = pid;
257               asp_ac_tmp->ac_state = ACSTATE_OK;
258               asp_ac_tmp->ac_sat = sat;
259               asp_ac_tmp->ac_sat.sat_port = asp->cmdbuf[1];
260               
261               asp->cmdbuf[0] = atp_sockaddr(atp)->sat_port;
262               asp->cmdbuf[1] = sid;
263               set_asp_ac(sid, asp_ac_tmp);
264               asperr = ASPERR_OK;
265               break;
266             } /* fall through if malloc fails */
267           case -1: /* bad error */
268             kill(pid, SIGQUIT); 
269             break;
270           default: /* non-fatal error */
271             break;
272           }
273           atp_close(atp);
274           break;
275         }
276         
277       } else {
278         asp->cmdbuf[0] = asp->cmdbuf[1] = 0;
279         asperr = ASPERR_SERVBUSY;
280       }
281
282       memcpy( asp->cmdbuf + 2, &asperr, sizeof(asperr));
283       iov[ 0 ].iov_base = asp->cmdbuf;
284       iov[ 0 ].iov_len = 4;
285       atpb.atp_sresiov = iov;
286       atpb.atp_sresiovcnt = 1;
287       atp_sresp( asp->asp_atp, &atpb );
288       break;
289
290     default:
291       LOG(log_info, logtype_default, "ASPUnknown %d", asp->cmdbuf[0]);
292       break;
293     }
294
295     return asp;
296 }
297
298 /* with fn defined after use, assume it's not optimized by the compiler */
299 static void set_asp_ac(int sid, struct asp_child *tmp)
300 {
301     asp_ac[sid] = tmp;
302 }