]> arthur.barton.de Git - netatalk.git/blob - libatalk/asp/asp_getsess.c
Primary reconnect
[netatalk.git] / libatalk / asp / asp_getsess.c
1 /*
2  * $Id: asp_getsess.c,v 1.9 2009-10-13 22:55:37 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 #ifndef MIN
48 #define MIN(a,b)     ((a)<(b)?(a):(b))
49 #endif /* ! MIN */
50
51 static ASP server_asp;
52 static struct server_child *children = NULL;
53 static struct asp_child    **asp_ac = NULL;
54
55 /* send tickles and check tickle status of connections
56  * thoughts on using a hashed list:
57  * + child_cleanup, finding slots 
58  * - tickle_handler, freeing, tickles 
59  * if setup for a large number of connections,
60  * + space: if actual connections < potential
61  * - space: actual connections ~ potential
62  */
63 static void tickle_handler(int sig _U_)
64 {
65   int sid;
66   
67   /* check status */
68   for (sid = 0; sid < children->nsessions; sid++) {
69     if (asp_ac[sid] == NULL || asp_ac[sid]->ac_state == ACSTATE_DEAD) 
70       continue;
71     
72     if (++asp_ac[sid]->ac_state >= ACSTATE_BAD) {
73       /* kill. if already dead, just continue */
74       if (kill( asp_ac[ sid ]->ac_pid, SIGTERM) == 0)
75         LOG(log_info, logtype_default, "asp_alrm: %d timed out",
76                 asp_ac[ sid ]->ac_pid );
77
78       asp_ac[ sid ]->ac_state = ACSTATE_DEAD;
79       continue;
80     }
81
82     /* send off a tickle */
83     asp_tickle(server_asp, sid, &asp_ac[sid]->ac_sat);
84   }
85 }
86
87 static void child_cleanup(const pid_t pid)
88 {
89   int i;
90
91   for (i = 0; i < children->nsessions; i++)
92     if (asp_ac[i] && (asp_ac[i]->ac_pid == pid)) {
93       asp_ac[i]->ac_state = ACSTATE_DEAD;
94       break;
95     }
96 }
97
98
99 /* kill children */
100 void asp_kill(int sig)
101 {
102   if (children) 
103     server_child_kill(children, CHILD_ASPFORK, sig);
104 }
105
106 void asp_stop_tickle(void)
107 {
108     if (server_asp && server_asp->inited) {
109         static const struct itimerval timer = {{0, 0}, {0, 0}};
110         
111         setitimer(ITIMER_REAL, &timer, NULL);
112     }
113 }
114
115 /*
116  * This call handles open, tickle, and getstatus requests. On a
117  * successful open, it forks a child process. 
118  * It returns an ASP to the child and parent and NULL if there is
119  * an error.
120  */
121 static void set_asp_ac(int sid, struct asp_child *tmp);
122
123 ASP asp_getsession(ASP asp, server_child *server_children, 
124                    const int tickleval)
125 {
126     struct sigaction    action;
127     struct itimerval    timer;
128     struct sockaddr_at  sat;
129     struct atp_block    atpb;
130     ATP                 atp;
131     struct iovec        iov[ 8 ];
132     pid_t               pid;
133     int                 i, iovcnt, sid;
134     u_int16_t           asperr;
135     char                *buf;
136     int                 buflen;
137
138     if (!asp->inited) {
139       if (!(children = server_children))
140         return NULL;
141
142       /* only calloc once */
143       if (!asp_ac && (asp_ac = (struct asp_child **) 
144            calloc(server_children->nsessions, sizeof(struct asp_child *)))
145            == NULL)
146         return NULL;
147
148       server_asp = asp;
149
150       /* install cleanup pointer */
151       server_child_setup(children, CHILD_ASPFORK, child_cleanup);
152
153       /* install tickle handler 
154        * we are the parent process
155        */
156       memset(&action, 0, sizeof(action));
157       action.sa_handler = tickle_handler;
158       sigemptyset(&action.sa_mask);
159       sigaddset(&action.sa_mask, SIGHUP);
160       sigaddset(&action.sa_mask, SIGTERM);
161       sigaddset(&action.sa_mask, SIGCHLD);
162       action.sa_flags = SA_RESTART;
163
164       timer.it_interval.tv_sec = timer.it_value.tv_sec = tickleval;
165       timer.it_interval.tv_usec = timer.it_value.tv_usec = 0;
166       if ((sigaction(SIGALRM, &action, NULL) < 0) ||
167           (setitimer(ITIMER_REAL, &timer, NULL) < 0)) {
168         free(asp_ac);
169         server_asp = NULL;
170         asp_ac = NULL;
171         return NULL;
172       }
173
174       asp->inited = 1;
175     }
176                     
177     memset( &sat, 0, sizeof( struct sockaddr_at ));
178 #ifdef BSD4_4
179     sat.sat_len = sizeof( struct sockaddr_at );
180 #endif /* BSD4_4 */
181     sat.sat_family = AF_APPLETALK;
182     sat.sat_addr.s_net = ATADDR_ANYNET;
183     sat.sat_addr.s_node = ATADDR_ANYNODE;
184     sat.sat_port = ATADDR_ANYPORT;
185     atpb.atp_saddr = &sat;
186     atpb.atp_rreqdata = asp->cmdbuf;
187     atpb.atp_rreqdlen = sizeof( asp->cmdbuf );
188     while ( atp_rreq( asp->asp_atp, &atpb ) < 0 ) {
189       if ( errno == EINTR || errno == EAGAIN ) {
190         continue;
191       }
192       return( NULL );
193     }
194     
195     switch ( asp->cmdbuf[ 0 ] ) {
196     case ASPFUNC_TICKLE:
197       sid = asp->cmdbuf[1];
198       if ((asp_ac[sid] != NULL) && (asp_ac[sid]->ac_state != ACSTATE_DEAD))
199         asp_ac[sid]->ac_state = ACSTATE_OK;
200       break;
201
202     case ASPFUNC_STAT :
203 #ifdef EBUG
204       printf( "asp stat\n" );
205 #endif /* EBUG */
206       if ( asp->asp_slen > 0 ) {
207         i = 0;
208         while(atpb.atp_bitmap) {
209             i++;
210             atpb.atp_bitmap >>= 1;
211         }
212
213         /* asp->data is big enough ... */
214         memcpy( asp->data, asp->asp_status, MIN(asp->asp_slen, i*ASP_CMDSIZ));
215         
216         buflen = MIN(asp->asp_slen, i*ASP_CMDSIZ);
217         buf = asp->data;
218         iovcnt = 0;
219
220         /* If status information is too big to fit into the available
221          * ASP packets, we simply send as much as we can.
222          * Older client versions will most likely not be able to use
223          * the additional information anyway, like directory services
224          * or UTF8 server name. A very long fqdn could be a problem,
225          * we could end up with an invalid address list.
226          */
227         do {
228             iov[ iovcnt ].iov_base = buf;
229             memmove(buf + ASP_HDRSIZ, buf, buflen);
230             memset( iov[ iovcnt ].iov_base, 0, ASP_HDRSIZ );
231
232            if ( buflen > ASP_CMDSIZ ) {
233                 buf += ASP_CMDMAXSIZ;
234                 buflen -= ASP_CMDSIZ;
235                 iov[ iovcnt ].iov_len = ASP_CMDMAXSIZ;
236             } else {
237                 iov[ iovcnt ].iov_len = buflen + ASP_HDRSIZ;
238                 buflen = 0;
239             }
240             iovcnt++;
241         } while ( iovcnt < i && buflen > 0 );
242
243         atpb.atp_sresiovcnt = iovcnt;
244         atpb.atp_sresiov = iov;
245         atp_sresp( asp->asp_atp, &atpb );
246       }
247       break;
248
249     case ASPFUNC_OPEN :
250       if (children->count < children->nsessions) {
251       struct asp_child    *asp_ac_tmp;
252
253         /* find a slot */
254         for (sid = 0; sid < children->nsessions; sid++) {
255           if (asp_ac[sid] == NULL)
256             break;
257
258           if (asp_ac[sid]->ac_state == ACSTATE_DEAD) {
259             free(asp_ac[sid]);
260             asp_ac[sid] = NULL;
261             break;
262           }
263         }
264
265         if ((atp = atp_open(ATADDR_ANYPORT, 
266                             &(atp_sockaddr(asp->asp_atp)->sat_addr))) == NULL) 
267           return NULL;
268
269     int dummy[2];
270         switch ((pid = fork())) {
271         case 0 : /* child */
272           server_reset_signal();
273           /* free/close some things */
274           for (i = 0; i < children->nsessions; i++ ) {
275             if ( asp_ac[i] != NULL )
276               free( asp_ac[i] );
277           }
278           free(asp_ac);
279           
280           server_child_free(children);
281           children = NULL;
282           atp_close(asp->asp_atp);
283
284           asp->child = 1;
285           asp->asp_atp = atp;
286           asp->asp_sat = sat;
287           asp->asp_wss = asp->cmdbuf[1];
288           asp->asp_seq = 0;
289           asp->asp_sid = sid;
290           asp->asp_flags = ASPFL_SSS;
291           return asp;
292           
293         case -1 : /* error */
294           asp->cmdbuf[ 0 ] = 0;
295           asp->cmdbuf[ 1 ] = 0;
296           asperr = ASPERR_SERVBUSY;
297           break;
298           
299         default : /* parent process */
300           /* we need atomic setting or pb with tickle_handler */ 
301       if (server_child_add(children, CHILD_ASPFORK, pid, dummy)) {
302             if ((asp_ac_tmp = malloc(sizeof(struct asp_child))) == NULL) {
303             kill(pid, SIGQUIT); 
304             break;
305         }
306         asp_ac_tmp->ac_pid = pid;
307         asp_ac_tmp->ac_state = ACSTATE_OK;
308         asp_ac_tmp->ac_sat = sat;
309         asp_ac_tmp->ac_sat.sat_port = asp->cmdbuf[1];
310             
311         asp->cmdbuf[0] = atp_sockaddr(atp)->sat_port;
312         asp->cmdbuf[1] = sid;
313         set_asp_ac(sid, asp_ac_tmp);
314         asperr = ASPERR_OK;
315         break;
316       } else {
317             kill(pid, SIGQUIT); 
318             break;
319       }
320           atp_close(atp);
321           break;
322         }
323         
324       } else {
325         asp->cmdbuf[0] = asp->cmdbuf[1] = 0;
326         asperr = ASPERR_SERVBUSY;
327       }
328
329       memcpy( asp->cmdbuf + 2, &asperr, sizeof(asperr));
330       iov[ 0 ].iov_base = asp->cmdbuf;
331       iov[ 0 ].iov_len = 4;
332       atpb.atp_sresiov = iov;
333       atpb.atp_sresiovcnt = 1;
334       atp_sresp( asp->asp_atp, &atpb );
335       break;
336
337     default:
338       LOG(log_info, logtype_default, "ASPUnknown %d", asp->cmdbuf[0]);
339       break;
340     }
341
342     return asp;
343 }
344
345 /* with fn defined after use, assume it's not optimized by the compiler */
346 static void set_asp_ac(int sid, struct asp_child *tmp)
347 {
348     asp_ac[sid] = tmp;
349 }