]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/afp_dsi.c
3a68866fd0626c7741bc0341c100ca40566880c2
[netatalk.git] / etc / afpd / afp_dsi.c
1 /* 
2  * $Id: afp_dsi.c,v 1.8 2001-06-20 18:33:04 rufustfirefly Exp $
3  *
4  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
5  * Copyright (c) 1990,1993 Regents of The University of Michigan.
6  * All Rights Reserved.  See COPYRIGHT.
7  *
8  * modified from main.c. this handles afp over tcp.
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif /* HAVE_CONFIG_H */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <signal.h>
18 #include <string.h>
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif /* HAVE_UNISTD_H */
22 #include <sys/socket.h>
23 #include <sys/time.h>
24 #ifdef HAVE_SYS_STAT_H
25 #include <sys/stat.h>
26 #endif /* HAVE_SYS_STAT_H */
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <syslog.h>
30
31 #include <atalk/dsi.h>
32 #include <atalk/compat.h>
33 #include <atalk/util.h>
34
35 #include "globals.h"
36 #include "switch.h"
37 #include "auth.h"
38 #include "fork.h"
39
40 extern struct oforks    *writtenfork;
41
42 #define CHILD_DIE         (1 << 0)
43 #define CHILD_RUNNING     (1 << 1)
44
45 static struct {
46   AFPObj *obj;
47   unsigned char tickle, flags;
48 } child;
49
50
51 static __inline__ void afp_dsi_close(AFPObj *obj)
52 {
53     DSI *dsi = obj->handle;
54
55     if (obj->logout)
56       (*obj->logout)();
57                       
58     dsi_close(dsi);
59
60     /* UAM had syslog control; afpd needs to reassert itself */
61     openlog( "afpd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
62     syslog(LOG_INFO, "%.2fKB read, %.2fKB written",
63            dsi->read_count/1024.0, dsi->write_count/1024.0);
64 }
65
66 /* a little bit of code duplication. */
67 static void afp_dsi_die(int sig)
68 {
69     dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN);
70     afp_dsi_close(child.obj);
71     if (sig) /* if no signal, assume dieing because logins are disabled &
72         don't log it (maintenance mode)*/
73       syslog (LOG_INFO, "Connection terminated");
74     if (sig == SIGTERM || sig == SIGALRM) {
75       exit( 0 );
76     }
77     else {
78       exit(sig);
79     }
80 }
81
82 static void afp_dsi_timedown()
83 {
84     struct sigaction    sv;
85     struct itimerval    it;
86
87     child.flags |= CHILD_DIE;
88     /* shutdown and don't reconnect. server going down in 5 minutes. */
89     setmessage("The server is going down for maintenance.");
90     dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
91                   AFPATTN_MESG | AFPATTN_TIME(5));
92
93     it.it_interval.tv_sec = 0;
94     it.it_interval.tv_usec = 0;
95     it.it_value.tv_sec = 300;
96     it.it_value.tv_usec = 0;
97     if ( setitimer( ITIMER_REAL, &it, 0 ) < 0 ) {
98         syslog( LOG_ERR, "afp_timedown: setitimer: %m" );
99         afp_dsi_die(1);
100     }
101
102     memset(&sv, 0, sizeof(sv));
103     sv.sa_handler = afp_dsi_die;
104     sigemptyset( &sv.sa_mask );
105     sigaddset(&sv.sa_mask, SIGHUP);
106     sigaddset(&sv.sa_mask, SIGTERM);
107     sv.sa_flags = SA_RESTART;
108     if ( sigaction( SIGALRM, &sv, 0 ) < 0 ) {
109         syslog( LOG_ERR, "afp_timedown: sigaction: %m" );
110         afp_dsi_die(1);
111     }
112 }
113
114 #ifdef SERVERTEXT
115 static void afp_dsi_getmesg (int sig)
116 {
117       readmessage();
118       dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
119 }
120 #endif /* SERVERTEXT */
121
122 static void alarm_handler()
123 {
124   /* if we're in the midst of processing something,
125      don't die. we'll allow 3 missed tickles before we die (2 minutes) */
126   if ((child.flags & CHILD_RUNNING) || (child.tickle++ < 4)) {
127     dsi_tickle(child.obj->handle);
128   } else { /* didn't receive a tickle. close connection */
129     syslog(LOG_ERR, "afp_alarm: child timed out");
130     afp_dsi_die(1);
131   }
132 }
133
134 /* afp over dsi. this never returns. */
135 void afp_over_dsi(AFPObj *obj)
136 {
137   DSI *dsi = (DSI *) obj->handle;
138   u_int32_t err, cmd;
139   u_int8_t function;
140   struct sigaction action;
141
142   obj->exit = afp_dsi_die;
143   obj->reply = (int (*)()) dsi_cmdreply;
144   obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
145   
146   child.obj = obj;
147   child.tickle = child.flags = 0;
148
149   /* install SIGTERM and SIGHUP */
150   memset(&action, 0, sizeof(action));
151   action.sa_handler = afp_dsi_timedown;
152   sigemptyset( &action.sa_mask );
153   sigaddset(&action.sa_mask, SIGALRM);
154   sigaddset(&action.sa_mask, SIGTERM);
155   action.sa_flags = SA_RESTART;
156   if ( sigaction( SIGHUP, &action, 0 ) < 0 ) {
157     syslog( LOG_ERR, "afp_over_dsi: sigaction: %m" );
158     afp_dsi_die(1);
159   }
160
161   action.sa_handler = afp_dsi_die;
162   sigemptyset( &action.sa_mask );
163   sigaddset(&action.sa_mask, SIGALRM);
164   sigaddset(&action.sa_mask, SIGHUP);
165   action.sa_flags = SA_RESTART;
166   if ( sigaction( SIGTERM, &action, 0 ) < 0 ) {
167     syslog( LOG_ERR, "afp_over_dsi: sigaction: %m" );
168     afp_dsi_die(1);
169   }
170
171 #ifdef SERVERTEXT
172   /* Added for server message support */
173   action.sa_handler = afp_dsi_getmesg;
174   sigemptyset( &action.sa_mask );
175   sigaddset(&action.sa_mask, SIGUSR2);
176   action.sa_flags = SA_RESTART;
177   if ( sigaction( SIGUSR2, &action, 0) < 0 ) {
178     syslog( LOG_ERR, "afp_over_dsi: sigaction: %m" );
179     afp_dsi_die(1);
180   }
181 #endif /* SERVERTEXT */
182
183   /* tickle handler */
184   action.sa_handler = alarm_handler;
185   sigemptyset(&action.sa_mask);
186   sigaddset(&action.sa_mask, SIGHUP);
187   sigaddset(&action.sa_mask, SIGTERM);
188   action.sa_flags = SA_RESTART;
189   if ((sigaction(SIGALRM, &action, NULL) < 0) ||
190       (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
191     afp_dsi_die(1);
192   }
193
194   /* get stuck here until the end */
195   while ((cmd = dsi_receive(dsi))) {
196     child.tickle = 0;
197
198     if (cmd == DSIFUNC_TICKLE) {
199       /* so we don't get killed on the client side. */
200       if (child.flags & CHILD_DIE) 
201         dsi_tickle(dsi);
202       continue;
203     } else if (!(child.flags & CHILD_DIE)) /* reset tickle timer */
204       setitimer(ITIMER_REAL, &dsi->timer, NULL);
205
206     switch(cmd) {
207     case DSIFUNC_CLOSE:
208       afp_dsi_close(obj);
209       syslog(LOG_INFO, "done");
210       if (obj->options.flags & OPTION_DEBUG ) 
211         printf("done\n");
212       return;
213       break;
214
215     case DSIFUNC_CMD:
216 #ifdef AFS
217       if ( writtenfork ) {
218         if ( flushfork( writtenfork ) < 0 ) {
219           syslog( LOG_ERR, "main flushfork: %m" );
220         }
221         writtenfork = NULL;
222       }
223 #endif /* AFS */
224
225       function = (u_char) dsi->commands[0];
226       if (obj->options.flags & OPTION_DEBUG ) {
227         printf("command: %d\n", function);
228         bprint(dsi->commands, dsi->cmdlen);
229       }
230
231       /* send off an afp command. in a couple cases, we take advantage
232        * of the fact that we're a stream-based protocol. */
233       if (afp_switch[function]) {
234         dsi->datalen = DSI_DATASIZ;
235         child.flags |= CHILD_RUNNING;
236         err = (*afp_switch[function])(obj,
237                                       dsi->commands, dsi->cmdlen,
238                                       dsi->data, &dsi->datalen);
239         child.flags &= ~CHILD_RUNNING;
240       } else {
241         syslog(LOG_ERR, "bad function %X", function);
242         dsi->datalen = 0;
243         err = AFPERR_NOOP;
244       }
245
246       /* single shot toggle that gets set by dsi_readinit. */
247       if (dsi->noreply) {
248         dsi->noreply = 0;
249         break;
250       }
251
252       if (obj->options.flags & OPTION_DEBUG ) {
253         printf( "reply: %d, %d\n", err, dsi->clientID);
254         bprint(dsi->data, dsi->datalen);
255       }
256
257       if (!dsi_cmdreply(dsi, err)) {
258         syslog(LOG_ERR, "dsi_cmdreply(%d): %m", dsi->socket);
259         afp_dsi_die(1);
260       }
261       break;
262
263     case DSIFUNC_WRITE: /* FPWrite and FPAddIcon */
264       function = (u_char) dsi->commands[0];
265       if ( obj->options.flags & OPTION_DEBUG ) {
266         printf("(write) command: %d, %d\n", function, dsi->cmdlen);
267         bprint(dsi->commands, dsi->cmdlen);
268       }
269
270       if ( afp_switch[ function ] != NULL ) {
271         dsi->datalen = DSI_DATASIZ;
272         child.flags |= CHILD_RUNNING;
273         err = (*afp_switch[function])(obj, dsi->commands, dsi->cmdlen,
274                                       dsi->data, &dsi->datalen);
275         child.flags &= ~CHILD_RUNNING;
276       } else {
277         syslog( LOG_ERR, "(write) bad function %x", function);
278         dsi->datalen = 0;
279         err = AFPERR_NOOP;
280       }
281
282       if (obj->options.flags & OPTION_DEBUG ) {
283         printf( "(write) reply code: %d, %d\n", err, dsi->clientID);
284         bprint(dsi->data, dsi->datalen);
285       }
286
287       if (!dsi_wrtreply(dsi, err)) {
288         syslog( LOG_ERR, "dsi_wrtreply: %m" );
289         afp_dsi_die(1);
290       }
291       break;
292
293     case DSIFUNC_ATTN: /* attention replies */
294       continue;
295       break;
296
297       /* error. this usually implies a mismatch of some kind
298        * between server and client. if things are correct,
299        * we need to flush the rest of the packet if necessary. */
300     default: 
301       syslog(LOG_INFO,"afp_dsi: spurious command %d", cmd);
302       dsi_writeinit(dsi, dsi->data, DSI_DATASIZ);
303       dsi_writeflush(dsi);
304       break;
305     }
306         
307     if ( obj->options.flags & OPTION_DEBUG ) {
308 #ifdef notdef
309       pdesc( stdout );
310 #endif /* notdef */
311       of_pforkdesc( stdout );
312       fflush( stdout );
313     }
314   }
315
316   /* error */
317   afp_dsi_die(1);
318 }