/*
+ * $Id: dsi_tcp.c,v 1.16 2009-10-25 06:13:11 didg Exp $
+ *
* Copyright (c) 1997, 1998 Adrian Sun (asun@zoology.washington.edu)
* All rights reserved. See COPYRIGHT.
*
#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+#endif /* HAVE_CONFIG_H */
#define USE_TCP_NODELAY
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
#include <errno.h>
+#ifdef HAVE_NETDB_H
#include <netdb.h>
+#endif /* HAVE_NETDB_H */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
-#endif
+#endif /* HAVE_STDINT_H */
#include <sys/ioctl.h>
+#ifdef TRU64
+#include <sys/mbuf.h>
+#include <net/route.h>
+#endif /* TRU64 */
#include <net/if.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
-#include <syslog.h>
+#include <atalk/logger.h>
#ifdef __svr4__
#include <sys/sockio.h>
-#endif
+#endif /* __svr4__ */
#ifdef TCPWRAP
#include <tcpd.h>
-int allow_severity = LOG_INFO;
-int deny_severity = LOG_WARNING;
-#endif
+int allow_severity = log_info;
+int deny_severity = log_warning;
+#endif /* TCPWRAP */
#include <atalk/dsi.h>
#include <atalk/compat.h>
#ifndef DSI_TCPMAXPEND
#define DSI_TCPMAXPEND 20 /* max # of pending connections */
-#endif
+#endif /* DSI_TCPMAXPEND */
#ifndef DSI_TCPTIMEOUT
#define DSI_TCPTIMEOUT 120 /* timeout in seconds for connections */
-#endif
+#endif /* ! DSI_TCPTIMEOUT */
/* FIXME/SOCKLEN_T: socklen_t is a unix98 feature. */
#ifndef SOCKLEN_T
#define SOCKLEN_T unsigned int
-#endif
+#endif /* ! SOCKLEN_T */
static void dsi_tcp_close(DSI *dsi)
{
dsi->socket = -1;
}
+static void dsi_tcp_timeout(DSI *dsi)
+{
+ struct timeval tv;
+ /* 2 seconds delay, most of the time it translates to 4 seconds:
+ * send/write returns first with whatever it has written and the
+ * second time it returns EAGAIN
+ */
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+
+ /* Note: write isn't a restartable syscall if there's a timeout on the socket
+ * we have to test for EINTR
+ */
+ if (setsockopt(dsi->socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
+ LOG(log_error, logtype_default, "dsi_tcp_open: unable to set timeout %s", strerror(errno));
+ exit(EXITERR_CLNT);
+ }
+}
+
/* alarm handler for tcp_open */
-static void timeout_handler()
+static void timeout_handler(int sig _U_)
{
- syslog(LOG_ERR, "dsi_tcp_open: connection timed out");
- exit(1);
+ LOG(log_error, logtype_default, "dsi_tcp_open: connection timed out");
+ exit(EXITERR_CLNT);
}
+static struct itimerval itimer;
/* accept the socket and do a little sanity checking */
static int dsi_tcp_open(DSI *dsi)
{
request_init(&req, RQ_DAEMON, dsi->program, RQ_FILE, dsi->socket, NULL);
fromhost(&req);
if (!hosts_access(&req)) {
- syslog(deny_severity, "refused connect from %s", eval_client(&req));
+ LOG(deny_severity, logtype_default, "refused connect from %s", eval_client(&req));
close(dsi->socket);
errno = ECONNREFUSED;
dsi->socket = -1;
}
}
-#endif
+#endif /* TCPWRAP */
if (dsi->socket < 0)
return -1;
- if ((pid = fork()) == 0) { /* child */
- static const struct itimerval timer = {{0, 0}, {DSI_TCPTIMEOUT, 0}};
+ getitimer(ITIMER_PROF, &itimer);
+ if (0 == (pid = fork()) ) { /* child */
+ static struct itimerval timer = {{0, 0}, {DSI_TCPTIMEOUT, 0}};
struct sigaction newact, oldact;
u_int8_t block[DSI_BLOCKSIZ];
size_t stored;
-
- /* reset a couple signals */
- signal(SIGTERM, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
+ /* reset signals */
+ server_reset_signal();
+
+#ifndef DEBUGGING
/* install an alarm to deal with non-responsive connections */
- memset(&newact, 0, sizeof(newact));
newact.sa_handler = timeout_handler;
+ sigemptyset(&newact.sa_mask);
+ newact.sa_flags = 0;
+ sigemptyset(&oldact.sa_mask);
+ oldact.sa_flags = 0;
+ setitimer(ITIMER_PROF, &itimer, NULL);
+
if ((sigaction(SIGALRM, &newact, &oldact) < 0) ||
(setitimer(ITIMER_REAL, &timer, NULL) < 0)) {
- syslog(LOG_ERR, "dsi_tcp_open: %m");
- exit(1);
+ LOG(log_error, logtype_default, "dsi_tcp_open: %s", strerror(errno));
+ exit(EXITERR_SYS);
}
+#endif
/* read in commands. this is similar to dsi_receive except
* for the fact that we do some sanity checking to prevent
* delinquent connections from causing mischief. */
/* read in the first two bytes */
- dsi_stream_read(dsi, block, 2);
- if ((block[0] > DSIFL_MAX) || (block[1] > DSIFUNC_MAX)) {
- syslog(LOG_ERR, "dsi_tcp_open: invalid header");
- exit(1);
+ len = dsi_stream_read(dsi, block, 2);
+ if (!len ) {
+ /* connection already closed, don't log it (normal OSX 10.3 behaviour) */
+ exit(EXITERR_CLNT);
+ }
+ if (len < 2 || (block[0] > DSIFL_MAX) || (block[1] > DSIFUNC_MAX)) {
+ LOG(log_error, logtype_default, "dsi_tcp_open: invalid header");
+ exit(EXITERR_CLNT);
}
/* read in the rest of the header */
if (len > 0)
stored += len;
else {
- syslog(LOG_ERR, "dsi_tcp_open: stream_read: %m");
- exit(1);
+ LOG(log_error, logtype_default, "dsi_tcp_open: stream_read: %s", strerror(errno));
+ exit(EXITERR_CLNT);
}
}
if (len > 0)
stored += len;
else {
- syslog(LOG_ERR, "dsi_tcp_open: stream_read: %m");
- exit(1);
+ LOG(log_error, logtype_default, "dsi_tcp_open: stream_read: %s", strerror(errno));
+ exit(EXITERR_CLNT);
}
}
- /* restore signal */
+ /* stop timer and restore signal handler */
+#ifndef DEBUGGING
+ memset(&timer, 0, sizeof(timer));
+ setitimer(ITIMER_REAL, &timer, NULL);
sigaction(SIGALRM, &oldact, NULL);
+#endif
+
+ dsi_tcp_timeout(dsi);
- syslog(LOG_INFO,"ASIP session:%u(%d) from %s:%u(%d)",
+ LOG(log_info, logtype_default,"ASIP session:%u(%d) from %s:%u(%d)",
ntohs(dsi->server.sin_port), dsi->serversock,
inet_ntoa(dsi->client.sin_addr), ntohs(dsi->client.sin_port),
dsi->socket);
if (!address)
dsi->server.sin_addr.s_addr = htonl(INADDR_ANY);
else if (inet_aton(address, &dsi->server.sin_addr) == 0) {
- syslog(LOG_INFO, "dsi_tcp: invalid address (%s)", address);
+ LOG(log_info, logtype_default, "dsi_tcp: invalid address (%s)", address);
return 0;
}
#endif
#ifdef USE_TCP_NODELAY
+
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
-#endif
+#endif
+
port = 1;
setsockopt(dsi->serversock, SOL_TCP, TCP_NODELAY, &port, sizeof(port));
-#endif
+#endif /* USE_TCP_NODELAY */
/* now, bind the socket and set it up for listening */
if ((bind(dsi->serversock, (struct sockaddr *) &dsi->server,
}
}
+ /* Point protocol specific functions to tcp versions */
+ dsi->proto_open = dsi_tcp_open;
+ dsi->proto_close = dsi_tcp_close;
+
/* get real address for GetStatus. we'll go through the list of
* interfaces if necessary. */
- if (!address) {
- if ((host = gethostbyname(hostname))) /* we can resolve the name */
- dsi->server.sin_addr.s_addr = ((struct in_addr *) host->h_addr)->s_addr;
- else {
+
+ if (address) {
+ /* address is a parameter, use it 'as is' */
+ return 1;
+ }
+
+ if (!(host = gethostbyname(hostname)) ) { /* we can't resolve the name */
+
+ LOG(log_info, logtype_default, "dsi_tcp: cannot resolve hostname '%s'", hostname);
+ if (proxy) {
+ /* give up we have nothing to advertise */
+ return 0;
+ }
+ }
+ else {
+ if (( ((struct in_addr *) host->h_addr)->s_addr & htonl(0x7F000000) ) != htonl(0x7F000000)) { /* FIXME ugly check */
+ dsi->server.sin_addr.s_addr = ((struct in_addr *) host->h_addr)->s_addr;
+ return 1;
+ }
+ LOG(log_info, logtype_default, "dsi_tcp: hostname '%s' resolves to loopback address", hostname);
+ }
+ {
char **start, **list;
struct ifreq ifr;
/* get it from the interface list */
start = list = getifacelist();
while (list && *list) {
- strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
- list++;
+ strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
+ list++;
#ifndef IFF_SLAVE
#define IFF_SLAVE 0
#endif
- if (ioctl(dsi->serversock, SIOCGIFFLAGS, &ifr) < 0)
- continue;
- if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
- continue;
+ if (ioctl(dsi->serversock, SIOCGIFFLAGS, &ifr) < 0)
+ continue;
- if ((ifr.ifr_flags & IFF_UP) == 0)
- continue;
+ if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
+ continue;
- if (ioctl(dsi->serversock, SIOCGIFADDR, &ifr) < 0)
- continue;
+ if (!(ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) )
+ continue;
+
+ if (ioctl(dsi->serversock, SIOCGIFADDR, &ifr) < 0)
+ continue;
- dsi->server.sin_addr.s_addr =
- ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
- syslog(LOG_INFO, "dsi_tcp: Can't resolve hostname (%s).\n"
- "%s on interface %s will be used instead.", hostname,
+ dsi->server.sin_addr.s_addr =
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
+ LOG(log_info, logtype_default, "dsi_tcp: '%s' on interface '%s' will be used instead.",
inet_ntoa(dsi->server.sin_addr), ifr.ifr_name);
- goto iflist_done;
-
+ goto iflist_done;
}
- syslog(LOG_INFO, "dsi_tcp (Chooser will not select afp/tcp)\n\
-Check to make sure %s is in /etc/hosts and the correct domain is in\n\
-/etc/resolv.conf: %m", hostname);
+ LOG(log_info, logtype_default, "dsi_tcp (Chooser will not select afp/tcp) \
+Check to make sure %s is in /etc/hosts and the correct domain is in \
+/etc/resolv.conf: %s", hostname, strerror(errno));
iflist_done:
if (start)
- freeifacelist(start);
- }
+ freeifacelist(start);
}
- /* everything's set up. now point protocol specific functions to
- * tcp versions */
- dsi->proto_open = dsi_tcp_open;
- dsi->proto_close = dsi_tcp_close;
return 1;
}