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