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