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