2 * $Id: afp_dsi.c,v 1.49.2.1 2010-02-01 10:56:08 franklahm Exp $
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.
8 * modified from main.c. this handles afp over tcp.
13 #endif /* HAVE_CONFIG_H */
22 #endif /* HAVE_UNISTD_H */
23 #include <sys/socket.h>
25 #ifdef HAVE_SYS_STAT_H
27 #endif /* HAVE_SYS_STAT_H */
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <atalk/logger.h>
32 #include <atalk/dsi.h>
33 #include <atalk/compat.h>
34 #include <atalk/util.h>
45 #endif /* FORCE_UIDGID */
47 #define CHILD_DIE (1 << 0)
48 #define CHILD_RUNNING (1 << 1)
49 #define CHILD_SLEEPING (1 << 2)
50 #define CHILD_DATA (1 << 3)
59 static void afp_dsi_close(AFPObj *obj)
61 DSI *dsi = obj->handle;
63 /* we may have been called from a signal handler caught when afpd was running
64 * as uid 0, that's the wrong user for volume's prexec_close scripts if any,
65 * restore our login user
67 if (seteuid( obj->uid ) < 0) {
68 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
75 LOG(log_info, logtype_afpd, "%.2fKB read, %.2fKB written",
76 dsi->read_count/1024.0, dsi->write_count/1024.0);
81 /* -------------------------------
83 * a little bit of code duplication.
85 static void afp_dsi_die(int sig)
87 static volatile int in_handler;
92 /* it's not atomic but we don't care because it's an exit function
93 * ie if a signal is received here, between the test and the affectation,
98 dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN);
99 afp_dsi_close(child.obj);
100 if (sig) /* if no signal, assume dieing because logins are disabled &
101 don't log it (maintenance mode)*/
102 LOG(log_info, logtype_afpd, "Connection terminated");
103 if (sig == SIGTERM || sig == SIGALRM) {
112 static void afp_dsi_sleep(void)
114 child.flags |= CHILD_SLEEPING;
115 dsi_sleep(child.obj->handle, 1);
118 /* ------------------- */
119 static void afp_dsi_timedown(int sig _U_)
124 child.flags |= CHILD_DIE;
125 /* shutdown and don't reconnect. server going down in 5 minutes. */
126 setmessage("The server is going down for maintenance.");
127 if (dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
128 AFPATTN_MESG | AFPATTN_TIME(5)) < 0) {
129 DSI *dsi = (DSI *) child.obj->handle;
130 dsi->down_request = 1;
133 it.it_interval.tv_sec = 0;
134 it.it_interval.tv_usec = 0;
135 it.it_value.tv_sec = 300;
136 it.it_value.tv_usec = 0;
138 if ( setitimer( ITIMER_REAL, &it, NULL ) < 0 ) {
139 LOG(log_error, logtype_afpd, "afp_timedown: setitimer: %s", strerror(errno) );
140 afp_dsi_die(EXITERR_SYS);
142 memset(&sv, 0, sizeof(sv));
143 sv.sa_handler = afp_dsi_die;
144 sigemptyset( &sv.sa_mask );
145 sigaddset(&sv.sa_mask, SIGHUP);
146 sigaddset(&sv.sa_mask, SIGTERM);
147 sv.sa_flags = SA_RESTART;
148 if ( sigaction( SIGALRM, &sv, NULL ) < 0 ) {
149 LOG(log_error, logtype_afpd, "afp_timedown: sigaction: %s", strerror(errno) );
150 afp_dsi_die(EXITERR_SYS);
154 sv.sa_handler = SIG_IGN;
155 sigemptyset( &sv.sa_mask );
156 sv.sa_flags = SA_RESTART;
157 if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
158 LOG(log_error, logtype_afpd, "afp_timedown: sigaction SIGHUP: %s", strerror(errno) );
159 afp_dsi_die(EXITERR_SYS);
163 /* ---------------------------------
164 * SIGHUP reload configuration file
165 * FIXME here or we wait ?
167 volatile int reload_request = 0;
169 static void afp_dsi_reload(int sig _U_)
174 /* ---------------------- */
176 static void afp_dsi_getmesg (int sig _U_)
178 DSI *dsi = (DSI *) child.obj->handle;
180 dsi->msg_request = 1;
181 if (dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5)) < 0)
182 dsi->msg_request = 2;
184 #endif /* SERVERTEXT */
186 static void alarm_handler(int sig _U_)
189 DSI *dsi = (DSI *) child.obj->handle;
191 /* we have to restart the timer because some libraries
193 setitimer(ITIMER_REAL, &dsi->timer, NULL);
195 /* we got some traffic from the client since the previous timer
197 if ((child.flags & CHILD_DATA)) {
198 child.flags &= ~CHILD_DATA;
202 /* if we're in the midst of processing something,
204 if ((child.flags & CHILD_SLEEPING) && child.tickle++ < child.obj->options.sleep) {
208 if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) {
209 if (!(err = pollvoltime(child.obj)))
210 err = dsi_tickle(child.obj->handle);
212 afp_dsi_die(EXITERR_CLNT);
214 } else { /* didn't receive a tickle. close connection */
215 LOG(log_error, logtype_afpd, "afp_alarm: child timed out");
216 afp_dsi_die(EXITERR_CLNT);
221 if dsi->in_write is set attention, tickle (and close?) msg
222 aren't sent. We don't care about tickle
224 static void pending_request(DSI *dsi)
226 /* send pending attention */
228 /* read msg if any, it could be done in afp_getsrvrmesg */
229 if (dsi->msg_request) {
230 if (dsi->msg_request == 2) {
231 /* didn't send it in signal handler */
232 dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
234 dsi->msg_request = 0;
235 readmessage(child.obj);
237 if (dsi->down_request) {
238 dsi->down_request = 0;
239 dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
240 AFPATTN_MESG | AFPATTN_TIME(5));
244 /* -------------------------------------------
245 afp over dsi. this never returns.
247 void afp_over_dsi(AFPObj *obj)
249 DSI *dsi = (DSI *) obj->handle;
252 struct sigaction action;
254 obj->exit = afp_dsi_die;
255 obj->reply = (int (*)()) dsi_cmdreply;
256 obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
258 obj->sleep = afp_dsi_sleep;
260 child.tickle = child.flags = 0;
262 memset(&action, 0, sizeof(action));
265 action.sa_handler = afp_dsi_reload;
266 sigemptyset( &action.sa_mask );
267 sigaddset(&action.sa_mask, SIGALRM);
268 sigaddset(&action.sa_mask, SIGTERM);
269 sigaddset(&action.sa_mask, SIGUSR1);
271 sigaddset(&action.sa_mask, SIGUSR2);
273 action.sa_flags = SA_RESTART;
274 if ( sigaction( SIGHUP, &action, NULL ) < 0 ) {
275 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
276 afp_dsi_die(EXITERR_SYS);
279 /* install SIGTERM */
280 action.sa_handler = afp_dsi_die;
281 sigemptyset( &action.sa_mask );
282 sigaddset(&action.sa_mask, SIGALRM);
283 sigaddset(&action.sa_mask, SIGHUP);
284 sigaddset(&action.sa_mask, SIGUSR1);
286 sigaddset(&action.sa_mask, SIGUSR2);
288 action.sa_flags = SA_RESTART;
289 if ( sigaction( SIGTERM, &action, NULL ) < 0 ) {
290 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
291 afp_dsi_die(EXITERR_SYS);
295 /* Added for server message support */
296 action.sa_handler = afp_dsi_getmesg;
297 sigemptyset( &action.sa_mask );
298 sigaddset(&action.sa_mask, SIGALRM);
299 sigaddset(&action.sa_mask, SIGTERM);
300 sigaddset(&action.sa_mask, SIGUSR1);
301 sigaddset(&action.sa_mask, SIGHUP);
302 action.sa_flags = SA_RESTART;
303 if ( sigaction( SIGUSR2, &action, NULL) < 0 ) {
304 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
305 afp_dsi_die(EXITERR_SYS);
307 #endif /* SERVERTEXT */
309 /* SIGUSR1 - set down in 5 minutes */
310 action.sa_handler = afp_dsi_timedown;
311 sigemptyset( &action.sa_mask );
312 sigaddset(&action.sa_mask, SIGALRM);
313 sigaddset(&action.sa_mask, SIGHUP);
314 sigaddset(&action.sa_mask, SIGTERM);
316 sigaddset(&action.sa_mask, SIGUSR2);
318 action.sa_flags = SA_RESTART;
319 if ( sigaction( SIGUSR1, &action, NULL) < 0 ) {
320 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
321 afp_dsi_die(EXITERR_SYS);
326 action.sa_handler = alarm_handler;
327 sigemptyset(&action.sa_mask);
328 sigaddset(&action.sa_mask, SIGHUP);
329 sigaddset(&action.sa_mask, SIGTERM);
330 sigaddset(&action.sa_mask, SIGUSR1);
332 sigaddset(&action.sa_mask, SIGUSR2);
334 action.sa_flags = SA_RESTART;
335 if ((sigaction(SIGALRM, &action, NULL) < 0) ||
336 (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
337 afp_dsi_die(EXITERR_SYS);
339 #endif /* DEBUGGING */
341 if (dircache_init(0) != 0)
342 afp_dsi_die(EXITERR_SYS);
344 /* get stuck here until the end */
345 while ((cmd = dsi_receive(dsi))) {
347 child.flags &= ~CHILD_SLEEPING;
348 dsi_sleep(dsi, 0); /* wake up */
349 if (reload_request) {
351 load_volumes(child.obj);
354 if (cmd == DSIFUNC_TICKLE) {
355 /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */
356 if ((child.flags & CHILD_DIE))
358 pending_request(dsi);
362 child.flags |= CHILD_DATA;
366 LOG(log_info, logtype_afpd, "done");
373 if ( flushfork( writtenfork ) < 0 ) {
374 LOG(log_error, logtype_afpd, "main flushfork: %s", strerror(errno) );
380 function = (u_char) dsi->commands[0];
382 /* send off an afp command. in a couple cases, we take advantage
383 * of the fact that we're a stream-based protocol. */
384 if (afp_switch[function]) {
385 dsi->datalen = DSI_DATASIZ;
386 child.flags |= CHILD_RUNNING;
388 LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
390 err = (*afp_switch[function])(obj,
391 (char *)&dsi->commands, dsi->cmdlen,
392 (char *)&dsi->data, &dsi->datalen);
394 LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
395 AfpNum2name(function), AfpErr2name(err));
397 /* bring everything back to old euid, egid */
399 restore_uidgid ( &obj->uidgid );
400 #endif /* FORCE_UIDGID */
401 child.flags &= ~CHILD_RUNNING;
403 LOG(log_error, logtype_afpd, "bad function %X", function);
408 /* single shot toggle that gets set by dsi_readinit. */
414 if (!dsi_cmdreply(dsi, err)) {
415 LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
416 afp_dsi_die(EXITERR_CLNT);
420 case DSIFUNC_WRITE: /* FPWrite and FPAddIcon */
421 function = (u_char) dsi->commands[0];
422 if ( afp_switch[ function ] != NULL ) {
423 dsi->datalen = DSI_DATASIZ;
424 child.flags |= CHILD_RUNNING;
425 err = (*afp_switch[function])(obj,
426 (char *)&dsi->commands, dsi->cmdlen,
427 (char *)&dsi->data, &dsi->datalen);
428 child.flags &= ~CHILD_RUNNING;
430 /* bring everything back to old euid, egid */
432 restore_uidgid ( &obj->uidgid );
433 #endif /* FORCE_UIDGID */
435 LOG(log_error, logtype_afpd, "(write) bad function %x", function);
440 if (!dsi_wrtreply(dsi, err)) {
441 LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) );
442 afp_dsi_die(EXITERR_CLNT);
446 case DSIFUNC_ATTN: /* attention replies */
449 /* error. this usually implies a mismatch of some kind
450 * between server and client. if things are correct,
451 * we need to flush the rest of the packet if necessary. */
453 LOG(log_info, logtype_afpd,"afp_dsi: spurious command %d", cmd);
454 dsi_writeinit(dsi, dsi->data, DSI_DATASIZ);
458 pending_request(dsi);
462 afp_dsi_die(EXITERR_CLNT);