]> arthur.barton.de Git - netatalk.git/blob - libatalk/dsi/dsi_getsess.c
Merge branch 'product-2-2' of git://netatalk.git.sourceforge.net/gitroot/netatalk...
[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 #include <unistd.h>
17 #include <signal.h>
18 #include <sys/types.h>
19 #include <sys/socket.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 /* hand off the command. return child connection to the main program */
41 afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval)
42 {
43   pid_t pid;
44   unsigned int ipc_fds[2];  
45   afp_child_t *child;
46
47   if (socketpair(PF_UNIX, SOCK_STREAM, 0, ipc_fds) < 0) {
48       LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
49       exit( EXITERR_CLNT );
50   }
51
52   if (setnonblock(ipc_fds[0], 1) != 0 || setnonblock(ipc_fds[1], 1) != 0) {
53       LOG(log_error, logtype_dsi, "dsi_getsess: setnonblock: %s", strerror(errno));
54       exit(EXITERR_CLNT);
55   }
56
57   switch (pid = dsi->proto_open(dsi)) { /* in libatalk/dsi/dsi_tcp.c */
58   case -1:
59     /* if we fail, just return. it might work later */
60     LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
61     return NULL;
62
63   case 0: /* child. mostly handled below. */
64     break;
65
66   default: /* parent */
67     /* using SIGKILL is hokey, but the child might not have
68      * re-established its signal handler for SIGTERM yet. */
69     close(ipc_fds[1]);
70     if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds[0])) ==  NULL) {
71       LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
72       close(ipc_fds[0]);
73       dsi->header.dsi_flags = DSIFL_REPLY;
74       dsi->header.dsi_code = DSIERR_SERVBUSY;
75       dsi_send(dsi);
76       dsi->header.dsi_code = DSIERR_OK;
77       kill(pid, SIGKILL);
78     }
79     dsi->proto_close(dsi);
80     return child;
81   }
82   
83   /* child: check number of open connections. this is one off the
84    * actual count. */
85   if ((serv_children->count >= serv_children->nsessions) &&
86       (dsi->header.dsi_command == DSIFUNC_OPEN)) {
87     LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
88     dsi->header.dsi_flags = DSIFL_REPLY;
89     dsi->header.dsi_code = DSIERR_TOOMANY;
90     dsi_send(dsi);
91     exit(EXITERR_CLNT);
92   }
93
94   /* get rid of some stuff */
95   dsi->AFPobj->ipc_fd = ipc_fds[1];
96   close(ipc_fds[0]);
97   close(dsi->serversock);
98   server_child_free(serv_children); 
99
100   switch (dsi->header.dsi_command) {
101   case DSIFUNC_STAT: /* send off status and return */
102     {
103       /* OpenTransport 1.1.2 bug workaround: 
104        *
105        * OT code doesn't currently handle close sockets well. urk.
106        * the workaround: wait for the client to close its
107        * side. timeouts prevent indefinite resource use. 
108        */
109       
110       static struct timeval timeout = {120, 0};
111       fd_set readfds;
112       
113       dsi_getstatus(dsi);
114
115       FD_ZERO(&readfds);
116       FD_SET(dsi->socket, &readfds);
117       free(dsi);
118       select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);    
119       exit(0);
120     }
121     break;
122     
123   case DSIFUNC_OPEN: /* setup session */
124     /* set up the tickle timer */
125     dsi->timer.it_interval.tv_sec = dsi->timer.it_value.tv_sec = tickleval;
126     dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0;
127     signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
128     dsi_opensession(dsi);
129     return NULL;
130
131   default: /* just close */
132     LOG(log_info, logtype_dsi, "DSIUnknown %d", dsi->header.dsi_command);
133     dsi->proto_close(dsi);
134     exit(EXITERR_CLNT);
135   }
136 }