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