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