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