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