kopia lustrzana https://gitlab.com/sane-project/backends
Added support for IPv6. Updated manpages. Patch from Julien BLACHE
<jb@jblache.org>.merge-requests/1/head
rodzic
e1b27e1c18
commit
088281c4e1
|
@ -2,6 +2,10 @@
|
|||
|
||||
* doc/descriptions/unsupported.desc: Added Medion MD 6228, Microtek
|
||||
ScanPort 3000, and PIE Primefilm 1800u.
|
||||
* acinclude.m4 aclocal.m4 configure configure.in backend/net.c
|
||||
backend/net.h doc/sane-net.man doc/saned.man frontend/saned.c
|
||||
include/sane/config.h.in: Added support for IPv6. Updated
|
||||
manpages. Patch from Julien BLACHE <jb@jblache.org>.
|
||||
|
||||
2003-03-28 Oliver Schirrmeister <oschirr@abm.de>
|
||||
|
||||
|
|
40
acinclude.m4
40
acinclude.m4
|
@ -12,6 +12,7 @@ dnl JAPHAR_GREP_CFLAGS(flag, cmd_if_missing, cmd_if_present)
|
|||
dnl SANE_LINKER_RPATH
|
||||
dnl SANE_CHECK_U_TYPES
|
||||
dnl SANE_CHECK_GPHOTO2
|
||||
dnl SANE_CHECK_IPV6
|
||||
dnl SANE_PROTOTYPES
|
||||
dnl AC_PROG_LIBTOOL
|
||||
dnl
|
||||
|
@ -344,6 +345,45 @@ AC_DEFUN([SANE_CHECK_GPHOTO2],
|
|||
]) fi
|
||||
])
|
||||
|
||||
#
|
||||
# Check for AF_INET6, determines whether or not to enable IPv6 support
|
||||
AC_DEFUN([SANE_CHECK_IPV6],
|
||||
[
|
||||
AC_MSG_CHECKING([whether to enable IPv6])
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
[ --enable-ipv6 enable IPv6 (with IPv4) support
|
||||
--disable-ipv6 disable IPv6 support],
|
||||
[ case "$enableval" in
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no
|
||||
;;
|
||||
*) AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([ENABLE_IPV6], 1, [Define to 1 if the system supports IPv6])
|
||||
ipv6=yes
|
||||
;;
|
||||
esac ],
|
||||
|
||||
AC_TRY_COMPILE([
|
||||
#define INET6
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h> ], [
|
||||
/* AF_INET6 available check */
|
||||
if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
|
||||
exit(1);
|
||||
else
|
||||
exit(0);
|
||||
],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([ENABLE_IPV6], 1, [Define to 1 if the system supports IPv6])
|
||||
ipv6=yes,
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no,
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no
|
||||
))
|
||||
])
|
||||
|
||||
#
|
||||
# Generate prototypes for functions not available on the system
|
||||
AC_DEFUN([SANE_PROTOTYPES],
|
||||
|
|
|
@ -24,6 +24,7 @@ dnl JAPHAR_GREP_CFLAGS(flag, cmd_if_missing, cmd_if_present)
|
|||
dnl SANE_LINKER_RPATH
|
||||
dnl SANE_CHECK_U_TYPES
|
||||
dnl SANE_CHECK_GPHOTO2
|
||||
dnl SANE_CHECK_IPV6
|
||||
dnl SANE_PROTOTYPES
|
||||
dnl AC_PROG_LIBTOOL
|
||||
dnl
|
||||
|
@ -356,6 +357,45 @@ AC_DEFUN([SANE_CHECK_GPHOTO2],
|
|||
]) fi
|
||||
])
|
||||
|
||||
#
|
||||
# Check for AF_INET6, determines whether or not to enable IPv6 support
|
||||
AC_DEFUN([SANE_CHECK_IPV6],
|
||||
[
|
||||
AC_MSG_CHECKING([whether to enable IPv6])
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
[ --enable-ipv6 enable IPv6 (with IPv4) support
|
||||
--disable-ipv6 disable IPv6 support],
|
||||
[ case "$enableval" in
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no
|
||||
;;
|
||||
*) AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([ENABLE_IPV6], 1, [Define to 1 if the system supports IPv6])
|
||||
ipv6=yes
|
||||
;;
|
||||
esac ],
|
||||
|
||||
AC_TRY_COMPILE([
|
||||
#define INET6
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h> ], [
|
||||
/* AF_INET6 available check */
|
||||
if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
|
||||
exit(1);
|
||||
else
|
||||
exit(0);
|
||||
],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([ENABLE_IPV6], 1, [Define to 1 if the system supports IPv6])
|
||||
ipv6=yes,
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no,
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no
|
||||
))
|
||||
])
|
||||
|
||||
#
|
||||
# Generate prototypes for functions not available on the system
|
||||
AC_DEFUN([SANE_PROTOTYPES],
|
||||
|
|
485
backend/net.c
485
backend/net.c
|
@ -1,5 +1,8 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
Copyright (C) 1997 David Mosberger-Tang
|
||||
Copyright (C) 2003 Julien BLACHE <jb@jblache.org>
|
||||
AF-independent code + IPv6
|
||||
|
||||
This file is part of the SANE package.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
|
@ -40,10 +43,6 @@
|
|||
|
||||
This file implements a SANE network-based meta backend. */
|
||||
|
||||
/* Please increase version number with every change
|
||||
(don't forget to update net.desc) */
|
||||
#define NET_VERSION "1.0.10"
|
||||
|
||||
#ifdef _AIX
|
||||
# include "../include/lalloca.h" /* MUST come first for AIX! */
|
||||
#endif
|
||||
|
@ -83,15 +82,34 @@
|
|||
#include "../include/sane/sanei_config.h"
|
||||
#define NET_CONFIG_FILE "net.conf"
|
||||
|
||||
/* Please increase version number with every change
|
||||
(don't forget to update net.desc) */
|
||||
|
||||
/* define the version string depending on which network code is used */
|
||||
#if defined (HAVE_GETADDRINFO) && defined (HAVE_GETNAMEINFO)
|
||||
# define NET_USES_AF_INDEP
|
||||
# ifdef ENABLE_IPV6
|
||||
# define NET_VERSION "1.0.11 (AF-indep+IPv6)"
|
||||
# else
|
||||
# define NET_VERSION "1.0.11 (AF-indep)"
|
||||
# endif /* ENABLE_IPV6 */
|
||||
#else
|
||||
# undef ENABLE_IPV6
|
||||
# define NET_VERSION "1.0.11"
|
||||
#endif /* HAVE_GETADDRINFO && HAVE_GETNAMEINFO */
|
||||
|
||||
static SANE_Auth_Callback auth_callback;
|
||||
static Net_Device *first_device;
|
||||
static Net_Scanner *first_handle;
|
||||
static const SANE_Device **devlist;
|
||||
static int saned_port;
|
||||
static int client_big_endian; /* 1 == big endian; 0 == little endian */
|
||||
static int server_big_endian; /* 1 == big endian; 0 == little endian */
|
||||
static int depth; /* bits per pixel */
|
||||
|
||||
#ifndef NET_USES_AF_INDEP
|
||||
static int saned_port;
|
||||
#endif /* !NET_USES_AF_INDEP */
|
||||
|
||||
/* This variable is only needed, if the depth is 16bit/channel and
|
||||
client/server have different endianness. A value of -1 means, that there's
|
||||
no hang over; otherwise the value has to be casted to SANE_Byte. hang_over
|
||||
|
@ -110,6 +128,99 @@ static int hang_over;
|
|||
*/
|
||||
static int left_over;
|
||||
|
||||
|
||||
#ifdef NET_USES_AF_INDEP
|
||||
static SANE_Status
|
||||
add_device (const char *name, Net_Device ** ndp)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res;
|
||||
struct addrinfo *resp;
|
||||
struct sockaddr_in *sin;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
Net_Device *nd = NULL;
|
||||
|
||||
int error;
|
||||
short sane_port = htons (6566);
|
||||
|
||||
DBG (1, "add_device: adding backend %s\n", name);
|
||||
|
||||
memset (&hints, 0, sizeof(hints));
|
||||
|
||||
# ifdef ENABLE_IPV6
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
# else
|
||||
hints.ai_family = PF_INET;
|
||||
# endif /* ENABLE_IPV6 */
|
||||
|
||||
error = getaddrinfo (name, "sane", &hints, &res);
|
||||
if (error)
|
||||
{
|
||||
error = getaddrinfo (name, NULL, &hints, &res);
|
||||
if (error)
|
||||
{
|
||||
DBG (1, "add_device: error while getting address of host %s: %s\n",
|
||||
name, gai_strerror (error));
|
||||
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (resp = res; resp != NULL; resp = resp->ai_next)
|
||||
{
|
||||
switch (resp->ai_family)
|
||||
{
|
||||
case AF_INET:
|
||||
sin = (struct sockaddr_in *) resp->ai_addr;
|
||||
sin->sin_port = sane_port;
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *) resp->ai_addr;
|
||||
sin6->sin6_port = sane_port;
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nd = malloc (sizeof (Net_Device));
|
||||
if (!nd)
|
||||
{
|
||||
DBG (1, "add_device: not enough memory for Net_Device struct\n");
|
||||
|
||||
freeaddrinfo (res);
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
|
||||
memset (nd, 0, sizeof (Net_Device));
|
||||
nd->name = strdup (name);
|
||||
if (!nd->name)
|
||||
{
|
||||
DBG (1, "add_device: not enough memory to duplicate name\n");
|
||||
free(nd);
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
|
||||
nd->addr = res;
|
||||
nd->ctl = -1;
|
||||
|
||||
nd->next = first_device;
|
||||
|
||||
first_device = nd;
|
||||
|
||||
if (ndp)
|
||||
*ndp = nd;
|
||||
DBG (2, "add_device: backend %s added\n", name);
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
#else /* !NET_USES_AF_INDEP */
|
||||
|
||||
static SANE_Status
|
||||
add_device (const char *name, Net_Device ** ndp)
|
||||
{
|
||||
|
@ -161,6 +272,69 @@ add_device (const char *name, Net_Device ** ndp)
|
|||
DBG (2, "add_device: backend %s added\n", name);
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
#endif /* NET_USES_AF_INDEP */
|
||||
|
||||
|
||||
#ifdef NET_USES_AF_INDEP
|
||||
static SANE_Status
|
||||
connect_dev (Net_Device * dev)
|
||||
{
|
||||
struct addrinfo *addrp;
|
||||
|
||||
SANE_Word version_code;
|
||||
SANE_Init_Reply reply;
|
||||
SANE_Status status = SANE_STATUS_IO_ERROR;
|
||||
SANE_Init_Req req;
|
||||
SANE_Bool connected = SANE_FALSE;
|
||||
#ifdef TCP_NODELAY
|
||||
int on = 1;
|
||||
int level = -1;
|
||||
#endif
|
||||
|
||||
int i;
|
||||
|
||||
DBG (2, "connect_dev: trying to connect to %s\n", dev->name);
|
||||
|
||||
for (addrp = dev->addr, i = 0; (addrp != NULL) && (connected == SANE_FALSE); addrp = addrp->ai_next, i++)
|
||||
{
|
||||
# ifdef ENABLE_IPV6
|
||||
if ((addrp->ai_family != AF_INET) && (addrp->ai_family != AF_INET6))
|
||||
# else /* !ENABLE_IPV6 */
|
||||
if (addrp->ai_family != AF_INET)
|
||||
# endif /* ENABLE_IPV6 */
|
||||
{
|
||||
DBG (1, "connect_dev: [%d] don't know how to deal with addr family %d\n",
|
||||
i, addrp->ai_family);
|
||||
break;
|
||||
}
|
||||
|
||||
dev->ctl = socket (addrp->ai_family, SOCK_STREAM, 0);
|
||||
if (dev->ctl < 0)
|
||||
{
|
||||
DBG (1, "connect_dev: [%d] failed to obtain socket (%s)\n",
|
||||
i, strerror (errno));
|
||||
dev->ctl = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (connect (dev->ctl, addrp->ai_addr, addrp->ai_addrlen) < 0)
|
||||
{
|
||||
DBG (1, "connect_dev: [%d] failed to connect (%s)\n", i, strerror (errno));
|
||||
dev->ctl = -1;
|
||||
break;
|
||||
}
|
||||
DBG (3, "connect_dev: [%d] connection succeeded (%s)\n", i, (addrp->ai_family == AF_INET6) ? "IPv6" : "IPv4");
|
||||
dev->addr_used = addrp;
|
||||
connected = SANE_TRUE;
|
||||
}
|
||||
|
||||
if (connected != SANE_TRUE)
|
||||
{
|
||||
DBG (1, "connect_dev: couldn't connect to host (see messages above)\n");
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
#else /* !NET_USES_AF_INDEP */
|
||||
|
||||
static SANE_Status
|
||||
connect_dev (Net_Device * dev)
|
||||
|
@ -202,6 +376,7 @@ connect_dev (Net_Device * dev)
|
|||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
DBG (3, "connect_dev: connection succeeded\n");
|
||||
#endif /* NET_USES_AF_INDEP */
|
||||
|
||||
#ifdef TCP_NODELAY
|
||||
# ifdef SOL_TCP
|
||||
|
@ -288,6 +463,7 @@ fail:
|
|||
return status;
|
||||
}
|
||||
|
||||
|
||||
static SANE_Status
|
||||
fetch_options (Net_Scanner * s)
|
||||
{
|
||||
|
@ -444,13 +620,16 @@ SANE_Status
|
|||
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
||||
{
|
||||
char device_name[PATH_MAX];
|
||||
struct servent *serv;
|
||||
const char *env;
|
||||
size_t len;
|
||||
FILE *fp;
|
||||
short ns = 0x1234;
|
||||
unsigned char *p = (unsigned char *)(&ns);
|
||||
|
||||
#ifndef NET_USES_AF_INDEP
|
||||
struct servent *serv;
|
||||
#endif /* !NET_USES_AF_INDEP */
|
||||
|
||||
DBG_INIT ();
|
||||
|
||||
DBG (2, "sane_init: authorize = %p, version_code = %p\n", authorize,
|
||||
|
@ -484,6 +663,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|||
DBG (3, "sane_init: Client has little endian byte order\n");
|
||||
}
|
||||
|
||||
#ifndef NET_USES_AF_INDEP
|
||||
DBG (2, "sane_init: determining sane service port\n");
|
||||
serv = getservbyname ("sane", "tcp");
|
||||
|
||||
|
@ -498,6 +678,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|||
DBG (1, "sane_init: could not find `sane' service (%s); using default "
|
||||
"port %d\n", strerror (errno), ntohs (saned_port));
|
||||
}
|
||||
#endif /* !NET_USES_AF_INDEP */
|
||||
|
||||
DBG (2, "sane_init: searching for config file\n");
|
||||
fp = sanei_config_open (NET_CONFIG_FILE);
|
||||
|
@ -533,6 +714,30 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|||
next = copy;
|
||||
while ((host = strsep (&next, ":")))
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
if (host[0] == '[')
|
||||
{
|
||||
/* skip '[' (host[0]) */
|
||||
host++;
|
||||
/* get the rest of the IPv6 addr (we're screwed if ] is missing)
|
||||
* Is it worth checking for the matching ] ? Not for now. */
|
||||
strsep (&next, "]");
|
||||
/* add back the ":" that got removed by the strsep() */
|
||||
host[strlen (host)] = ':';
|
||||
/* host now holds the IPv6 address */
|
||||
|
||||
/* skip the ':' that could be after ] (avoids a call to strsep() */
|
||||
if (next[0] == ':')
|
||||
next++;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the IPv6 is last in the list, the strsep() call in the while()
|
||||
* will return a string with the first char being '\0'. Skip it.
|
||||
*/
|
||||
if (host[0] == '\0')
|
||||
continue;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
DBG (2, "sane_init: trying to add %s\n", host);
|
||||
add_device (host, 0);
|
||||
}
|
||||
|
@ -580,6 +785,12 @@ sane_exit (void)
|
|||
}
|
||||
if (dev->name)
|
||||
free ((void *) dev->name);
|
||||
|
||||
#ifdef NET_USES_AF_INDEP
|
||||
if (dev->addr)
|
||||
freeaddrinfo(dev->addr);
|
||||
#endif /* NET_USES_AF_INDEP */
|
||||
|
||||
free (dev);
|
||||
}
|
||||
if (devlist)
|
||||
|
@ -693,11 +904,23 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
|||
{
|
||||
SANE_Device *rdev;
|
||||
char *mem;
|
||||
#ifdef ENABLE_IPV6
|
||||
SANE_Bool IPv6 = SANE_FALSE;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
/* create a new device entry with a device name that is the
|
||||
sum of the backend name a colon and the backend's device
|
||||
name: */
|
||||
len = strlen (dev->name) + 1 + strlen (reply.device_list[i]->name);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if (strchr (dev->name, ':') != NULL)
|
||||
{
|
||||
len += 2;
|
||||
IPv6 = SANE_TRUE;
|
||||
}
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
mem = malloc (sizeof (*dev) + len + 1);
|
||||
if (!mem)
|
||||
{
|
||||
|
@ -707,8 +930,22 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
|||
&reply);
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
|
||||
memset (mem, 0, sizeof (*dev) + len);
|
||||
full_name = mem + sizeof (*dev);
|
||||
strcpy (full_name, dev->name);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if (IPv6 == SANE_TRUE)
|
||||
strcat (full_name, "[");
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
strcat (full_name, dev->name);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if (IPv6 == SANE_TRUE)
|
||||
strcat (full_name, "]");
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
strcat (full_name, ":");
|
||||
strcat (full_name, reply.device_list[i]->name);
|
||||
DBG (3, "sane_get_devices: got %s\n", full_name);
|
||||
|
@ -723,11 +960,11 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
|||
{
|
||||
DBG (1, "sane_get_devices: not enough free memory\n");
|
||||
if (rdev->vendor)
|
||||
free (rdev->vendor);
|
||||
free ((void *) rdev->vendor);
|
||||
if (rdev->model)
|
||||
free (rdev->model);
|
||||
free ((void *) rdev->model);
|
||||
if (rdev->type)
|
||||
free (rdev->type);
|
||||
free ((void *) rdev->type);
|
||||
free (rdev);
|
||||
sanei_w_free (&dev->wire,
|
||||
(WireCodecFunc) sanei_w_get_devices_reply,
|
||||
|
@ -756,6 +993,10 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
|
|||
{
|
||||
SANE_Open_Reply reply;
|
||||
const char *dev_name;
|
||||
#ifdef ENABLE_IPV6
|
||||
const char *tmp_name;
|
||||
SANE_Bool v6addr = SANE_FALSE;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
SANE_String nd_name;
|
||||
SANE_Status status;
|
||||
SANE_Word handle;
|
||||
|
@ -764,12 +1005,46 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
|
|||
int need_auth;
|
||||
|
||||
DBG (3, "sane_open(\"%s\")\n", full_name);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
/*
|
||||
* Check whether a numerical IPv6 host was specified
|
||||
* [2001:42:42::12] <== check for '[' as full_name[0]
|
||||
* ex: [2001:42:42::12]:test:0 (syntax taken from Apache 2)
|
||||
*/
|
||||
if (full_name[0] == '[')
|
||||
{
|
||||
v6addr = SANE_TRUE;
|
||||
tmp_name = strchr (full_name, ']');
|
||||
if (!tmp_name)
|
||||
{
|
||||
DBG (1, "sane_open: incorrect host address: missing matching ']'\n");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
tmp_name = full_name;
|
||||
|
||||
dev_name = strchr (tmp_name, ':');
|
||||
#else /* !ENABLE_IPV6 */
|
||||
|
||||
dev_name = strchr (full_name, ':');
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
dev_name = strchr (full_name, ':');
|
||||
if (dev_name)
|
||||
{
|
||||
#ifdef strndupa
|
||||
# ifdef ENABLE_IPV6
|
||||
if (v6addr == SANE_TRUE)
|
||||
nd_name = strndupa (full_name + 1, dev_name - full_name - 2);
|
||||
else
|
||||
nd_name = strndupa (full_name, dev_name - full_name);
|
||||
|
||||
# else /* !ENABLE_IPV6 */
|
||||
|
||||
nd_name = strndupa (full_name, dev_name - full_name);
|
||||
# endif /* ENABLE_IPV6 */
|
||||
|
||||
if (!nd_name)
|
||||
{
|
||||
DBG (1, "sane_open: not enough free memory\n");
|
||||
|
@ -778,14 +1053,41 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
|
|||
#else
|
||||
char *tmp;
|
||||
|
||||
# ifdef ENABLE_IPV6
|
||||
if (v6addr == SANE_TRUE)
|
||||
tmp = alloca (dev_name - full_name - 2 + 1);
|
||||
else
|
||||
tmp = alloca (dev_name - full_name + 1);
|
||||
|
||||
# else /* !ENABLE_IPV6 */
|
||||
|
||||
tmp = alloca (dev_name - full_name + 1);
|
||||
# endif /* ENABLE_IPV6 */
|
||||
|
||||
if (!tmp)
|
||||
{
|
||||
DBG (1, "sane_open: not enough free memory\n");
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
|
||||
# ifdef ENABLE_IPV6
|
||||
if (v6addr == SANE_TRUE)
|
||||
{
|
||||
memcpy (tmp, full_name + 1, dev_name - full_name - 2);
|
||||
tmp[dev_name - full_name - 2] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (tmp, full_name, dev_name - full_name);
|
||||
tmp[dev_name - full_name] = '\0';
|
||||
}
|
||||
|
||||
# else /* !ENABLE_IPV6 */
|
||||
|
||||
memcpy (tmp, full_name, dev_name - full_name);
|
||||
tmp[dev_name - full_name] = '\0';
|
||||
# endif /* ENABLE_IPV6 */
|
||||
|
||||
nd_name = tmp;
|
||||
#endif
|
||||
++dev_name; /* skip colon */
|
||||
|
@ -795,7 +1097,26 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
|
|||
/* if no colon interpret full_name as the host name; an empty
|
||||
device name will cause us to open the first device of that
|
||||
host. */
|
||||
#ifdef ENABLE_IPV6
|
||||
if (v6addr == SANE_TRUE)
|
||||
{
|
||||
nd_name = alloca (strlen (full_name) - 2 + 1);
|
||||
if (!nd_name)
|
||||
{
|
||||
DBG (1, "sane_open: not enough free memory\n");
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
memcpy (nd_name, full_name + 1, strlen (full_name) - 2);
|
||||
nd_name[strlen (full_name) - 2] = '\0';
|
||||
}
|
||||
else
|
||||
nd_name = (char *) full_name;
|
||||
|
||||
#else /* !ENABLE_IPV6 */
|
||||
|
||||
nd_name = (char *) full_name;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
dev_name = "";
|
||||
}
|
||||
DBG (2, "sane_open: host = %s, device = %s\n", nd_name, dev_name);
|
||||
|
@ -1136,6 +1457,146 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
|
|||
return status;
|
||||
}
|
||||
|
||||
#ifdef NET_USES_AF_INDEP
|
||||
SANE_Status
|
||||
sane_start (SANE_Handle handle)
|
||||
{
|
||||
Net_Scanner *s = handle;
|
||||
SANE_Start_Reply reply;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr *sa;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 sin6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
SANE_Status status;
|
||||
int fd, need_auth;
|
||||
socklen_t len;
|
||||
u_int16_t port; /* Internet-specific */
|
||||
|
||||
|
||||
DBG (3, "sane_start\n");
|
||||
|
||||
hang_over = -1;
|
||||
left_over = -1;
|
||||
|
||||
if (s->data >= 0)
|
||||
{
|
||||
DBG (2, "sane_start: data pipe already exists\n");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
/* Do this ahead of time so in case anything fails, we can
|
||||
recover gracefully (without hanging our server). */
|
||||
|
||||
switch (s->hw->addr_used->ai_family)
|
||||
{
|
||||
case AF_INET:
|
||||
len = sizeof (sin);
|
||||
sa = (struct sockaddr *) &sin;
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
len = sizeof (sin6);
|
||||
sa = (struct sockaddr *) &sin6;
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
default:
|
||||
DBG (1, "sane_start: unknown address family : %d\n",
|
||||
s->hw->addr_used->ai_family);
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
if (getpeername (s->hw->ctl, sa, &len) < 0)
|
||||
{
|
||||
DBG (1, "sane_start: getpeername() failed (%s)\n", strerror (errno));
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
fd = socket (s->hw->addr_used->ai_family, SOCK_STREAM, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
DBG (1, "sane_start: socket() failed (%s)\n", strerror (errno));
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
DBG (3, "sane_start: remote start\n");
|
||||
sanei_w_call (&s->hw->wire, SANE_NET_START,
|
||||
(WireCodecFunc) sanei_w_word, &s->handle,
|
||||
(WireCodecFunc) sanei_w_start_reply, &reply);
|
||||
do
|
||||
{
|
||||
status = reply.status;
|
||||
port = reply.port;
|
||||
if (reply.byte_order == 0x1234)
|
||||
{
|
||||
server_big_endian = 0;
|
||||
DBG (1, "sane_start: server has little endian byte order\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
server_big_endian = 1;
|
||||
DBG (1, "sane_start: server has big endian byte order\n");
|
||||
}
|
||||
|
||||
need_auth = (reply.resource_to_authorize != 0);
|
||||
if (need_auth)
|
||||
{
|
||||
DBG (3, "sane_start: auth required\n");
|
||||
do_authorization (s->hw, reply.resource_to_authorize);
|
||||
|
||||
sanei_w_free (&s->hw->wire,
|
||||
(WireCodecFunc) sanei_w_start_reply, &reply);
|
||||
|
||||
sanei_w_set_dir (&s->hw->wire, WIRE_DECODE);
|
||||
|
||||
sanei_w_start_reply (&s->hw->wire, &reply);
|
||||
|
||||
continue;
|
||||
}
|
||||
sanei_w_free (&s->hw->wire, (WireCodecFunc) sanei_w_start_reply,
|
||||
&reply);
|
||||
if (need_auth && !s->hw->auth_active)
|
||||
return SANE_STATUS_CANCELLED;
|
||||
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (1, "sane_start: remote start failed (%s)\n",
|
||||
sane_strstatus (status));
|
||||
close (fd);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
while (need_auth);
|
||||
DBG (3, "sane_start: remote start finished, data at port %hu\n", port);
|
||||
|
||||
switch (s->hw->addr_used->ai_family)
|
||||
{
|
||||
case AF_INET:
|
||||
sin.sin_port = htons (port);
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
sin6.sin6_port = htons (port);
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
}
|
||||
|
||||
if (connect (fd, sa, len) < 0)
|
||||
{
|
||||
DBG (1, "sane_start: connect() failed (%s)\n", strerror (errno));
|
||||
close (fd);
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
shutdown (fd, 1);
|
||||
s->data = fd;
|
||||
s->reclen_buf_offset = 0;
|
||||
s->bytes_remaining = 0;
|
||||
DBG (3, "sane_start: done (%s)\n", sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
#else /* !NET_USES_AF_INDEP */
|
||||
|
||||
SANE_Status
|
||||
sane_start (SANE_Handle handle)
|
||||
{
|
||||
|
@ -1240,6 +1701,8 @@ sane_start (SANE_Handle handle)
|
|||
DBG (3, "sane_start: done (%s)\n", sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
#endif /* NET_USES_AF_INDEP */
|
||||
|
||||
|
||||
SANE_Status
|
||||
sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
Copyright (C) 1997 David Mosberger-Tang
|
||||
Copyright (C) 2003 Julien BLACHE <jb@jblache.org>
|
||||
AF-independent code + IPv6
|
||||
|
||||
This file is part of the SANE package.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
|
@ -44,12 +47,18 @@
|
|||
#include <sys/socket.h>
|
||||
|
||||
#include "../include/sane/sanei_wire.h"
|
||||
#include "../include/sane/config.h"
|
||||
|
||||
typedef struct Net_Device
|
||||
{
|
||||
struct Net_Device *next;
|
||||
const char *name;
|
||||
#if defined (HAVE_GETADDRINFO) && defined (HAVE_GETNAMEINFO)
|
||||
struct addrinfo *addr;
|
||||
struct addrinfo *addr_used;
|
||||
#else
|
||||
struct sockaddr addr;
|
||||
#endif /* HAVE_GETADDRINFO && HAVE_GETNAMEINFO */
|
||||
int ctl; /* socket descriptor (or -1) */
|
||||
Wire wire;
|
||||
int auth_active;
|
||||
|
|
|
@ -1011,6 +1011,8 @@ Optional Features:
|
|||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||
--enable-warnings turn on tons of compiler warnings (GCC only)
|
||||
--enable-ipv6 enable IPv6 (with IPv4) support
|
||||
--disable-ipv6 disable IPv6 support
|
||||
--enable-static=PKGS build static libraries default=no
|
||||
--enable-shared=PKGS build shared libraries default=yes
|
||||
--enable-fast-install=PKGS optimize for fast installation default=yes
|
||||
|
@ -8013,9 +8015,12 @@ rm -f conftest.mmap
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
for ac_func in atexit inet_addr inet_aton inet_ntoa ioperm mkdir \
|
||||
scsireq_enter strftime strstr strtod \
|
||||
cfmakeraw tcsendbreak strcasecmp strncasecmp _portaccess
|
||||
cfmakeraw tcsendbreak strcasecmp strncasecmp _portaccess \
|
||||
getaddrinfo getnameinfo
|
||||
do
|
||||
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
echo "$as_me:$LINENO: checking for $ac_func" >&5
|
||||
|
@ -8298,6 +8303,90 @@ _ACEOF
|
|||
|
||||
fi
|
||||
|
||||
if test "$ac_cv_func_getnameinfo" = "yes" && test "$ac_cv_func_getaddrinfo" = "yes" ; then
|
||||
|
||||
echo "$as_me:$LINENO: checking whether to enable IPv6" >&5
|
||||
echo $ECHO_N "checking whether to enable IPv6... $ECHO_C" >&6
|
||||
# Check whether --enable-ipv6 or --disable-ipv6 was given.
|
||||
if test "${enable_ipv6+set}" = set; then
|
||||
enableval="$enable_ipv6"
|
||||
case "$enableval" in
|
||||
no)
|
||||
echo "$as_me:$LINENO: result: no" >&5
|
||||
echo "${ECHO_T}no" >&6
|
||||
ipv6=no
|
||||
;;
|
||||
*) echo "$as_me:$LINENO: result: yes" >&5
|
||||
echo "${ECHO_T}yes" >&6
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define ENABLE_IPV6 1
|
||||
_ACEOF
|
||||
|
||||
ipv6=yes
|
||||
;;
|
||||
esac
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line $LINENO "configure"
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
#define INET6
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
/* AF_INET6 available check */
|
||||
if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
|
||||
exit(1);
|
||||
else
|
||||
exit(0);
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } &&
|
||||
{ ac_try='test -s conftest.$ac_objext'
|
||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; }; then
|
||||
echo "$as_me:$LINENO: result: yes" >&5
|
||||
echo "${ECHO_T}yes" >&6
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define ENABLE_IPV6 1
|
||||
_ACEOF
|
||||
|
||||
ipv6=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
echo "$as_me:$LINENO: result: no" >&5
|
||||
echo "${ECHO_T}no" >&6
|
||||
ipv6=no
|
||||
fi
|
||||
rm -f conftest.$ac_objext conftest.$ac_ext
|
||||
fi;
|
||||
|
||||
else
|
||||
ipv6="no"
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-static or --disable-static was given.
|
||||
if test "${enable_static+set}" = set; then
|
||||
|
@ -9475,7 +9564,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
|
|||
case $host in
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 9478 "configure"' > conftest.$ac_ext
|
||||
echo '#line 9567 "configure"' > conftest.$ac_ext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
|
@ -10004,7 +10093,7 @@ chmod -w .
|
|||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
|
||||
compiler_c_o=no
|
||||
if { (eval echo configure:10007: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
|
||||
if { (eval echo configure:10096: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings
|
||||
if test -s out/conftest.err; then
|
||||
|
@ -11836,7 +11925,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 11839 "configure"
|
||||
#line 11928 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -11934,7 +12023,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 11937 "configure"
|
||||
#line 12026 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -14026,6 +14115,8 @@ echo "Configuration: `eval eval echo ${sysconfdir}`"
|
|||
echo "Libraries: `eval eval echo ${libdir}`"
|
||||
echo "Binaries: `eval eval echo ${bindir}` and `eval eval echo ${sbindir}`"
|
||||
echo "Manpages: `eval eval echo ${mandir}`"
|
||||
echo "Network parameters:"
|
||||
echo "IPv6 support: `eval eval echo ${ipv6}`"
|
||||
|
||||
if test "$SANE_CONFIG_PATH" != "no" ; then
|
||||
SANE_INSTALLED_VERSION=`$SANE_CONFIG_PATH --version`
|
||||
|
|
12
configure.in
12
configure.in
|
@ -180,7 +180,8 @@ AC_FUNC_ALLOCA
|
|||
AC_FUNC_MMAP
|
||||
AC_CHECK_FUNCS(atexit inet_addr inet_aton inet_ntoa ioperm mkdir \
|
||||
scsireq_enter strftime strstr strtod \
|
||||
cfmakeraw tcsendbreak strcasecmp strncasecmp _portaccess)
|
||||
cfmakeraw tcsendbreak strcasecmp strncasecmp _portaccess \
|
||||
getaddrinfo getnameinfo)
|
||||
AC_REPLACE_FUNCS(getenv inet_ntop inet_pton isfdtype sigprocmask snprintf \
|
||||
strdup strndup strsep usleep vsyslog)
|
||||
SANE_PROTOTYPES
|
||||
|
@ -208,6 +209,13 @@ if sparc64 -q > /dev/null 2>&1 ; then
|
|||
AC_DEFINE(DISABLE_LINUX_SG_IO, 1, [Should we disable SCSI generic v3?])
|
||||
fi
|
||||
|
||||
dnl check for IPv6 (can be overriden by --enable-ipv6)
|
||||
if test "$ac_cv_func_getnameinfo" = "yes" && test "$ac_cv_func_getaddrinfo" = "yes" ; then
|
||||
SANE_CHECK_IPV6
|
||||
else
|
||||
ipv6="no"
|
||||
fi
|
||||
|
||||
dnl ***********************************************************************
|
||||
dnl initialize libtool
|
||||
dnl ***********************************************************************
|
||||
|
@ -433,6 +441,8 @@ echo "Configuration: `eval eval echo ${sysconfdir}`"
|
|||
echo "Libraries: `eval eval echo ${libdir}`"
|
||||
echo "Binaries: `eval eval echo ${bindir}` and `eval eval echo ${sbindir}`"
|
||||
echo "Manpages: `eval eval echo ${mandir}`"
|
||||
echo "Network parameters:"
|
||||
echo "IPv6 support: `eval eval echo ${ipv6}`"
|
||||
|
||||
if test "$SANE_CONFIG_PATH" != "no" ; then
|
||||
SANE_INSTALLED_VERSION=`$SANE_CONFIG_PATH --version`
|
||||
|
|
|
@ -20,7 +20,7 @@ This backend expects device names of the form:
|
|||
.PP
|
||||
Where
|
||||
.I host
|
||||
is the name of the (remote-) host and
|
||||
is the name (or IP address) of the (remote-) host and
|
||||
.I device
|
||||
is the name of the device on this host that should be addressed.
|
||||
If the device name does not contain a colon (:), then the entire string
|
||||
|
@ -28,35 +28,50 @@ is treated as the
|
|||
.I device
|
||||
string for the default host. The default host is the host listed last
|
||||
in the configuration file (see below).
|
||||
.PP
|
||||
An IPv6 address can be specified enclosed in square brackets:
|
||||
.PP
|
||||
.RS
|
||||
.IR [::1] : device
|
||||
.RE
|
||||
.SH CONFIGURATION
|
||||
The contents of the
|
||||
.IR net.conf .
|
||||
file is a list of host names that should be contacted for
|
||||
.IR net.conf
|
||||
file is a list of host names (or IP addresses) that should be contacted for
|
||||
scan requests. Empty lines and lines starting with a hash mark (#) are
|
||||
ignored. A sample configuration file is shown below:
|
||||
ignored. Note that IPv6 addresses in this file do not need to be enclosed
|
||||
in square brackets. A sample configuration file is shown below:
|
||||
.PP
|
||||
.RS
|
||||
scan-server.somedomain.firm
|
||||
.br
|
||||
192.168.0.1
|
||||
.br
|
||||
# this is a comment
|
||||
.br
|
||||
localhost
|
||||
.br
|
||||
::1
|
||||
.RE
|
||||
.PP
|
||||
The above list of host names can be extended at run-time using environment
|
||||
The above list of hosts can be extended at run-time using environment
|
||||
variable
|
||||
.BR SANE_NET_HOSTS .
|
||||
This environment variable is a colon-separated list of hostnames that
|
||||
should be contacted in addition to the hosts mentioned in the
|
||||
configuration file. For example, a user could set the environment
|
||||
This environment variable is a colon-separated list of hostnames or IP
|
||||
addresses that should be contacted in addition to the hosts mentioned in
|
||||
the configuration file. For example, a user could set the environment
|
||||
variable to the string:
|
||||
.PP
|
||||
.RS
|
||||
new.scanner.com:scanner.univ.edu
|
||||
new.scanner.com:[::1]:192.168.0.2:scanner.univ.edu
|
||||
.RE
|
||||
.PP
|
||||
To request that hosts
|
||||
.I new.scanner.com
|
||||
,
|
||||
.I [::1]
|
||||
,
|
||||
.I 192.168.0.2
|
||||
and
|
||||
.I scanner.univ.edu
|
||||
are contacted in addition to the hosts listed above.
|
||||
|
@ -65,7 +80,7 @@ For this backend to function properly, it is also necessary to define the
|
|||
.B sane
|
||||
service in
|
||||
.IR /etc/services .
|
||||
At present, the
|
||||
The
|
||||
.B sane
|
||||
service should be defined using a line of the following form:
|
||||
.PP
|
||||
|
@ -103,7 +118,8 @@ to "/tmp/config:" would result in directories "tmp/config", ".", and
|
|||
"@CONFIGDIR@" being searched (in this order).
|
||||
.TP
|
||||
.B SANE_NET_HOSTS
|
||||
A colon-separated list of host names to be contacted by this backend.
|
||||
A colon-separated list of host names or IP addresses to be contacted by this
|
||||
backend.
|
||||
.TP
|
||||
.B SANE_DEBUG_NET
|
||||
If the library was compiled with debug support enabled, this
|
||||
|
|
|
@ -68,15 +68,22 @@ scan-client.somedomain.firm
|
|||
# this is a comment
|
||||
.br
|
||||
192.168.0.1
|
||||
.br
|
||||
::1
|
||||
.RE
|
||||
.PP
|
||||
The case of the host names does not matter, so AHost.COM is considered
|
||||
identical to ahost.com.
|
||||
identical to ahost.com. IPv6 addresses should always be specified in their
|
||||
compressed form.
|
||||
|
||||
For
|
||||
.B saned
|
||||
to work properly, 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
|
||||
support IPv6, check the documentation for your inetd daemon.
|
||||
.PP
|
||||
The configuration line normally looks like this:
|
||||
.PP
|
||||
.RS
|
||||
|
|
757
frontend/saned.c
757
frontend/saned.c
|
@ -1,6 +1,9 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
Copyright (C) 1997 Andreas Beck
|
||||
Copyright (C) 2001, 2002 Henning Meier-Geinitz
|
||||
Copyright (C) 2003 Julien BLACHE <jb@jblache.org>
|
||||
AF-independent + IPv6 code
|
||||
|
||||
This file is part of the SANE package.
|
||||
|
||||
SANE is free software; you can redistribute it and/or modify it under
|
||||
|
@ -54,6 +57,7 @@
|
|||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -74,12 +78,26 @@
|
|||
# define IN_LOOPBACK(addr) (addr == 0x7f000001L)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
# define SANE_IN6_IS_ADDR_LOOPBACK(a) \
|
||||
(((const uint32_t *) (a))[0] == 0 \
|
||||
&& ((const uint32_t *) (a))[1] == 0 \
|
||||
&& ((const uint32_t *) (a))[2] == 0 \
|
||||
&& ((const uint32_t *) (a))[3] == htonl (1))
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
# define MAXHOSTNAMELEN 120
|
||||
#endif
|
||||
|
||||
#define SANED_CONFIG_FILE "saned.conf"
|
||||
|
||||
#if defined(HAVE_GETADDRINFO) && defined (HAVE_GETNAMEINFO)
|
||||
# define SANED_USES_AF_INDEP
|
||||
#else
|
||||
# undef ENABLE_IPV6
|
||||
#endif /* HAVE_GETADDRINFO && HAVE_GETNAMEINFO */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u_int inuse:1; /* is this handle in use? */
|
||||
|
@ -107,8 +125,14 @@ byte_order;
|
|||
it does is save a remote user some work by reducing the amount of
|
||||
text s/he has to type when authentication is requested. */
|
||||
static const char *default_username = "saned-user";
|
||||
static char *remote_hostname;
|
||||
static char *remote_ip;
|
||||
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
static struct sockaddr_storage remote_address;
|
||||
static int remote_address_len;
|
||||
#else
|
||||
static struct in_addr remote_address;
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
||||
#ifndef _PATH_HEQUIV
|
||||
# define _PATH_HEQUIV "/etc/hosts.equiv"
|
||||
|
@ -371,6 +395,300 @@ decode_handle (Wire * w, const char *op)
|
|||
}
|
||||
|
||||
/* Access control */
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
static SANE_Status
|
||||
check_host (int fd)
|
||||
{
|
||||
struct sockaddr_in *sin = NULL;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res;
|
||||
struct addrinfo *resp;
|
||||
int j, access_ok = 0;
|
||||
int err;
|
||||
char text_addr[64];
|
||||
#ifdef ENABLE_IPV6
|
||||
char *remote_ipv4 = NULL; /* in case we have an IPv4-mapped address (eg ::ffff:127.0.0.1) */
|
||||
struct addrinfo *remote_ipv4_addr = NULL;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
char config_line[1024];
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
SANE_Bool IPv4map = SANE_FALSE;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
int len;
|
||||
FILE *fp;
|
||||
|
||||
/* Get address of remote host */
|
||||
remote_address_len = sizeof (remote_address);
|
||||
if (getpeername (fd, (struct sockaddr *) &remote_address, (socklen_t *) &remote_address_len) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "check_host: getpeername failed: %s\n", strerror (errno));
|
||||
remote_ip = strdup ("[error]");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
err = getnameinfo ((struct sockaddr *) &remote_address, remote_address_len,
|
||||
hostname, sizeof (hostname), NULL, 0, NI_NUMERICHOST);
|
||||
if (err)
|
||||
{
|
||||
DBG (DBG_DBG, "check_host: getnameinfo failed: %s\n", gai_strerror(err));
|
||||
remote_ip = strdup ("[error]");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
else
|
||||
remote_ip = strdup (hostname);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if (strncmp (remote_ip, "::ffff:", 7) == 0)
|
||||
{
|
||||
DBG (DBG_DBG, "check_host: detected an IPv4-mapped address\n");
|
||||
remote_ipv4 = remote_ip + 7;
|
||||
IPv4map = SANE_TRUE;
|
||||
|
||||
memset (&hints, 0, sizeof (struct addrinfo));
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
hints.ai_family = PF_INET;
|
||||
|
||||
err = getaddrinfo (remote_ipv4, NULL, &hints, &res);
|
||||
if (err)
|
||||
{
|
||||
DBG (DBG_DBG, "check_host: getaddrinfo() failed: %s\n", gai_strerror (err));
|
||||
IPv4map = SANE_FALSE; /* we failed, remote_ipv4_addr points to nothing */
|
||||
}
|
||||
else
|
||||
{
|
||||
remote_ipv4_addr = res;
|
||||
sin = (struct sockaddr_in *)res->ai_addr;
|
||||
}
|
||||
}
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
DBG (DBG_WARN, "check_host: access by remote host: %s\n", remote_ip);
|
||||
|
||||
/* Always allow access from local host. Do it here to avoid DNS lookups
|
||||
and reading saned.conf. */
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if (IPv4map == SANE_TRUE)
|
||||
{
|
||||
if (IN_LOOPBACK (ntohl (sin->sin_addr.s_addr)))
|
||||
{
|
||||
DBG (DBG_MSG,
|
||||
"check_host: remote host is IN_LOOPBACK: access granted\n");
|
||||
freeaddrinfo (remote_ipv4_addr);
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
freeaddrinfo (remote_ipv4_addr);
|
||||
}
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
sin = (struct sockaddr_in *) &remote_address;
|
||||
#ifdef ENABLE_IPV6
|
||||
sin6 = (struct sockaddr_in6 *) &remote_address;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
switch (remote_address.ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
if (IN_LOOPBACK (ntohl (sin->sin_addr.s_addr)))
|
||||
{
|
||||
DBG (DBG_MSG,
|
||||
"check_host: remote host is IN_LOOPBACK: access granted\n");
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
if (SANE_IN6_IS_ADDR_LOOPBACK (sin6->sin6_addr.s6_addr))
|
||||
{
|
||||
DBG (DBG_MSG,
|
||||
"check_host: remote host is IN6_LOOPBACK: access granted\n");
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DBG (DBG_DBG, "check_host: remote host is not IN_LOOPBACK"
|
||||
#ifdef ENABLE_IPV6
|
||||
" nor IN6_LOOPBACK"
|
||||
#endif /* ENABLE_IPV6 */
|
||||
"\n");
|
||||
|
||||
|
||||
/* Get name of local host */
|
||||
if (gethostname (hostname, sizeof (hostname)) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "check_host: gethostname failed: %s\n", strerror (errno));
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
DBG (DBG_DBG, "check_host: local hostname: %s\n", hostname);
|
||||
|
||||
/* Get local addresses */
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
#ifdef ENABLE_IPV6
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
#else
|
||||
hints.ai_family = PF_INET;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
err = getaddrinfo (hostname, NULL, &hints, &res);
|
||||
if (err)
|
||||
{
|
||||
DBG (DBG_ERR, "check_host: getaddrinfo failed: %s\n",
|
||||
gai_strerror (err));
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (resp = res; resp != NULL; resp = resp->ai_next)
|
||||
{
|
||||
DBG (DBG_DBG, "check_host: local hostname(s) (from DNS): %s\n",
|
||||
resp->ai_canonname);
|
||||
|
||||
err = getnameinfo (resp->ai_addr, resp->ai_addrlen, text_addr,
|
||||
sizeof (text_addr), NULL, 0, NI_NUMERICHOST);
|
||||
if (err)
|
||||
strncpy (text_addr, "[error]", 8);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if ((strcmp (text_addr, remote_ip) == 0) ||
|
||||
((IPv4map == SANE_TRUE) && (strcmp (text_addr, remote_ipv4) == 0)))
|
||||
#else
|
||||
if (strcmp (text_addr, remote_ip) == 0)
|
||||
#endif /* ENABLE_IPV6 */
|
||||
{
|
||||
DBG (DBG_MSG, "check_host: remote host has same addr as local: access granted\n");
|
||||
|
||||
freeaddrinfo (res);
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo (res);
|
||||
|
||||
DBG (DBG_DBG,
|
||||
"check_host: remote host doesn't have same addr as local\n");
|
||||
}
|
||||
|
||||
/* must be a remote host: check contents of PATH_NET_CONFIG or
|
||||
/etc/hosts.equiv if former doesn't exist: */
|
||||
for (j = 0; j < NELEMS (config_file_names); ++j)
|
||||
{
|
||||
DBG (DBG_DBG, "check_host: opening config file: %s\n",
|
||||
config_file_names[j]);
|
||||
if (config_file_names[j][0] == '/')
|
||||
fp = fopen (config_file_names[j], "r");
|
||||
else
|
||||
fp = sanei_config_open (config_file_names[j]);
|
||||
if (!fp)
|
||||
{
|
||||
DBG (DBG_MSG,
|
||||
"check_host: can't open config file: %s (%s)\n",
|
||||
config_file_names[j], strerror (errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
while (!access_ok && sanei_config_read (config_line,
|
||||
sizeof (config_line), fp))
|
||||
{
|
||||
DBG (DBG_DBG, "check_host: config file line: `%s'\n", config_line);
|
||||
if (config_line[0] == '#') /* ignore line comments */
|
||||
continue;
|
||||
len = strlen (config_line);
|
||||
|
||||
if (!len)
|
||||
continue; /* ignore empty lines */
|
||||
|
||||
if (strcmp (config_line, "+") == 0)
|
||||
{
|
||||
access_ok = 1;
|
||||
DBG (DBG_DBG,
|
||||
"check_host: access granted from any host (`+')\n");
|
||||
}
|
||||
/* compare remote_ip (remote IP address) to the config_line */
|
||||
else if (strcmp (config_line, remote_ip) == 0)
|
||||
{
|
||||
access_ok = 1;
|
||||
DBG (DBG_DBG,
|
||||
"check_host: access granted from IP address %s\n", remote_ip);
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
else if ((IPv4map == SANE_TRUE) && (strcmp (config_line, remote_ipv4) == 0))
|
||||
{
|
||||
access_ok = 1;
|
||||
DBG (DBG_DBG,
|
||||
"check_host: access granted from IP address %s (IPv4-mapped)\n", remote_ip);
|
||||
}
|
||||
#endif /* ENABLE_IPV6 */
|
||||
else
|
||||
{
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
#ifdef ENABLE_IPV6
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
#else
|
||||
hints.ai_family = PF_INET;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
err = getaddrinfo (config_line, NULL, &hints, &res);
|
||||
if (err)
|
||||
{
|
||||
DBG (DBG_DBG,
|
||||
"check_host: getaddrinfo for `%s' failed: %s\n",
|
||||
config_line, gai_strerror (err));
|
||||
DBG (DBG_MSG, "check_host: entry isn't an IP address "
|
||||
"and can't be found in DNS\n");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (resp = res; resp != NULL; resp = resp->ai_next)
|
||||
{
|
||||
err = getnameinfo (resp->ai_addr, resp->ai_addrlen, text_addr,
|
||||
sizeof (text_addr), NULL, 0, NI_NUMERICHOST);
|
||||
if (err)
|
||||
strncpy (text_addr, "[error]", 8);
|
||||
|
||||
DBG (DBG_MSG,
|
||||
"check_host: DNS lookup returns IP address: %s\n",
|
||||
text_addr);
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if ((strcmp (text_addr, remote_ip) == 0) ||
|
||||
((IPv4map == SANE_TRUE) && (strcmp (text_addr, remote_ipv4) == 0)))
|
||||
#else
|
||||
if (strcmp (text_addr, remote_ip) == 0)
|
||||
#endif /* ENABLE_IPV6 */
|
||||
access_ok = 1;
|
||||
|
||||
if (access_ok)
|
||||
break;
|
||||
}
|
||||
freeaddrinfo (res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
if (access_ok)
|
||||
return SANE_STATUS_GOOD;
|
||||
|
||||
return SANE_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
#else /* !SANED_USES_AF_INDEP */
|
||||
|
||||
static SANE_Status
|
||||
check_host (int fd)
|
||||
{
|
||||
|
@ -391,12 +709,13 @@ check_host (int fd)
|
|||
if (getpeername (fd, (struct sockaddr *) &sin, (socklen_t *) &len) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "check_host: getpeername failed: %s\n", strerror (errno));
|
||||
remote_ip = strdup ("[error]");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
r_hostname = inet_ntoa (sin.sin_addr);
|
||||
remote_hostname = strdup (r_hostname);
|
||||
remote_ip = strdup (r_hostname);
|
||||
DBG (DBG_WARN, "check_host: access by remote host: %s\n",
|
||||
remote_hostname);
|
||||
remote_ip);
|
||||
/* Save remote address for check of control and data connections */
|
||||
memcpy (&remote_address, &sin.sin_addr, sizeof (remote_address));
|
||||
|
||||
|
@ -530,6 +849,8 @@ check_host (int fd)
|
|||
return SANE_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
||||
static int
|
||||
init (Wire * w)
|
||||
{
|
||||
|
@ -543,9 +864,11 @@ init (Wire * w)
|
|||
status = check_host (w->io.fd);
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_WARN, "init: access by host %s denied\n", remote_hostname);
|
||||
DBG (DBG_WARN, "init: access by host %s denied\n", remote_ip);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
DBG (DBG_MSG, "init: access granted\n");
|
||||
|
||||
sanei_w_set_dir (w, WIRE_DECODE);
|
||||
if (w->status)
|
||||
|
@ -583,8 +906,8 @@ init (Wire * w)
|
|||
reply.version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR,
|
||||
SANEI_NET_PROTOCOL_VERSION);
|
||||
|
||||
DBG (DBG_WARN, "init: access by %s@%s accepted\n",
|
||||
default_username, remote_hostname);
|
||||
DBG (DBG_WARN, "init: access granted to %s@%s\n",
|
||||
default_username, remote_ip);
|
||||
|
||||
if (status == SANE_STATUS_GOOD)
|
||||
{
|
||||
|
@ -612,6 +935,108 @@ init (Wire * w)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
static int
|
||||
start_scan (Wire * w, int h, SANE_Start_Reply * reply)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr_in *sin;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
SANE_Handle be_handle;
|
||||
int fd, len;
|
||||
|
||||
be_handle = handle[h].handle;
|
||||
|
||||
len = sizeof (ss);
|
||||
if (getsockname (w->io.fd, (struct sockaddr *) &ss, (socklen_t *) &len) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "start_scan: failed to obtain socket address (%s)\n",
|
||||
strerror (errno));
|
||||
reply->status = SANE_STATUS_IO_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = socket (ss.ss_family, SOCK_STREAM, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "start_scan: failed to obtain data socket (%s)\n",
|
||||
strerror (errno));
|
||||
reply->status = SANE_STATUS_IO_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ss.ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
sin = (struct sockaddr_in *) &ss;
|
||||
sin->sin_port = 0;
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *) &ss;
|
||||
sin6->sin6_port = 0;
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (bind (fd, (struct sockaddr *) &ss, len) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "start_scan: failed to bind address (%s)\n",
|
||||
strerror (errno));
|
||||
reply->status = SANE_STATUS_IO_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (fd, 1) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "start_scan: failed to make socket listen (%s)\n",
|
||||
strerror (errno));
|
||||
reply->status = SANE_STATUS_IO_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (getsockname (fd, (struct sockaddr *) &ss, (socklen_t *) &len) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "start_scan: failed to obtain socket address (%s)\n",
|
||||
strerror (errno));
|
||||
reply->status = SANE_STATUS_IO_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ss.ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
sin = (struct sockaddr_in *) &ss;
|
||||
reply->port = ntohs (sin->sin_port);
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *) &ss;
|
||||
reply->port = ntohs (sin6->sin6_port);
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DBG (DBG_MSG, "start_scan: using port %d for data\n", reply->port);
|
||||
|
||||
reply->status = sane_start (be_handle);
|
||||
if (reply->status == SANE_STATUS_GOOD)
|
||||
{
|
||||
handle[h].scanning = 1;
|
||||
handle[h].docancel = 0;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#else /* !SANED_USES_AF_INDEP */
|
||||
|
||||
static int
|
||||
start_scan (Wire * w, int h, SANE_Start_Reply * reply)
|
||||
{
|
||||
|
@ -677,6 +1102,7 @@ start_scan (Wire * w, int h, SANE_Start_Reply * reply)
|
|||
|
||||
return fd;
|
||||
}
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
||||
static int
|
||||
store_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen)
|
||||
|
@ -958,7 +1384,7 @@ process_request (Wire * w)
|
|||
}
|
||||
else
|
||||
{
|
||||
DBG (DBG_MSG, "process_request: access to resource `%s' accepted\n",
|
||||
DBG (DBG_MSG, "process_request: access to resource `%s' granted\n",
|
||||
resource);
|
||||
free (resource);
|
||||
memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */
|
||||
|
@ -1089,6 +1515,51 @@ process_request (Wire * w)
|
|||
|
||||
sanei_w_reply (w, (WireCodecFunc) sanei_w_start_reply, &reply);
|
||||
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
if (reply.status == SANE_STATUS_GOOD)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
char text_addr[64];
|
||||
int len;
|
||||
int error;
|
||||
|
||||
DBG (DBG_MSG, "process_request: waiting for data connection\n");
|
||||
data_fd = accept (fd, 0, 0);
|
||||
close (fd);
|
||||
|
||||
/* Get address of remote host */
|
||||
len = sizeof (ss);
|
||||
if (getpeername (data_fd, (struct sockaddr *) &ss, (socklen_t *) &len) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "process_request: getpeername failed: %s\n",
|
||||
strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
error = getnameinfo ((struct sockaddr *) &ss, len, text_addr,
|
||||
sizeof (text_addr), NULL, 0, NI_NUMERICHOST);
|
||||
if (error)
|
||||
{
|
||||
DBG (DBG_ERR, "process_request: getnameinfo failed: %s\n",
|
||||
gai_strerror (error));
|
||||
return;
|
||||
}
|
||||
|
||||
DBG (DBG_MSG, "process_request: access to data port from %s\n",
|
||||
text_addr);
|
||||
|
||||
if (strcmp (text_addr, remote_ip) != 0)
|
||||
{
|
||||
DBG (DBG_ERR, "process_request: however, only %s is authorized\n",
|
||||
text_addr);
|
||||
DBG (DBG_ERR, "process_request: configuration problem or attack?\n");
|
||||
close (data_fd);
|
||||
data_fd = -1;
|
||||
quit (0);
|
||||
}
|
||||
|
||||
#else /* !SANED_USES_AF_INDEP */
|
||||
|
||||
if (reply.status == SANE_STATUS_GOOD)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
|
@ -1126,6 +1597,7 @@ process_request (Wire * w)
|
|||
else
|
||||
DBG (DBG_MSG, "process_request: access to data port from %s\n",
|
||||
inet_ntoa (sin.sin_addr));
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
||||
if (data_fd < 0)
|
||||
{
|
||||
|
@ -1169,6 +1641,274 @@ process_request (Wire * w)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef SANED_USES_AF_INDEP
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int fd = -1;
|
||||
int 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)
|
||||
++prog_name;
|
||||
else
|
||||
prog_name = argv[0];
|
||||
|
||||
byte_order.w = 0;
|
||||
byte_order.ch = 1;
|
||||
|
||||
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))
|
||||
{
|
||||
/* don't operate in daemon mode: wait for connection request: */
|
||||
struct addrinfo *res;
|
||||
struct addrinfo *resp;
|
||||
struct addrinfo hints;
|
||||
struct sockaddr_in *sin;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
struct pollfd *fds = NULL;
|
||||
struct pollfd *fdp = NULL;
|
||||
int nfds;
|
||||
int err;
|
||||
int i;
|
||||
short sane_port = htons (6566);
|
||||
|
||||
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' (getaddrinfo)\n");
|
||||
|
||||
memset (&hints, 0, sizeof (struct addrinfo));
|
||||
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
err = getaddrinfo (NULL, "sane", &hints, &res);
|
||||
if (err)
|
||||
{
|
||||
/*
|
||||
* You cannot pass (NULL, NULL, &hints, &res) to getaddrinfo,
|
||||
* so request a good-old well known service, and change the port
|
||||
* afterwards as a workaround
|
||||
*/
|
||||
err = getaddrinfo (NULL, "telnet", &hints, &res);
|
||||
if (err)
|
||||
{
|
||||
DBG (DBG_ERR, "main: getaddrinfo() failed: %s\n", gai_strerror (err));
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG (DBG_WARN, "main: \"sane\" service unknown on your host; you should add\n");
|
||||
DBG (DBG_WARN, "main: sane 6566/tcp saned # SANE network scanner daemon\n");
|
||||
DBG (DBG_WARN, "main: to your /etc/services file (or equivalent). Proceeding anyway.\n");
|
||||
|
||||
for (resp = res; resp != NULL; resp = resp->ai_next)
|
||||
{
|
||||
switch (resp->ai_family)
|
||||
{
|
||||
case AF_INET:
|
||||
sin = (struct sockaddr_in *) resp->ai_addr;
|
||||
sin->sin_port = sane_port;
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *) resp->ai_addr;
|
||||
sin6->sin6_port = sane_port;
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (resp = res, nfds = 0; resp != NULL; resp = resp->ai_next, nfds++)
|
||||
;
|
||||
|
||||
fds = malloc (nfds * sizeof (struct pollfd));
|
||||
|
||||
if (fds == NULL)
|
||||
{
|
||||
DBG (DBG_ERR, "main: not enough memory for fds\n");
|
||||
freeaddrinfo (res);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for (resp = res, i = 0, fdp = fds; resp != NULL; resp = resp->ai_next, i++, fdp++)
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
if ((resp->ai_family != AF_INET) && (resp->ai_family != AF_INET6))
|
||||
#else
|
||||
if (resp->ai_family != AF_INET)
|
||||
#endif /* ENABLE_IPV6 */
|
||||
{
|
||||
fdp--;
|
||||
nfds--;
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG (DBG_DBG, "main: [%d] socket ()\n", i);
|
||||
fd = socket (resp->ai_family, SOCK_STREAM, 0);
|
||||
|
||||
DBG (DBG_DBG, "main: [%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_DBG, "main: [%d] bind ()\n", i);
|
||||
if (bind (fd, resp->ai_addr, resp->ai_addrlen) < 0)
|
||||
{
|
||||
/*
|
||||
* binding a socket may fail, eg if we already
|
||||
* to the IPv6 addr returned by getaddrinfo (usually the first one),
|
||||
* or if IPv6 isn't supported, but saned was built with IPv6 support
|
||||
*/
|
||||
DBG (DBG_ERR, "main: [%d] bind failed: %s\n", i, strerror (errno));
|
||||
|
||||
close (fd);
|
||||
|
||||
nfds--;
|
||||
fdp--;
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG (DBG_DBG, "main: [%d] listen ()\n", i);
|
||||
if (listen (fd, 1) < 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: [%d] listen failed: %s\n", i, strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
fdp->fd = fd;
|
||||
fdp->events = POLLIN;
|
||||
}
|
||||
|
||||
resp = NULL;
|
||||
freeaddrinfo (res);
|
||||
|
||||
if (nfds <= 0)
|
||||
{
|
||||
DBG (DBG_ERR, "main: couldn't bind an address. Exiting.\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
DBG (DBG_MSG, "main: waiting for control connection\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (poll (fds, nfds, -1) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
DBG (DBG_ERR, "main: poll failed: %s\n", strerror (errno));
|
||||
free (fds);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, fdp = fds; i < nfds; i++, fdp++)
|
||||
{
|
||||
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));
|
||||
free (fds);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
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
|
||||
/* 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !SANED_USES_AF_INDEP */
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
@ -1287,7 +2027,7 @@ main (int argc, char *argv[])
|
|||
p = getprotobyname ("tcp");
|
||||
if (p == 0)
|
||||
{
|
||||
DBG (DBG_WARN, "main:: cannot look up `tcp' protocol number");
|
||||
DBG (DBG_WARN, "main: cannot look up `tcp' protocol number");
|
||||
}
|
||||
else
|
||||
level = p->p_proto;
|
||||
|
@ -1310,3 +2050,4 @@ main (int argc, char *argv[])
|
|||
process_request (&wire);
|
||||
}
|
||||
}
|
||||
#endif /* SANED_USES_AF_INDEP */
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
/* Should we disable SCSI generic v3? */
|
||||
#undef DISABLE_LINUX_SG_IO
|
||||
|
||||
/* Define to 1 if the system supports IPv6 */
|
||||
#undef ENABLE_IPV6
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
|
@ -51,9 +54,15 @@
|
|||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
/* Define to 1 if you have the `getenv' function. */
|
||||
#undef HAVE_GETENV
|
||||
|
||||
/* Define to 1 if you have the `getnameinfo' function. */
|
||||
#undef HAVE_GETNAMEINFO
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue