]> arthur.barton.de Git - netatalk.git/blob - libatalk/dsi/dsi_getsess.c
b8ff4944467becec4eeb035223024cf92cc71fe4
[netatalk.git] / libatalk / dsi / dsi_getsess.c
1 /*
2  * $Id: dsi_getsess.c,v 1.7 2005-04-28 20:50:02 bfernhomberg Exp $
3  *
4  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
5  * All rights reserved. See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <signal.h>
18
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <sys/time.h>
22 #include <atalk/logger.h>
23 #include <atalk/util.h>
24
25 #include <atalk/dsi.h>
26 #include <atalk/server_child.h>
27
28 /* hand off the command. return child connection to the main program */
29 afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval)
30 {
31   pid_t pid;
32   unsigned int ipc_fds[2];  
33   afp_child_t *child;
34
35   if (socketpair(PF_UNIX, SOCK_STREAM, 0, ipc_fds) < 0) {
36       LOG(log_error, logtype_afpd, "dsi_getsess: %s", strerror(errno));
37       exit( EXITERR_CLNT );
38   }
39
40   if (setnonblock(ipc_fds[0], 1) != 0 || setnonblock(ipc_fds[1], 1) != 0) {
41       LOG(log_error, logtype_afpd, "dsi_getsess: setnonblock: %s", strerror(errno));
42       exit(EXITERR_CLNT);
43   }
44
45   switch (pid = dsi->proto_open(dsi)) { /* in libatalk/dsi/dsi_tcp.c */
46   case -1:
47     /* if we fail, just return. it might work later */
48     LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
49     return NULL;
50
51   case 0: /* child. mostly handled below. */
52     break;
53
54   default: /* parent */
55     /* using SIGQUIT is hokey, but the child might not have
56      * re-established its signal handler for SIGTERM yet. */
57     if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) < 0) {
58       LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
59       dsi->header.dsi_flags = DSIFL_REPLY;
60       dsi->header.dsi_code = DSIERR_SERVBUSY;
61       dsi_send(dsi);
62       dsi->header.dsi_code = DSIERR_OK;
63       kill(pid, SIGQUIT);
64     }
65     dsi->proto_close(dsi);
66     return child;
67   }
68   
69   /* child: check number of open connections. this is one off the
70    * actual count. */
71   if ((serv_children->count >= serv_children->nsessions) &&
72       (dsi->header.dsi_command == DSIFUNC_OPEN)) {
73     LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
74     dsi->header.dsi_flags = DSIFL_REPLY;
75     dsi->header.dsi_code = DSIERR_TOOMANY;
76     dsi_send(dsi);
77     exit(EXITERR_CLNT);
78   }
79
80   /* get rid of some stuff */
81   close(dsi->serversock);
82   server_child_free(serv_children); 
83
84   switch (dsi->header.dsi_command) {
85   case DSIFUNC_STAT: /* send off status and return */
86     {
87       /* OpenTransport 1.1.2 bug workaround: 
88        *
89        * OT code doesn't currently handle close sockets well. urk.
90        * the workaround: wait for the client to close its
91        * side. timeouts prevent indefinite resource use. 
92        */
93       
94       static struct timeval timeout = {120, 0};
95       fd_set readfds;
96       
97       dsi_getstatus(dsi);
98
99       FD_ZERO(&readfds);
100       FD_SET(dsi->socket, &readfds);
101       free(dsi);
102       select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);    
103       exit(0);
104     }
105     break;
106     
107   case DSIFUNC_OPEN: /* setup session */
108     /* set up the tickle timer */
109     dsi->timer.it_interval.tv_sec = dsi->timer.it_value.tv_sec = tickleval;
110     dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0;
111     signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
112     dsi_opensession(dsi);
113     if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
114         exit(EXITERR_SYS);
115     child->ipc_fds[1] = ipc_fds[1];
116     return child;
117     break;
118
119   default: /* just close */
120     LOG(log_info, logtype_dsi, "DSIUnknown %d", dsi->header.dsi_command);
121     dsi->proto_close(dsi);
122     exit(EXITERR_CLNT);
123   }
124 }