]> arthur.barton.de Git - netatalk.git/blob - libatalk/dsi/dsi_getsess.c
Initial revision
[netatalk.git] / libatalk / dsi / dsi_getsess.c
1 /*
2  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
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 #include <sys/types.h>
11 #include <signal.h>
12 #include <sys/wait.h>
13 #include <sys/time.h>
14 #include <syslog.h>
15
16 #include <atalk/dsi.h>
17 #include <atalk/server_child.h>
18
19 static server_child *children = NULL;
20
21 void dsi_kill(int sig)
22 {
23   if (children)
24     server_child_kill(children, CHILD_DSIFORK, sig);
25 }
26
27 /* hand off the command. return child connection to the main program */
28 DSI *dsi_getsession(DSI *dsi, server_child *serv_children, 
29                     const int tickleval)
30 {
31   pid_t pid;
32   
33   /* do a couple things on first entry */
34   if (!dsi->inited) {
35     if (!(children = serv_children))
36       return NULL;
37     dsi->inited = 1;
38   }
39   
40   switch (pid = dsi->proto_open(dsi)) {
41   case -1:
42     /* if we fail, just return. it might work later */
43     syslog(LOG_ERR, "dsi_getsess: %m");
44     return dsi;
45
46   case 0: /* child. mostly handled below. */
47     dsi->child = 1;
48     break;
49
50   default: /* parent */
51     /* using SIGQUIT is hokey, but the child might not have
52      * re-established its signal handler for SIGTERM yet. */
53     if (server_child_add(children, CHILD_DSIFORK, pid) < 0) {
54       syslog(LOG_ERR, "dsi_getsess: %m");
55       dsi->header.dsi_flags = DSIFL_REPLY;
56       dsi->header.dsi_code = DSIERR_SERVBUSY;
57       dsi_send(dsi);
58       dsi->header.dsi_code = DSIERR_OK;
59       kill(pid, SIGQUIT);
60     }
61
62     dsi->proto_close(dsi);
63     return dsi;
64   }
65   
66   /* child: check number of open connections. this is one off the
67    * actual count. */
68   if ((children->count >= children->nsessions) &&
69       (dsi->header.dsi_command == DSIFUNC_OPEN)) {
70     syslog(LOG_INFO, "dsi_getsess: too many connections");
71     dsi->header.dsi_flags = DSIFL_REPLY;
72     dsi->header.dsi_code = DSIERR_TOOMANY;
73     dsi_send(dsi);
74     exit(1);
75   }
76
77   /* get rid of some stuff */
78   close(dsi->serversock);
79   server_child_free(children); 
80   children = NULL;
81
82   switch (dsi->header.dsi_command) {
83   case DSIFUNC_STAT: /* send off status and return */
84     {
85       /* OpenTransport 1.1.2 bug workaround: 
86        *
87        * OT code doesn't currently handle close sockets well. urk.
88        * the workaround: wait for the client to close its
89        * side. timeouts prevent indefinite resource use. 
90        */
91       
92       static struct timeval timeout = {120, 0};
93       fd_set readfds;
94       
95       dsi_getstatus(dsi);
96
97       FD_ZERO(&readfds);
98       FD_SET(dsi->socket, &readfds);
99       free(dsi);
100       select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);    
101       exit(0);
102     }
103     break;
104     
105   case DSIFUNC_OPEN: /* setup session */
106     /* set up the tickle timer */
107     dsi->timer.it_interval.tv_sec = dsi->timer.it_value.tv_sec = tickleval;
108     dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0;
109     signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
110     dsi_opensession(dsi);
111     return dsi;
112     break;
113
114   default: /* just close */
115     syslog(LOG_INFO, "DSIUnknown %d", dsi->header.dsi_command);
116     dsi->proto_close(dsi);
117     exit(1);
118   }
119 }