kopia lustrzana https://gitlab.com/sane-project/backends
Add standalone daemon mode, building upon the AF-indep/IPv6 debug mode.
Reorganize code by splitting the main() function into a series of functions. Factorize common code between the old network code and the AF-indep code. There's now only one version of main().merge-requests/1/head
rodzic
ef2838234e
commit
9c6fea1943
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2008-04-06 Julien Blache <jb@jblache.org>
|
||||
* frontend/saned.c: add standalone daemon mode, building upon the
|
||||
AF-indep/IPv6 debug mode. Reorganize code by splitting the main()
|
||||
function into a series of functions. Factorize common code between
|
||||
the old network code and the AF-indep code. There's now only one
|
||||
version of main().
|
||||
* doc/saned.man: document new -a flag, reorganize manpage
|
||||
sections (separate inetd configuration under the INETD
|
||||
CONFIGURATION section).
|
||||
|
||||
2008-04-05 Stéphane Voltz <stef.dev@free.fr>
|
||||
* backend/genesys.c backend/genesys.h backend/genesys_devices.c
|
||||
backend/genesys_gl646.c backend/genesys_low.h:
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
.TH saned 8 "30 May 2004" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy"
|
||||
.TH saned 8 "6 April 2008" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy"
|
||||
.IX saned
|
||||
.SH NAME
|
||||
saned \- SANE network daemon
|
||||
.SH SYNOPSIS
|
||||
.B saned
|
||||
.RB [ -d | -s
|
||||
.RI [ n ]]
|
||||
.B [ -a | -d
|
||||
.I [ n ]
|
||||
.B | -s
|
||||
.I [ n ]
|
||||
.B ]
|
||||
.SH DESCRIPTION
|
||||
.B saned
|
||||
is the SANE (Scanner Access Now Easy) daemon that allows remote clients
|
||||
|
@ -13,6 +16,19 @@ to access image acquisition devices available on the local host.
|
|||
.SH OPTIONS
|
||||
.PP
|
||||
The
|
||||
.B -a
|
||||
flag requests that
|
||||
.B saned
|
||||
run in standalone daemon mode. In this mode,
|
||||
.B saned
|
||||
will detach from the console and run in the background, listening for incoming
|
||||
client connections;
|
||||
.B inetd
|
||||
is not required for
|
||||
.B saned
|
||||
operations in this mode.
|
||||
.PP
|
||||
The
|
||||
.B -d
|
||||
and
|
||||
.B -s
|
||||
|
@ -80,10 +96,11 @@ scan-client.somedomain.firm
|
|||
.PP
|
||||
The case of the host names does not matter, so AHost.COM is considered
|
||||
identical to ahost.com.
|
||||
|
||||
.SH INETD CONFIGURATION
|
||||
For
|
||||
.B saned
|
||||
to work properly, it is also necessary to add a configuration line to
|
||||
to work properly in its default mode of operation, it is also necessary to add
|
||||
a configuration line to
|
||||
.IR /etc/inetd.conf .
|
||||
Note that your inetd must support IPv6 if you
|
||||
want to connect to saned over IPv6 ; xinetd and openbsd-inetd are known to
|
||||
|
@ -152,7 +169,11 @@ The official IANA short name for port 6566 is "sane-port". The older name "sane"
|
|||
is now deprecated.
|
||||
|
||||
.SH "RESTRICTIONS"
|
||||
In addition to the control connection (port 6566) saned also uses a data
|
||||
In addition to the control connection (port
|
||||
.B 6566
|
||||
)
|
||||
.B saned
|
||||
also uses a data
|
||||
connection. The port of this socket is selected by the operating system and
|
||||
can't be specified by the user currently. This may be a problem if the
|
||||
connection must go through a firewall (packet filter). If you must use a packet
|
||||
|
|
701
frontend/saned.c
701
frontend/saned.c
|
@ -1,8 +1,8 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
Copyright (C) 1997 Andreas Beck
|
||||
Copyright (C) 2001 - 2004 Henning Meier-Geinitz
|
||||
Copyright (C) 2003 Julien BLACHE <jb@jblache.org>
|
||||
AF-independent + IPv6 code
|
||||
Copyright (C) 2003, 2008 Julien BLACHE <jb@jblache.org>
|
||||
AF-independent + IPv6 code, standalone mode
|
||||
|
||||
This file is part of the SANE package.
|
||||
|
||||
|
@ -76,13 +76,14 @@
|
|||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
#include <sys/wait.h>
|
||||
|
||||
#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
/*
|
||||
* This replacement poll() using select() is only designed to cover
|
||||
* our needs in main(). It should probably be extended...
|
||||
* our needs in run_standalone(). It should probably be extended...
|
||||
*/
|
||||
struct pollfd
|
||||
{
|
||||
|
@ -92,34 +93,44 @@ struct pollfd
|
|||
};
|
||||
|
||||
#define POLLIN 0x0001
|
||||
#define POLLERR 0x0002
|
||||
|
||||
int
|
||||
poll (struct pollfd *ufds, unsigned int nfds, int timeout);
|
||||
|
||||
int
|
||||
poll (struct pollfd *ufds, unsigned int nfds, int timeout)
|
||||
{
|
||||
struct pollfd *fdp;
|
||||
|
||||
fd_set fds;
|
||||
fd_set rfds;
|
||||
fd_set efds;
|
||||
struct timeval tv;
|
||||
int maxfd = 0;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* unused */
|
||||
timeout = timeout;
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000;
|
||||
|
||||
FD_ZERO (&fds);
|
||||
FD_ZERO (&rfds);
|
||||
FD_ZERO (&efds);
|
||||
|
||||
for (i = 0, fdp = ufds; i < nfds; i++, fdp++)
|
||||
{
|
||||
fdp->revents = 0;
|
||||
|
||||
if (fdp->events & POLLIN)
|
||||
{
|
||||
FD_SET (fdp->fd, &fds);
|
||||
FD_SET (fdp->fd, &rfds);
|
||||
|
||||
FD_SET (fdp->fd, &efds);
|
||||
|
||||
maxfd = (fdp->fd > maxfd) ? fdp->fd : maxfd;
|
||||
}
|
||||
}
|
||||
|
||||
maxfd++;
|
||||
|
||||
ret = select (maxfd, &fds, NULL, NULL, NULL);
|
||||
ret = select (maxfd, &rfds, NULL, &efds, &tv);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -127,14 +138,16 @@ poll (struct pollfd *ufds, unsigned int nfds, int timeout)
|
|||
for (i = 0, fdp = ufds; i < nfds; i++, fdp++)
|
||||
{
|
||||
if (fdp->events & POLLIN)
|
||||
if (FD_ISSET (fdp->fd, &fds))
|
||||
fdp->revents = POLLIN;
|
||||
if (FD_ISSET (fdp->fd, &rfds))
|
||||
fdp->revents |= POLLIN;
|
||||
|
||||
if (FD_ISSET (fdp->fd, &efds))
|
||||
fdp->revents |= POLLERR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* HAVE_SYS_POLL_H && HAVE_POLL */
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
||||
#include "../include/sane/sane.h"
|
||||
#include "../include/sane/sanei.h"
|
||||
|
@ -169,8 +182,19 @@ poll (struct pollfd *ufds, unsigned int nfds, int timeout)
|
|||
# define MAXHOSTNAMELEN 120
|
||||
#endif
|
||||
|
||||
struct saned_child {
|
||||
pid_t pid;
|
||||
struct saned_child *next;
|
||||
};
|
||||
struct saned_child *children;
|
||||
int numchildren;
|
||||
|
||||
#define SANED_CONFIG_FILE "saned.conf"
|
||||
|
||||
#define SANED_SERVICE_NAME "sane-port"
|
||||
#define SANED_SERVICE_PORT 6566
|
||||
#define SANED_SERVICE_PORT_S "6566"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u_int inuse:1; /* is this handle in use? */
|
||||
|
@ -186,6 +210,7 @@ static int can_authorize;
|
|||
static Wire wire;
|
||||
static int num_handles;
|
||||
static int debug;
|
||||
static int run_mode;
|
||||
static Handle *handle;
|
||||
static union
|
||||
{
|
||||
|
@ -220,6 +245,11 @@ static SANE_Bool log_to_syslog = SANE_TRUE;
|
|||
/* forward declarations: */
|
||||
static void process_request (Wire * w);
|
||||
|
||||
#define SANED_RUN_INETD 0
|
||||
#define SANED_RUN_DEBUG 1
|
||||
#define SANED_RUN_ALONE 2
|
||||
|
||||
|
||||
#define DBG_ERR 1
|
||||
#define DBG_WARN 2
|
||||
#define DBG_MSG 3
|
||||
|
@ -399,6 +429,7 @@ quit (int signum)
|
|||
if (handle)
|
||||
free (handle);
|
||||
DBG (DBG_WARN, "quit: exiting\n");
|
||||
if (log_to_syslog)
|
||||
closelog ();
|
||||
exit (EXIT_SUCCESS); /* This is a nowait-daemon. */
|
||||
}
|
||||
|
@ -2035,56 +2066,178 @@ process_request (Wire * w)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
|
||||
static int
|
||||
wait_child (pid_t pid, int *status, int options)
|
||||
{
|
||||
struct saned_child *c;
|
||||
struct saned_child *p = NULL;
|
||||
int ret;
|
||||
|
||||
ret = waitpid(pid, status, options);
|
||||
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
for (c = children; (c != NULL) && (c->next != NULL); p = c, c = c->next)
|
||||
{
|
||||
if (c->pid == ret)
|
||||
{
|
||||
if (c == children)
|
||||
children = c->next;
|
||||
else if (p != NULL)
|
||||
p->next = c->next;
|
||||
|
||||
free(c);
|
||||
|
||||
numchildren--;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
add_child (pid_t pid)
|
||||
{
|
||||
struct saned_child *c;
|
||||
|
||||
c = (struct saned_child *) malloc (sizeof(struct saned_child));
|
||||
|
||||
if (c == NULL)
|
||||
{
|
||||
DBG (DBG_ERR, "add_child: out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->pid = pid;
|
||||
c->next = children;
|
||||
|
||||
children = c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handle_connection (int fd)
|
||||
{
|
||||
int fd = -1;
|
||||
int on = 1;
|
||||
#ifdef TCP_NODELAY
|
||||
int level = -1;
|
||||
#endif
|
||||
|
||||
debug = DBG_WARN;
|
||||
openlog ("saned", LOG_PID | LOG_CONS, LOG_DAEMON);
|
||||
DBG (DBG_DBG, "handle_connection: processing client connection\n");
|
||||
|
||||
prog_name = strrchr (argv[0], '/');
|
||||
if (prog_name)
|
||||
++prog_name;
|
||||
else
|
||||
prog_name = argv[0];
|
||||
wire.io.fd = fd;
|
||||
|
||||
byte_order.w = 0;
|
||||
byte_order.ch = 1;
|
||||
signal (SIGALRM, quit);
|
||||
signal (SIGPIPE, quit);
|
||||
|
||||
sanei_w_init (&wire, sanei_codec_bin_init);
|
||||
wire.io.read = read;
|
||||
wire.io.write = write;
|
||||
|
||||
if (argc == 2 &&
|
||||
(strncmp (argv[1], "-d", 2) == 0 || strncmp (argv[1], "-s", 2) == 0))
|
||||
#ifdef TCP_NODELAY
|
||||
# ifdef SOL_TCP
|
||||
level = SOL_TCP;
|
||||
# else /* !SOL_TCP */
|
||||
/* Look up the protocol level in the protocols database. */
|
||||
{
|
||||
struct protoent *p;
|
||||
p = getprotobyname ("tcp");
|
||||
if (p == 0)
|
||||
{
|
||||
DBG (DBG_WARN, "handle_connection: cannot look up `tcp' protocol number");
|
||||
}
|
||||
else
|
||||
level = p->p_proto;
|
||||
}
|
||||
# endif /* SOL_TCP */
|
||||
if (level == -1
|
||||
|| setsockopt (wire.io.fd, level, TCP_NODELAY, &on, sizeof (on)))
|
||||
DBG (DBG_WARN, "handle_connection: failed to put socket in TCP_NODELAY mode (%s)",
|
||||
strerror (errno));
|
||||
#endif /* !TCP_NODELAY */
|
||||
|
||||
if (init (&wire) < 0)
|
||||
quit (0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
reset_watchdog ();
|
||||
process_request (&wire);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_client (int fd)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
DBG (DBG_DBG, "handle_client: spawning child process\n");
|
||||
|
||||
pid = fork ();
|
||||
if (pid == 0)
|
||||
{
|
||||
/* child */
|
||||
handle_connection (fd);
|
||||
}
|
||||
else if (pid > 0)
|
||||
{
|
||||
/* parent */
|
||||
add_child (pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FAILED */
|
||||
DBG (DBG_ERR, "handle_client: fork() failed: %s\n", strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bail_out (int error)
|
||||
{
|
||||
DBG (DBG_ERR, "%sbailing out, waiting for children...\n", (error) ? "FATAL ERROR; " : "");
|
||||
|
||||
while (numchildren > 0)
|
||||
wait_child (-1, NULL, 0);
|
||||
|
||||
DBG (DBG_ERR, "bail_out: all children exited\n");
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sig_int_term_handler (int signum);
|
||||
|
||||
void
|
||||
sig_int_term_handler (int signum)
|
||||
{
|
||||
/* unused */
|
||||
signum = signum;
|
||||
|
||||
signal (SIGINT, NULL);
|
||||
signal (SIGTERM, NULL);
|
||||
|
||||
bail_out (0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
static void
|
||||
do_bindings (int *nfds, struct pollfd **fds)
|
||||
{
|
||||
/* don't operate in daemon mode: wait for connection request: */
|
||||
struct addrinfo *res;
|
||||
struct addrinfo *resp;
|
||||
struct addrinfo hints;
|
||||
struct pollfd *fds = NULL;
|
||||
struct pollfd *fdp = NULL;
|
||||
int nfds;
|
||||
int err;
|
||||
int i;
|
||||
short sane_port;
|
||||
int family;
|
||||
int fd = -1;
|
||||
int on = 1;
|
||||
|
||||
if (argv[1][2])
|
||||
debug = atoi (argv[1] + 2);
|
||||
if (strncmp (argv[1], "-d", 2) == 0)
|
||||
log_to_syslog = SANE_FALSE;
|
||||
|
||||
DBG (DBG_WARN, "main: starting debug mode (level %d)\n", debug);
|
||||
|
||||
DBG (DBG_DBG,
|
||||
"main: trying to get port for service `sane-port' (getaddrinfo)\n");
|
||||
DBG (DBG_DBG, "do_bindings: trying to get port for service \"%s\" (getaddrinfo)\n", SANED_SERVICE_NAME);
|
||||
|
||||
memset (&hints, 0, sizeof (struct addrinfo));
|
||||
|
||||
|
@ -2092,34 +2245,33 @@ main (int argc, char *argv[])
|
|||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
err = getaddrinfo (NULL, "sane-port", &hints, &res);
|
||||
err = getaddrinfo (NULL, SANED_SERVICE_NAME, &hints, &res);
|
||||
if (err)
|
||||
{
|
||||
DBG (DBG_WARN, "main: \"sane-port\" service unknown on your host; you should add\n");
|
||||
DBG (DBG_WARN, "main: sane-port 6566/tcp saned # SANE network scanner daemon\n");
|
||||
DBG (DBG_WARN, "main: to your /etc/services file (or equivalent). Proceeding anyway.\n");
|
||||
err = getaddrinfo (NULL, "6566", &hints, &res);
|
||||
DBG (DBG_WARN, "do_bindings: \" %s \" service unknown on your host; you should add\n", SANED_SERVICE_NAME);
|
||||
DBG (DBG_WARN, "do_bindings: %s %d/tcp saned # SANE network scanner daemon\n", SANED_SERVICE_NAME, SANED_SERVICE_PORT);
|
||||
DBG (DBG_WARN, "do_bindings: to your /etc/services file (or equivalent). Proceeding anyway.\n");
|
||||
err = getaddrinfo (NULL, SANED_SERVICE_PORT_S, &hints, &res);
|
||||
if (err)
|
||||
{
|
||||
DBG (DBG_ERR, "main: getaddrinfo() failed even with numeric port: %s\n",
|
||||
gai_strerror (err));
|
||||
exit (1);
|
||||
DBG (DBG_ERR, "do_bindings: getaddrinfo() failed even with numeric port: %s\n", gai_strerror (err));
|
||||
bail_out (1);
|
||||
}
|
||||
}
|
||||
|
||||
for (resp = res, nfds = 0; resp != NULL; resp = resp->ai_next, nfds++)
|
||||
for (resp = res, *nfds = 0; resp != NULL; resp = resp->ai_next, (*nfds)++)
|
||||
;
|
||||
|
||||
fds = malloc (nfds * sizeof (struct pollfd));
|
||||
*fds = malloc (*nfds * sizeof (struct pollfd));
|
||||
|
||||
if (fds == NULL)
|
||||
{
|
||||
DBG (DBG_ERR, "main: not enough memory for fds\n");
|
||||
DBG (DBG_ERR, "do_bindings: not enough memory for fds\n");
|
||||
freeaddrinfo (res);
|
||||
exit (1);
|
||||
bail_out (1);
|
||||
}
|
||||
|
||||
for (resp = res, i = 0, fdp = fds; resp != NULL; resp = resp->ai_next, i++, fdp++)
|
||||
for (resp = res, i = 0, fdp = *fds; resp != NULL; resp = resp->ai_next, i++, fdp++)
|
||||
{
|
||||
if (resp->ai_family == AF_INET)
|
||||
{
|
||||
|
@ -2136,28 +2288,26 @@ main (int argc, char *argv[])
|
|||
else
|
||||
{
|
||||
fdp--;
|
||||
nfds--;
|
||||
(*nfds)--;
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG (DBG_DBG, "main: [%d] socket () using IPv%d\n", i, family);
|
||||
DBG (DBG_DBG, "do_bindings: [%d] socket () using IPv%d\n", i, family);
|
||||
if ((fd = socket (resp->ai_family, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: [%d] socket failed: %s\n", i,
|
||||
strerror (errno));
|
||||
DBG (DBG_ERR, "do_bindings: [%d] socket failed: %s\n", i, strerror (errno));
|
||||
|
||||
nfds--;
|
||||
fdp--;
|
||||
(*nfds)--;
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG (DBG_DBG, "main: [%d] setsockopt ()\n", i);
|
||||
DBG (DBG_DBG, "do_bindings: [%d] setsockopt ()\n", i);
|
||||
if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
|
||||
DBG (DBG_ERR, "main: [%d] failed to put socket in SO_REUSEADDR mode (%s)\n",
|
||||
i, strerror (errno));
|
||||
DBG (DBG_ERR, "do_bindings: [%d] failed to put socket in SO_REUSEADDR mode (%s)\n", i, strerror (errno));
|
||||
|
||||
|
||||
DBG (DBG_DBG, "main: [%d] bind () to port %d\n", i, sane_port);
|
||||
DBG (DBG_DBG, "do_bindings: [%d] bind () to port %d\n", i, sane_port);
|
||||
if (bind (fd, resp->ai_addr, resp->ai_addrlen) < 0)
|
||||
{
|
||||
/*
|
||||
|
@ -2168,20 +2318,25 @@ main (int argc, char *argv[])
|
|||
* is not functional on this machine.
|
||||
* In any case, a bind() call returning an error is not necessarily fatal.
|
||||
*/
|
||||
DBG (DBG_ERR, "main: [%d] bind failed: %s\n", i, strerror (errno));
|
||||
DBG (DBG_WARN, "do_bindings: [%d] bind failed: %s\n", i, strerror (errno));
|
||||
|
||||
close (fd);
|
||||
|
||||
nfds--;
|
||||
fdp--;
|
||||
(*nfds)--;
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG (DBG_DBG, "main: [%d] listen ()\n", i);
|
||||
DBG (DBG_DBG, "do_bindings: [%d] listen ()\n", i);
|
||||
if (listen (fd, 1) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: [%d] listen failed: %s\n", i, strerror (errno));
|
||||
exit (1);
|
||||
DBG (DBG_ERR, "do_bindings: [%d] listen failed: %s\n", i, strerror (errno));
|
||||
|
||||
close (fd);
|
||||
|
||||
fdp--;
|
||||
(*nfds)--;
|
||||
continue;
|
||||
}
|
||||
|
||||
fdp->fd = fd;
|
||||
|
@ -2191,121 +2346,212 @@ main (int argc, char *argv[])
|
|||
resp = NULL;
|
||||
freeaddrinfo (res);
|
||||
|
||||
if (nfds <= 0)
|
||||
if (*nfds <= 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: couldn't bind an address. Exiting.\n");
|
||||
DBG (DBG_ERR, "do_bindings: couldn't bind an address. Exiting.\n");
|
||||
bail_out (1);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !SANED_USES_AF_INDEP */
|
||||
|
||||
static void
|
||||
do_bindings (int *nfds, struct pollfd **fds)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
struct servent *serv;
|
||||
short port;
|
||||
int fd = -1;
|
||||
int on = 1;
|
||||
|
||||
DBG (DBG_DBG, "do_bindings: trying to get port for service \"%s\" (getservbyname)\n", SANED_SERVICE_PORT);
|
||||
serv = getservbyname (SANED_SERVICE_NAME, "tcp");
|
||||
|
||||
if (serv)
|
||||
{
|
||||
port = serv->s_port;
|
||||
DBG (DBG_MSG, "main: port is %d\n", ntohs (port));
|
||||
}
|
||||
else
|
||||
{
|
||||
port = htons (SANED_SERVICE_PORT);
|
||||
DBG (DBG_WARN, "do_bindings: \"%s\" service unknown on your host; you should add\n", SANED_SERVICE_NAME);
|
||||
DBG (DBG_WARN, "do_bindings: %s %d/tcp saned # SANE network scanner daemon\n", SANED_SERVICE_NAME, SANED_SERVICE_PORT);
|
||||
DBG (DBG_WARN, "do_bindings: to your /etc/services file (or equivalent). Proceeding anyway.\n");
|
||||
}
|
||||
|
||||
*nfds = 1;
|
||||
*fds = malloc (*nfds * sizeof (struct pollfd));
|
||||
|
||||
if (fds == NULL)
|
||||
{
|
||||
DBG (DBG_ERR, "do_bindings: not enough memory for fds\n");
|
||||
bail_out (1);
|
||||
}
|
||||
|
||||
memset (&sin, 0, sizeof (sin));
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
sin.sin_port = port;
|
||||
|
||||
DBG (DBG_DBG, "do_bindings: socket ()\n");
|
||||
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
DBG (DBG_DBG, "do_bindings: setsockopt ()\n");
|
||||
if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
|
||||
DBG (DBG_ERR, "do_bindings: failed to put socket in SO_REUSEADDR mode (%s)", strerror (errno));
|
||||
|
||||
DBG (DBG_DBG, "do_bindings: bind ()\n");
|
||||
if (bind (fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "do_bindings: bind failed: %s", strerror (errno));
|
||||
bail_out (1);
|
||||
}
|
||||
|
||||
DBG (DBG_DBG, "do_bindings: listen ()\n");
|
||||
if (listen (fd, 1) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "do_bindings: listen failed: %s", strerror (errno));
|
||||
bail_out (1);
|
||||
}
|
||||
|
||||
(*fds)->fd = fd;
|
||||
(*fds)->events = POLLIN;
|
||||
}
|
||||
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
||||
|
||||
static void
|
||||
run_standalone (int argc, char **argv)
|
||||
{
|
||||
struct pollfd *fds = NULL;
|
||||
struct pollfd *fdp = NULL;
|
||||
int nfds;
|
||||
int fd;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Unused in this function */
|
||||
argc = argc;
|
||||
argv = argv;
|
||||
|
||||
do_bindings (&nfds, &fds);
|
||||
|
||||
if (run_mode != SANED_RUN_DEBUG)
|
||||
{
|
||||
DBG (DBG_MSG, "run_standalone: daemonizing now\n");
|
||||
|
||||
if (daemon (0, 0) != 0)
|
||||
{
|
||||
DBG (DBG_ERR, "FATAL ERROR: cannot daemonize: %s\n", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
DBG (DBG_MSG, "main: waiting for control connection\n");
|
||||
signal(SIGINT, sig_int_term_handler);
|
||||
signal(SIGTERM, sig_int_term_handler);
|
||||
}
|
||||
|
||||
DBG (DBG_MSG, "run_standalone: waiting for control connection\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (poll (fds, nfds, -1) < 0)
|
||||
ret = poll (fds, nfds, 500);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
DBG (DBG_ERR, "main: poll failed: %s\n", strerror (errno));
|
||||
DBG (DBG_ERR, "run_standalone: poll failed: %s\n", strerror (errno));
|
||||
free (fds);
|
||||
exit (1);
|
||||
bail_out (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for children */
|
||||
while (wait_child (-1, NULL, WNOHANG) > 0)
|
||||
;
|
||||
|
||||
if (ret == 0)
|
||||
continue;
|
||||
|
||||
for (i = 0, fdp = fds; i < nfds; i++, fdp++)
|
||||
{
|
||||
/* Error on an fd */
|
||||
if (! (fdp->revents & POLLIN))
|
||||
continue;
|
||||
|
||||
wire.io.fd = accept (fdp->fd, 0, 0);
|
||||
if (wire.io.fd < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: accept failed: %s", strerror (errno));
|
||||
for (i = 0, fdp = fds; i < nfds; i++, fdp++)
|
||||
close (fdp->fd);
|
||||
|
||||
free (fds);
|
||||
exit (1);
|
||||
|
||||
DBG (DBG_WARN, "run_standalone: invalid fd in set, attempting to re-bind\n");
|
||||
|
||||
/* Reopen sockets */
|
||||
do_bindings (&nfds, &fds);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fd = accept (fdp->fd, 0, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "run_standalone: accept failed: %s", strerror (errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (run_mode == SANED_RUN_DEBUG)
|
||||
{
|
||||
handle_connection (fd);
|
||||
break;
|
||||
}
|
||||
else
|
||||
handle_client (fd);
|
||||
}
|
||||
|
||||
if (run_mode == SANED_RUN_DEBUG)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0, fdp = fds; i < nfds; i++, fdp++)
|
||||
close (fdp->fd);
|
||||
|
||||
free (fds);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* use filedescriptor opened by inetd: */
|
||||
#ifdef HAVE_OS2_H
|
||||
|
||||
static void
|
||||
run_inetd (int argc, char **argv)
|
||||
{
|
||||
int fd = 1;
|
||||
|
||||
#ifndef HAVE_OS2_H
|
||||
/* Unused in this function */
|
||||
argc = argc;
|
||||
argv = argv;
|
||||
|
||||
#else
|
||||
/* under OS/2, the socket handle is passed as argument on the command
|
||||
line; the socket handle is relative to IBM TCP/IP, so a call
|
||||
to impsockethandle() is required to add it to the EMX runtime */
|
||||
if (argc == 2)
|
||||
{
|
||||
wire.io.fd = _impsockhandle (atoi (argv[1]), 0);
|
||||
if (wire.io.fd == -1)
|
||||
fd = _impsockhandle (atoi (argv[1]), 0);
|
||||
if (fd == -1)
|
||||
perror ("impsockhandle");
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_OS2_H */
|
||||
wire.io.fd = 1;
|
||||
|
||||
signal (SIGALRM, quit);
|
||||
signal (SIGPIPE, quit);
|
||||
|
||||
#ifdef TCP_NODELAY
|
||||
# ifdef SOL_TCP
|
||||
level = SOL_TCP;
|
||||
# else /* !SOL_TCP */
|
||||
/* Look up the protocol level in the protocols database. */
|
||||
{
|
||||
struct protoent *p;
|
||||
p = getprotobyname ("tcp");
|
||||
if (p == 0)
|
||||
{
|
||||
DBG (DBG_WARN, "main: cannot look up `tcp' protocol number");
|
||||
}
|
||||
else
|
||||
level = p->p_proto;
|
||||
}
|
||||
# endif /* SOL_TCP */
|
||||
if (level == -1
|
||||
|| setsockopt (wire.io.fd, level, TCP_NODELAY, &on, sizeof (on)))
|
||||
DBG (DBG_WARN, "main: failed to put socket in TCP_NODELAY mode (%s)",
|
||||
strerror (errno));
|
||||
#endif /* !TCP_NODELAY */
|
||||
|
||||
/* define the version string depending on which network code is used */
|
||||
#ifdef ENABLE_IPV6
|
||||
DBG (DBG_WARN, "saned (AF-indep+IPv6) from %s ready\n", PACKAGE_STRING);
|
||||
#else
|
||||
DBG (DBG_WARN, "saned (AF-indep) from %s ready\n", PACKAGE_STRING);
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
if (init (&wire) < 0)
|
||||
quit (0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
reset_watchdog ();
|
||||
process_request (&wire);
|
||||
}
|
||||
handle_connection(fd);
|
||||
}
|
||||
|
||||
#else /* !SANED_USES_AF_INDEP */
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int fd, on = 1;
|
||||
#ifdef TCP_NODELAY
|
||||
int level = -1;
|
||||
#endif
|
||||
|
||||
debug = DBG_WARN;
|
||||
openlog ("saned", LOG_PID | LOG_CONS, LOG_DAEMON);
|
||||
|
||||
prog_name = strrchr (argv[0], '/');
|
||||
if (prog_name)
|
||||
|
@ -2313,6 +2559,33 @@ main (int argc, char *argv[])
|
|||
else
|
||||
prog_name = argv[0];
|
||||
|
||||
numchildren = 0;
|
||||
run_mode = SANED_RUN_INETD;
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
if (strncmp (argv[1], "-a", 2) == 0)
|
||||
run_mode = SANED_RUN_ALONE;
|
||||
else if (strncmp (argv[1], "-d", 2) == 0)
|
||||
{
|
||||
run_mode = SANED_RUN_DEBUG;
|
||||
log_to_syslog = SANE_FALSE;
|
||||
}
|
||||
else if (strncmp (argv[1], "-s", 2) == 0)
|
||||
run_mode = SANED_RUN_DEBUG;
|
||||
}
|
||||
|
||||
if (run_mode == SANED_RUN_DEBUG)
|
||||
{
|
||||
if (argv[1][2])
|
||||
debug = atoi (argv[1] + 2);
|
||||
|
||||
DBG (DBG_WARN, "main: starting debug mode (level %d)\n", debug);
|
||||
}
|
||||
|
||||
if (log_to_syslog)
|
||||
openlog ("saned", LOG_PID | LOG_CONS, LOG_DAEMON);
|
||||
|
||||
byte_order.w = 0;
|
||||
byte_order.ch = 1;
|
||||
|
||||
|
@ -2320,121 +2593,27 @@ main (int argc, char *argv[])
|
|||
wire.io.read = read;
|
||||
wire.io.write = write;
|
||||
|
||||
if (argc == 2 &&
|
||||
(strncmp (argv[1], "-d", 2) == 0 || strncmp (argv[1], "-s", 2) == 0))
|
||||
{
|
||||
/* don't operate in daemon mode: wait for connection request: */
|
||||
struct sockaddr_in sin;
|
||||
struct servent *serv;
|
||||
short port;
|
||||
|
||||
if (argv[1][2])
|
||||
debug = atoi (argv[1] + 2);
|
||||
if (strncmp (argv[1], "-d", 2) == 0)
|
||||
log_to_syslog = SANE_FALSE;
|
||||
|
||||
DBG (DBG_WARN, "main: starting debug mode (level %d)\n", debug);
|
||||
|
||||
memset (&sin, 0, sizeof (sin));
|
||||
|
||||
DBG (DBG_DBG,
|
||||
"main: trying to get port for service `sane-port' (getservbyname)\n");
|
||||
serv = getservbyname ("sane-port", "tcp");
|
||||
if (serv)
|
||||
{
|
||||
port = serv->s_port;
|
||||
DBG (DBG_MSG, "main: port is %d\n", ntohs (port));
|
||||
}
|
||||
else
|
||||
{
|
||||
port = htons (6566);
|
||||
DBG (DBG_WARN, "main: \"sane-port\" service unknown on your host; you should add\n");
|
||||
DBG (DBG_WARN, "main: sane-port 6566/tcp saned # SANE network scanner daemon\n");
|
||||
DBG (DBG_WARN, "main: to your /etc/services file (or equivalent). Proceeding anyway.\n");
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
sin.sin_port = port;
|
||||
|
||||
DBG (DBG_DBG, "main: socket ()\n");
|
||||
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
DBG (DBG_DBG, "main: setsockopt ()\n");
|
||||
if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
|
||||
DBG (DBG_ERR, "failed to put socket in SO_REUSEADDR mode (%s)",
|
||||
strerror (errno));
|
||||
|
||||
DBG (DBG_DBG, "main: bind ()\n");
|
||||
if (bind (fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: bind failed: %s", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
DBG (DBG_DBG, "main: listen ()\n");
|
||||
if (listen (fd, 1) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: listen failed: %s", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
DBG (DBG_MSG, "main: waiting for control connection\n");
|
||||
wire.io.fd = accept (fd, 0, 0);
|
||||
if (wire.io.fd < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: accept failed: %s", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
else
|
||||
/* use filedescriptor opened by inetd: */
|
||||
#ifdef HAVE_OS2_H
|
||||
/* under OS/2, the socket handle is passed as argument on the command
|
||||
line; the socket handle is relative to IBM TCP/IP, so a call
|
||||
to impsockethandle() is required to add it to the EMX runtime */
|
||||
if (argc == 2)
|
||||
{
|
||||
wire.io.fd = _impsockhandle (atoi (argv[1]), 0);
|
||||
if (wire.io.fd == -1)
|
||||
perror ("impsockhandle");
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_OS2_H */
|
||||
wire.io.fd = 1;
|
||||
|
||||
signal (SIGALRM, quit);
|
||||
signal (SIGPIPE, quit);
|
||||
|
||||
#ifdef TCP_NODELAY
|
||||
# ifdef SOL_TCP
|
||||
level = SOL_TCP;
|
||||
# else /* !SOL_TCP */
|
||||
/* Look up the protocol level in the protocols database. */
|
||||
{
|
||||
struct protoent *p;
|
||||
p = getprotobyname ("tcp");
|
||||
if (p == 0)
|
||||
{
|
||||
DBG (DBG_WARN, "main: cannot look up `tcp' protocol number");
|
||||
}
|
||||
else
|
||||
level = p->p_proto;
|
||||
}
|
||||
# endif /* SOL_TCP */
|
||||
if (level == -1
|
||||
|| setsockopt (wire.io.fd, level, TCP_NODELAY, &on, sizeof (on)))
|
||||
DBG (DBG_WARN, "main: failed to put socket in TCP_NODELAY mode (%s)",
|
||||
strerror (errno));
|
||||
#endif /* !TCP_NODELAY */
|
||||
|
||||
/* define the version string depending on which network code is used */
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
# ifdef ENABLE_IPV6
|
||||
DBG (DBG_WARN, "saned (AF-indep+IPv6) from %s starting up\n", PACKAGE_STRING);
|
||||
# else
|
||||
DBG (DBG_WARN, "saned (AF-indep) from %s starting up\n", PACKAGE_STRING);
|
||||
# endif /* ENABLE_IPV6 */
|
||||
#else
|
||||
DBG (DBG_WARN, "saned from %s ready\n", PACKAGE_STRING);
|
||||
|
||||
if (init (&wire) < 0)
|
||||
quit (0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
reset_watchdog ();
|
||||
process_request (&wire);
|
||||
}
|
||||
}
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
||||
if ((run_mode == SANED_RUN_ALONE) || (run_mode == SANED_RUN_DEBUG))
|
||||
{
|
||||
run_standalone(argc, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
run_inetd(argc, argv);
|
||||
}
|
||||
|
||||
DBG (DBG_WARN, "saned exiting\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue