• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.5/libatalk/asp/
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
51static ASP server_asp;
52static struct server_child *children = NULL;
53static 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 */
63static 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
87static 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 */
100void asp_kill(int sig)
101{
102  if (children)
103    server_child_kill(children, CHILD_ASPFORK, sig);
104}
105
106void 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 */
121static void set_asp_ac(int sid, struct asp_child *tmp);
122
123ASP 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 */
346static void set_asp_ac(int sid, struct asp_child *tmp)
347{
348    asp_ac[sid] = tmp;
349}
350