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