2 * $Id: asp_getsess.c,v 1.9 2009-10-13 22:55:37 didg Exp $
4 * Copyright (c) 1990,1996 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
20 #endif /* HAVE_UNISTD_H */
22 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/param.h>
27 #ifdef HAVE_SYS_WAIT_H
29 #endif /* HAVE_SYS_WAIT_H */
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>
38 #include "asp_child.h"
41 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
42 #endif /* ! WEXITSTATUS */
44 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
45 #endif /* ! WIFEXITED */
48 #define MIN(a,b) ((a)<(b)?(a):(b))
51 static ASP server_asp;
52 static struct server_child *children = NULL;
53 static struct asp_child **asp_ac = NULL;
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
63 static void tickle_handler(int sig _U_)
68 for (sid = 0; sid < children->nsessions; sid++) {
69 if (asp_ac[sid] == NULL || asp_ac[sid]->ac_state == ACSTATE_DEAD)
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 );
78 asp_ac[ sid ]->ac_state = ACSTATE_DEAD;
82 /* send off a tickle */
83 asp_tickle(server_asp, sid, &asp_ac[sid]->ac_sat);
87 static void child_cleanup(const pid_t pid)
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;
100 void asp_kill(int sig)
103 server_child_kill(children, CHILD_ASPFORK, sig);
106 void asp_stop_tickle(void)
108 if (server_asp && server_asp->inited) {
109 static const struct itimerval timer = {{0, 0}, {0, 0}};
111 setitimer(ITIMER_REAL, &timer, NULL);
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
121 static void set_asp_ac(int sid, struct asp_child *tmp);
123 ASP asp_getsession(ASP asp, server_child *server_children,
126 struct sigaction action;
127 struct itimerval timer;
128 struct sockaddr_at sat;
129 struct atp_block atpb;
131 struct iovec iov[ 8 ];
139 if (!(children = server_children))
142 /* only calloc once */
143 if (!asp_ac && (asp_ac = (struct asp_child **)
144 calloc(server_children->nsessions, sizeof(struct asp_child *)))
150 /* install cleanup pointer */
151 server_child_setup(children, CHILD_ASPFORK, child_cleanup);
153 /* install tickle handler
154 * we are the parent process
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;
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)) {
177 memset( &sat, 0, sizeof( struct sockaddr_at ));
179 sat.sat_len = sizeof( struct sockaddr_at );
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 ) {
195 switch ( asp->cmdbuf[ 0 ] ) {
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;
204 printf( "asp stat\n" );
206 if ( asp->asp_slen > 0 ) {
208 while(atpb.atp_bitmap) {
210 atpb.atp_bitmap >>= 1;
213 /* asp->data is big enough ... */
214 memcpy( asp->data, asp->asp_status, MIN(asp->asp_slen, i*ASP_CMDSIZ));
216 buflen = MIN(asp->asp_slen, i*ASP_CMDSIZ);
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.
228 iov[ iovcnt ].iov_base = buf;
229 memmove(buf + ASP_HDRSIZ, buf, buflen);
230 memset( iov[ iovcnt ].iov_base, 0, ASP_HDRSIZ );
232 if ( buflen > ASP_CMDSIZ ) {
233 buf += ASP_CMDMAXSIZ;
234 buflen -= ASP_CMDSIZ;
235 iov[ iovcnt ].iov_len = ASP_CMDMAXSIZ;
237 iov[ iovcnt ].iov_len = buflen + ASP_HDRSIZ;
241 } while ( iovcnt < i && buflen > 0 );
243 atpb.atp_sresiovcnt = iovcnt;
244 atpb.atp_sresiov = iov;
245 atp_sresp( asp->asp_atp, &atpb );
250 if (children->count < children->nsessions) {
251 struct asp_child *asp_ac_tmp;
254 for (sid = 0; sid < children->nsessions; sid++) {
255 if (asp_ac[sid] == NULL)
258 if (asp_ac[sid]->ac_state == ACSTATE_DEAD) {
265 if ((atp = atp_open(ATADDR_ANYPORT,
266 &(atp_sockaddr(asp->asp_atp)->sat_addr))) == NULL)
270 switch ((pid = fork())) {
272 server_reset_signal();
273 /* free/close some things */
274 for (i = 0; i < children->nsessions; i++ ) {
275 if ( asp_ac[i] != NULL )
280 server_child_free(children);
282 atp_close(asp->asp_atp);
287 asp->asp_wss = asp->cmdbuf[1];
290 asp->asp_flags = ASPFL_SSS;
293 case -1 : /* error */
294 asp->cmdbuf[ 0 ] = 0;
295 asp->cmdbuf[ 1 ] = 0;
296 asperr = ASPERR_SERVBUSY;
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) {
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];
311 asp->cmdbuf[0] = atp_sockaddr(atp)->sat_port;
312 asp->cmdbuf[1] = sid;
313 set_asp_ac(sid, asp_ac_tmp);
325 asp->cmdbuf[0] = asp->cmdbuf[1] = 0;
326 asperr = ASPERR_SERVBUSY;
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 );
338 LOG(log_info, logtype_default, "ASPUnknown %d", asp->cmdbuf[0]);
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)