• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/libatalk/dsi/
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 */
41afp_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 SIGQUIT is hokey, but the child might not have
68     * re-established its signal handler for SIGTERM yet. */
69    if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) ==  NULL) {
70      LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
71      dsi->header.dsi_flags = DSIFL_REPLY;
72      dsi->header.dsi_code = DSIERR_SERVBUSY;
73      dsi_send(dsi);
74      dsi->header.dsi_code = DSIERR_OK;
75      kill(pid, SIGQUIT);
76    }
77    dsi->proto_close(dsi);
78    return child;
79  }
80
81  /* child: check number of open connections. this is one off the
82   * actual count. */
83  if ((serv_children->count >= serv_children->nsessions) &&
84      (dsi->header.dsi_command == DSIFUNC_OPEN)) {
85    LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
86    dsi->header.dsi_flags = DSIFL_REPLY;
87    dsi->header.dsi_code = DSIERR_TOOMANY;
88    dsi_send(dsi);
89    exit(EXITERR_CLNT);
90  }
91
92  /* get rid of some stuff */
93  close(dsi->serversock);
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    signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
124    dsi_opensession(dsi);
125    if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
126        exit(EXITERR_SYS);
127    child->ipc_fds[1] = ipc_fds[1];
128    return child;
129    break;
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}
137