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