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
|
* doc/descriptions/unsupported.desc: Added Medion MD 6228, Microtek
|
||||||
ScanPort 3000, and PIE Primefilm 1800u.
|
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>
|
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_LINKER_RPATH
|
||||||
dnl SANE_CHECK_U_TYPES
|
dnl SANE_CHECK_U_TYPES
|
||||||
dnl SANE_CHECK_GPHOTO2
|
dnl SANE_CHECK_GPHOTO2
|
||||||
|
dnl SANE_CHECK_IPV6
|
||||||
dnl SANE_PROTOTYPES
|
dnl SANE_PROTOTYPES
|
||||||
dnl AC_PROG_LIBTOOL
|
dnl AC_PROG_LIBTOOL
|
||||||
dnl
|
dnl
|
||||||
|
@ -344,6 +345,45 @@ AC_DEFUN([SANE_CHECK_GPHOTO2],
|
||||||
]) fi
|
]) 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
|
# Generate prototypes for functions not available on the system
|
||||||
AC_DEFUN([SANE_PROTOTYPES],
|
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_LINKER_RPATH
|
||||||
dnl SANE_CHECK_U_TYPES
|
dnl SANE_CHECK_U_TYPES
|
||||||
dnl SANE_CHECK_GPHOTO2
|
dnl SANE_CHECK_GPHOTO2
|
||||||
|
dnl SANE_CHECK_IPV6
|
||||||
dnl SANE_PROTOTYPES
|
dnl SANE_PROTOTYPES
|
||||||
dnl AC_PROG_LIBTOOL
|
dnl AC_PROG_LIBTOOL
|
||||||
dnl
|
dnl
|
||||||
|
@ -356,6 +357,45 @@ AC_DEFUN([SANE_CHECK_GPHOTO2],
|
||||||
]) fi
|
]) 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
|
# Generate prototypes for functions not available on the system
|
||||||
AC_DEFUN([SANE_PROTOTYPES],
|
AC_DEFUN([SANE_PROTOTYPES],
|
||||||
|
|
485
backend/net.c
485
backend/net.c
|
@ -1,5 +1,8 @@
|
||||||
/* sane - Scanner Access Now Easy.
|
/* sane - Scanner Access Now Easy.
|
||||||
Copyright (C) 1997 David Mosberger-Tang
|
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 file is part of the SANE package.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
|
@ -40,10 +43,6 @@
|
||||||
|
|
||||||
This file implements a SANE network-based meta backend. */
|
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
|
#ifdef _AIX
|
||||||
# include "../include/lalloca.h" /* MUST come first for AIX! */
|
# include "../include/lalloca.h" /* MUST come first for AIX! */
|
||||||
#endif
|
#endif
|
||||||
|
@ -83,15 +82,34 @@
|
||||||
#include "../include/sane/sanei_config.h"
|
#include "../include/sane/sanei_config.h"
|
||||||
#define NET_CONFIG_FILE "net.conf"
|
#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 SANE_Auth_Callback auth_callback;
|
||||||
static Net_Device *first_device;
|
static Net_Device *first_device;
|
||||||
static Net_Scanner *first_handle;
|
static Net_Scanner *first_handle;
|
||||||
static const SANE_Device **devlist;
|
static const SANE_Device **devlist;
|
||||||
static int saned_port;
|
|
||||||
static int client_big_endian; /* 1 == big endian; 0 == little endian */
|
static int client_big_endian; /* 1 == big endian; 0 == little endian */
|
||||||
static int server_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 */
|
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
|
/* 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
|
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
|
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;
|
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
|
static SANE_Status
|
||||||
add_device (const char *name, Net_Device ** ndp)
|
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);
|
DBG (2, "add_device: backend %s added\n", name);
|
||||||
return SANE_STATUS_GOOD;
|
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
|
static SANE_Status
|
||||||
connect_dev (Net_Device * dev)
|
connect_dev (Net_Device * dev)
|
||||||
|
@ -202,6 +376,7 @@ connect_dev (Net_Device * dev)
|
||||||
return SANE_STATUS_IO_ERROR;
|
return SANE_STATUS_IO_ERROR;
|
||||||
}
|
}
|
||||||
DBG (3, "connect_dev: connection succeeded\n");
|
DBG (3, "connect_dev: connection succeeded\n");
|
||||||
|
#endif /* NET_USES_AF_INDEP */
|
||||||
|
|
||||||
#ifdef TCP_NODELAY
|
#ifdef TCP_NODELAY
|
||||||
# ifdef SOL_TCP
|
# ifdef SOL_TCP
|
||||||
|
@ -288,6 +463,7 @@ fail:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static SANE_Status
|
static SANE_Status
|
||||||
fetch_options (Net_Scanner * s)
|
fetch_options (Net_Scanner * s)
|
||||||
{
|
{
|
||||||
|
@ -444,13 +620,16 @@ SANE_Status
|
||||||
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
||||||
{
|
{
|
||||||
char device_name[PATH_MAX];
|
char device_name[PATH_MAX];
|
||||||
struct servent *serv;
|
|
||||||
const char *env;
|
const char *env;
|
||||||
size_t len;
|
size_t len;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
short ns = 0x1234;
|
short ns = 0x1234;
|
||||||
unsigned char *p = (unsigned char *)(&ns);
|
unsigned char *p = (unsigned char *)(&ns);
|
||||||
|
|
||||||
|
#ifndef NET_USES_AF_INDEP
|
||||||
|
struct servent *serv;
|
||||||
|
#endif /* !NET_USES_AF_INDEP */
|
||||||
|
|
||||||
DBG_INIT ();
|
DBG_INIT ();
|
||||||
|
|
||||||
DBG (2, "sane_init: authorize = %p, version_code = %p\n", authorize,
|
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");
|
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");
|
DBG (2, "sane_init: determining sane service port\n");
|
||||||
serv = getservbyname ("sane", "tcp");
|
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 "
|
DBG (1, "sane_init: could not find `sane' service (%s); using default "
|
||||||
"port %d\n", strerror (errno), ntohs (saned_port));
|
"port %d\n", strerror (errno), ntohs (saned_port));
|
||||||
}
|
}
|
||||||
|
#endif /* !NET_USES_AF_INDEP */
|
||||||
|
|
||||||
DBG (2, "sane_init: searching for config file\n");
|
DBG (2, "sane_init: searching for config file\n");
|
||||||
fp = sanei_config_open (NET_CONFIG_FILE);
|
fp = sanei_config_open (NET_CONFIG_FILE);
|
||||||
|
@ -533,6 +714,30 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
||||||
next = copy;
|
next = copy;
|
||||||
while ((host = strsep (&next, ":")))
|
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);
|
DBG (2, "sane_init: trying to add %s\n", host);
|
||||||
add_device (host, 0);
|
add_device (host, 0);
|
||||||
}
|
}
|
||||||
|
@ -580,6 +785,12 @@ sane_exit (void)
|
||||||
}
|
}
|
||||||
if (dev->name)
|
if (dev->name)
|
||||||
free ((void *) dev->name);
|
free ((void *) dev->name);
|
||||||
|
|
||||||
|
#ifdef NET_USES_AF_INDEP
|
||||||
|
if (dev->addr)
|
||||||
|
freeaddrinfo(dev->addr);
|
||||||
|
#endif /* NET_USES_AF_INDEP */
|
||||||
|
|
||||||
free (dev);
|
free (dev);
|
||||||
}
|
}
|
||||||
if (devlist)
|
if (devlist)
|
||||||
|
@ -693,11 +904,23 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
||||||
{
|
{
|
||||||
SANE_Device *rdev;
|
SANE_Device *rdev;
|
||||||
char *mem;
|
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
|
/* create a new device entry with a device name that is the
|
||||||
sum of the backend name a colon and the backend's device
|
sum of the backend name a colon and the backend's device
|
||||||
name: */
|
name: */
|
||||||
len = strlen (dev->name) + 1 + strlen (reply.device_list[i]->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);
|
mem = malloc (sizeof (*dev) + len + 1);
|
||||||
if (!mem)
|
if (!mem)
|
||||||
{
|
{
|
||||||
|
@ -707,8 +930,22 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
||||||
&reply);
|
&reply);
|
||||||
return SANE_STATUS_NO_MEM;
|
return SANE_STATUS_NO_MEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset (mem, 0, sizeof (*dev) + len);
|
||||||
full_name = mem + sizeof (*dev);
|
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, ":");
|
||||||
strcat (full_name, reply.device_list[i]->name);
|
strcat (full_name, reply.device_list[i]->name);
|
||||||
DBG (3, "sane_get_devices: got %s\n", full_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");
|
DBG (1, "sane_get_devices: not enough free memory\n");
|
||||||
if (rdev->vendor)
|
if (rdev->vendor)
|
||||||
free (rdev->vendor);
|
free ((void *) rdev->vendor);
|
||||||
if (rdev->model)
|
if (rdev->model)
|
||||||
free (rdev->model);
|
free ((void *) rdev->model);
|
||||||
if (rdev->type)
|
if (rdev->type)
|
||||||
free (rdev->type);
|
free ((void *) rdev->type);
|
||||||
free (rdev);
|
free (rdev);
|
||||||
sanei_w_free (&dev->wire,
|
sanei_w_free (&dev->wire,
|
||||||
(WireCodecFunc) sanei_w_get_devices_reply,
|
(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;
|
SANE_Open_Reply reply;
|
||||||
const char *dev_name;
|
const char *dev_name;
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
const char *tmp_name;
|
||||||
|
SANE_Bool v6addr = SANE_FALSE;
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
SANE_String nd_name;
|
SANE_String nd_name;
|
||||||
SANE_Status status;
|
SANE_Status status;
|
||||||
SANE_Word handle;
|
SANE_Word handle;
|
||||||
|
@ -764,12 +1005,46 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
|
||||||
int need_auth;
|
int need_auth;
|
||||||
|
|
||||||
DBG (3, "sane_open(\"%s\")\n", full_name);
|
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)
|
if (dev_name)
|
||||||
{
|
{
|
||||||
#ifdef strndupa
|
#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);
|
nd_name = strndupa (full_name, dev_name - full_name);
|
||||||
|
# endif /* ENABLE_IPV6 */
|
||||||
|
|
||||||
if (!nd_name)
|
if (!nd_name)
|
||||||
{
|
{
|
||||||
DBG (1, "sane_open: not enough free memory\n");
|
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
|
#else
|
||||||
char *tmp;
|
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);
|
tmp = alloca (dev_name - full_name + 1);
|
||||||
|
# endif /* ENABLE_IPV6 */
|
||||||
|
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
{
|
{
|
||||||
DBG (1, "sane_open: not enough free memory\n");
|
DBG (1, "sane_open: not enough free memory\n");
|
||||||
return SANE_STATUS_NO_MEM;
|
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);
|
memcpy (tmp, full_name, dev_name - full_name);
|
||||||
tmp[dev_name - full_name] = '\0';
|
tmp[dev_name - full_name] = '\0';
|
||||||
|
# endif /* ENABLE_IPV6 */
|
||||||
|
|
||||||
nd_name = tmp;
|
nd_name = tmp;
|
||||||
#endif
|
#endif
|
||||||
++dev_name; /* skip colon */
|
++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
|
/* if no colon interpret full_name as the host name; an empty
|
||||||
device name will cause us to open the first device of that
|
device name will cause us to open the first device of that
|
||||||
host. */
|
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;
|
nd_name = (char *) full_name;
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
|
|
||||||
dev_name = "";
|
dev_name = "";
|
||||||
}
|
}
|
||||||
DBG (2, "sane_open: host = %s, device = %s\n", nd_name, 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;
|
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_Status
|
||||||
sane_start (SANE_Handle handle)
|
sane_start (SANE_Handle handle)
|
||||||
{
|
{
|
||||||
|
@ -1240,6 +1701,8 @@ sane_start (SANE_Handle handle)
|
||||||
DBG (3, "sane_start: done (%s)\n", sane_strstatus (status));
|
DBG (3, "sane_start: done (%s)\n", sane_strstatus (status));
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
#endif /* NET_USES_AF_INDEP */
|
||||||
|
|
||||||
|
|
||||||
SANE_Status
|
SANE_Status
|
||||||
sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length,
|
sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length,
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
/* sane - Scanner Access Now Easy.
|
/* sane - Scanner Access Now Easy.
|
||||||
Copyright (C) 1997 David Mosberger-Tang
|
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 file is part of the SANE package.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
|
@ -44,12 +47,18 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "../include/sane/sanei_wire.h"
|
#include "../include/sane/sanei_wire.h"
|
||||||
|
#include "../include/sane/config.h"
|
||||||
|
|
||||||
typedef struct Net_Device
|
typedef struct Net_Device
|
||||||
{
|
{
|
||||||
struct Net_Device *next;
|
struct Net_Device *next;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
#if defined (HAVE_GETADDRINFO) && defined (HAVE_GETNAMEINFO)
|
||||||
|
struct addrinfo *addr;
|
||||||
|
struct addrinfo *addr_used;
|
||||||
|
#else
|
||||||
struct sockaddr addr;
|
struct sockaddr addr;
|
||||||
|
#endif /* HAVE_GETADDRINFO && HAVE_GETNAMEINFO */
|
||||||
int ctl; /* socket descriptor (or -1) */
|
int ctl; /* socket descriptor (or -1) */
|
||||||
Wire wire;
|
Wire wire;
|
||||||
int auth_active;
|
int auth_active;
|
||||||
|
|
|
@ -1011,6 +1011,8 @@ Optional Features:
|
||||||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||||
--enable-warnings turn on tons of compiler warnings (GCC only)
|
--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-static=PKGS build static libraries default=no
|
||||||
--enable-shared=PKGS build shared libraries default=yes
|
--enable-shared=PKGS build shared libraries default=yes
|
||||||
--enable-fast-install=PKGS optimize for fast installation 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 \
|
for ac_func in atexit inet_addr inet_aton inet_ntoa ioperm mkdir \
|
||||||
scsireq_enter strftime strstr strtod \
|
scsireq_enter strftime strstr strtod \
|
||||||
cfmakeraw tcsendbreak strcasecmp strncasecmp _portaccess
|
cfmakeraw tcsendbreak strcasecmp strncasecmp _portaccess \
|
||||||
|
getaddrinfo getnameinfo
|
||||||
do
|
do
|
||||||
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||||
echo "$as_me:$LINENO: checking for $ac_func" >&5
|
echo "$as_me:$LINENO: checking for $ac_func" >&5
|
||||||
|
@ -8298,6 +8303,90 @@ _ACEOF
|
||||||
|
|
||||||
fi
|
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.
|
# Check whether --enable-static or --disable-static was given.
|
||||||
if test "${enable_static+set}" = set; then
|
if test "${enable_static+set}" = set; then
|
||||||
|
@ -9475,7 +9564,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
|
||||||
case $host in
|
case $host in
|
||||||
*-*-irix6*)
|
*-*-irix6*)
|
||||||
# Find out which ABI we are using.
|
# 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
|
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||||
(eval $ac_compile) 2>&5
|
(eval $ac_compile) 2>&5
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
|
@ -10004,7 +10093,7 @@ chmod -w .
|
||||||
save_CFLAGS="$CFLAGS"
|
save_CFLAGS="$CFLAGS"
|
||||||
CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
|
CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
|
||||||
compiler_c_o=no
|
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
|
# The compiler can only warn and ignore the option if not recognized
|
||||||
# So say no if there are warnings
|
# So say no if there are warnings
|
||||||
if test -s out/conftest.err; then
|
if test -s out/conftest.err; then
|
||||||
|
@ -11836,7 +11925,7 @@ else
|
||||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||||
lt_status=$lt_dlunknown
|
lt_status=$lt_dlunknown
|
||||||
cat > conftest.$ac_ext <<EOF
|
cat > conftest.$ac_ext <<EOF
|
||||||
#line 11839 "configure"
|
#line 11928 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
|
@ -11934,7 +12023,7 @@ else
|
||||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||||
lt_status=$lt_dlunknown
|
lt_status=$lt_dlunknown
|
||||||
cat > conftest.$ac_ext <<EOF
|
cat > conftest.$ac_ext <<EOF
|
||||||
#line 11937 "configure"
|
#line 12026 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
|
@ -14026,6 +14115,8 @@ echo "Configuration: `eval eval echo ${sysconfdir}`"
|
||||||
echo "Libraries: `eval eval echo ${libdir}`"
|
echo "Libraries: `eval eval echo ${libdir}`"
|
||||||
echo "Binaries: `eval eval echo ${bindir}` and `eval eval echo ${sbindir}`"
|
echo "Binaries: `eval eval echo ${bindir}` and `eval eval echo ${sbindir}`"
|
||||||
echo "Manpages: `eval eval echo ${mandir}`"
|
echo "Manpages: `eval eval echo ${mandir}`"
|
||||||
|
echo "Network parameters:"
|
||||||
|
echo "IPv6 support: `eval eval echo ${ipv6}`"
|
||||||
|
|
||||||
if test "$SANE_CONFIG_PATH" != "no" ; then
|
if test "$SANE_CONFIG_PATH" != "no" ; then
|
||||||
SANE_INSTALLED_VERSION=`$SANE_CONFIG_PATH --version`
|
SANE_INSTALLED_VERSION=`$SANE_CONFIG_PATH --version`
|
||||||
|
|
12
configure.in
12
configure.in
|
@ -180,7 +180,8 @@ AC_FUNC_ALLOCA
|
||||||
AC_FUNC_MMAP
|
AC_FUNC_MMAP
|
||||||
AC_CHECK_FUNCS(atexit inet_addr inet_aton inet_ntoa ioperm mkdir \
|
AC_CHECK_FUNCS(atexit inet_addr inet_aton inet_ntoa ioperm mkdir \
|
||||||
scsireq_enter strftime strstr strtod \
|
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 \
|
AC_REPLACE_FUNCS(getenv inet_ntop inet_pton isfdtype sigprocmask snprintf \
|
||||||
strdup strndup strsep usleep vsyslog)
|
strdup strndup strsep usleep vsyslog)
|
||||||
SANE_PROTOTYPES
|
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?])
|
AC_DEFINE(DISABLE_LINUX_SG_IO, 1, [Should we disable SCSI generic v3?])
|
||||||
fi
|
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 ***********************************************************************
|
||||||
dnl initialize libtool
|
dnl initialize libtool
|
||||||
dnl ***********************************************************************
|
dnl ***********************************************************************
|
||||||
|
@ -433,6 +441,8 @@ echo "Configuration: `eval eval echo ${sysconfdir}`"
|
||||||
echo "Libraries: `eval eval echo ${libdir}`"
|
echo "Libraries: `eval eval echo ${libdir}`"
|
||||||
echo "Binaries: `eval eval echo ${bindir}` and `eval eval echo ${sbindir}`"
|
echo "Binaries: `eval eval echo ${bindir}` and `eval eval echo ${sbindir}`"
|
||||||
echo "Manpages: `eval eval echo ${mandir}`"
|
echo "Manpages: `eval eval echo ${mandir}`"
|
||||||
|
echo "Network parameters:"
|
||||||
|
echo "IPv6 support: `eval eval echo ${ipv6}`"
|
||||||
|
|
||||||
if test "$SANE_CONFIG_PATH" != "no" ; then
|
if test "$SANE_CONFIG_PATH" != "no" ; then
|
||||||
SANE_INSTALLED_VERSION=`$SANE_CONFIG_PATH --version`
|
SANE_INSTALLED_VERSION=`$SANE_CONFIG_PATH --version`
|
||||||
|
|
|
@ -20,7 +20,7 @@ This backend expects device names of the form:
|
||||||
.PP
|
.PP
|
||||||
Where
|
Where
|
||||||
.I host
|
.I host
|
||||||
is the name of the (remote-) host and
|
is the name (or IP address) of the (remote-) host and
|
||||||
.I device
|
.I device
|
||||||
is the name of the device on this host that should be addressed.
|
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
|
If the device name does not contain a colon (:), then the entire string
|
||||||
|
@ -28,35 +28,50 @@ is treated as the
|
||||||
.I device
|
.I device
|
||||||
string for the default host. The default host is the host listed last
|
string for the default host. The default host is the host listed last
|
||||||
in the configuration file (see below).
|
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
|
.SH CONFIGURATION
|
||||||
The contents of the
|
The contents of the
|
||||||
.IR net.conf .
|
.IR net.conf
|
||||||
file is a list of host names that should be contacted for
|
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
|
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
|
.PP
|
||||||
.RS
|
.RS
|
||||||
scan-server.somedomain.firm
|
scan-server.somedomain.firm
|
||||||
.br
|
.br
|
||||||
|
192.168.0.1
|
||||||
|
.br
|
||||||
# this is a comment
|
# this is a comment
|
||||||
.br
|
.br
|
||||||
localhost
|
localhost
|
||||||
|
.br
|
||||||
|
::1
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.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
|
variable
|
||||||
.BR SANE_NET_HOSTS .
|
.BR SANE_NET_HOSTS .
|
||||||
This environment variable is a colon-separated list of hostnames that
|
This environment variable is a colon-separated list of hostnames or IP
|
||||||
should be contacted in addition to the hosts mentioned in the
|
addresses that should be contacted in addition to the hosts mentioned in
|
||||||
configuration file. For example, a user could set the environment
|
the configuration file. For example, a user could set the environment
|
||||||
variable to the string:
|
variable to the string:
|
||||||
.PP
|
.PP
|
||||||
.RS
|
.RS
|
||||||
new.scanner.com:scanner.univ.edu
|
new.scanner.com:[::1]:192.168.0.2:scanner.univ.edu
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
To request that hosts
|
To request that hosts
|
||||||
.I new.scanner.com
|
.I new.scanner.com
|
||||||
|
,
|
||||||
|
.I [::1]
|
||||||
|
,
|
||||||
|
.I 192.168.0.2
|
||||||
and
|
and
|
||||||
.I scanner.univ.edu
|
.I scanner.univ.edu
|
||||||
are contacted in addition to the hosts listed above.
|
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
|
.B sane
|
||||||
service in
|
service in
|
||||||
.IR /etc/services .
|
.IR /etc/services .
|
||||||
At present, the
|
The
|
||||||
.B sane
|
.B sane
|
||||||
service should be defined using a line of the following form:
|
service should be defined using a line of the following form:
|
||||||
.PP
|
.PP
|
||||||
|
@ -103,7 +118,8 @@ to "/tmp/config:" would result in directories "tmp/config", ".", and
|
||||||
"@CONFIGDIR@" being searched (in this order).
|
"@CONFIGDIR@" being searched (in this order).
|
||||||
.TP
|
.TP
|
||||||
.B SANE_NET_HOSTS
|
.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
|
.TP
|
||||||
.B SANE_DEBUG_NET
|
.B SANE_DEBUG_NET
|
||||||
If the library was compiled with debug support enabled, this
|
If the library was compiled with debug support enabled, this
|
||||||
|
|
|
@ -68,15 +68,22 @@ scan-client.somedomain.firm
|
||||||
# this is a comment
|
# this is a comment
|
||||||
.br
|
.br
|
||||||
192.168.0.1
|
192.168.0.1
|
||||||
|
.br
|
||||||
|
::1
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
The case of the host names does not matter, so AHost.COM is considered
|
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
|
For
|
||||||
.B saned
|
.B saned
|
||||||
to work properly, it is also necessary to add a configuration line to
|
to work properly, it is also necessary to add a configuration line to
|
||||||
.IR /etc/inetd.conf .
|
.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:
|
The configuration line normally looks like this:
|
||||||
.PP
|
.PP
|
||||||
.RS
|
.RS
|
||||||
|
|
757
frontend/saned.c
757
frontend/saned.c
|
@ -1,6 +1,9 @@
|
||||||
/* sane - Scanner Access Now Easy.
|
/* sane - Scanner Access Now Easy.
|
||||||
Copyright (C) 1997 Andreas Beck
|
Copyright (C) 1997 Andreas Beck
|
||||||
Copyright (C) 2001, 2002 Henning Meier-Geinitz
|
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.
|
This file is part of the SANE package.
|
||||||
|
|
||||||
SANE is free software; you can redistribute it and/or modify it under
|
SANE is free software; you can redistribute it and/or modify it under
|
||||||
|
@ -54,6 +57,7 @@
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
@ -74,12 +78,26 @@
|
||||||
# define IN_LOOPBACK(addr) (addr == 0x7f000001L)
|
# define IN_LOOPBACK(addr) (addr == 0x7f000001L)
|
||||||
#endif
|
#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
|
#ifndef MAXHOSTNAMELEN
|
||||||
# define MAXHOSTNAMELEN 120
|
# define MAXHOSTNAMELEN 120
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SANED_CONFIG_FILE "saned.conf"
|
#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
|
typedef struct
|
||||||
{
|
{
|
||||||
u_int inuse:1; /* is this handle in use? */
|
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
|
it does is save a remote user some work by reducing the amount of
|
||||||
text s/he has to type when authentication is requested. */
|
text s/he has to type when authentication is requested. */
|
||||||
static const char *default_username = "saned-user";
|
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;
|
static struct in_addr remote_address;
|
||||||
|
#endif /* SANED_USES_AF_INDEP */
|
||||||
|
|
||||||
#ifndef _PATH_HEQUIV
|
#ifndef _PATH_HEQUIV
|
||||||
# define _PATH_HEQUIV "/etc/hosts.equiv"
|
# define _PATH_HEQUIV "/etc/hosts.equiv"
|
||||||
|
@ -371,6 +395,300 @@ decode_handle (Wire * w, const char *op)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Access control */
|
/* 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
|
static SANE_Status
|
||||||
check_host (int fd)
|
check_host (int fd)
|
||||||
{
|
{
|
||||||
|
@ -391,12 +709,13 @@ check_host (int fd)
|
||||||
if (getpeername (fd, (struct sockaddr *) &sin, (socklen_t *) &len) < 0)
|
if (getpeername (fd, (struct sockaddr *) &sin, (socklen_t *) &len) < 0)
|
||||||
{
|
{
|
||||||
DBG (DBG_ERR, "check_host: getpeername failed: %s\n", strerror (errno));
|
DBG (DBG_ERR, "check_host: getpeername failed: %s\n", strerror (errno));
|
||||||
|
remote_ip = strdup ("[error]");
|
||||||
return SANE_STATUS_INVAL;
|
return SANE_STATUS_INVAL;
|
||||||
}
|
}
|
||||||
r_hostname = inet_ntoa (sin.sin_addr);
|
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",
|
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 */
|
/* Save remote address for check of control and data connections */
|
||||||
memcpy (&remote_address, &sin.sin_addr, sizeof (remote_address));
|
memcpy (&remote_address, &sin.sin_addr, sizeof (remote_address));
|
||||||
|
|
||||||
|
@ -530,6 +849,8 @@ check_host (int fd)
|
||||||
return SANE_STATUS_ACCESS_DENIED;
|
return SANE_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* SANED_USES_AF_INDEP */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
init (Wire * w)
|
init (Wire * w)
|
||||||
{
|
{
|
||||||
|
@ -543,9 +864,11 @@ init (Wire * w)
|
||||||
status = check_host (w->io.fd);
|
status = check_host (w->io.fd);
|
||||||
if (status != SANE_STATUS_GOOD)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
DBG (DBG_MSG, "init: access granted\n");
|
||||||
|
|
||||||
sanei_w_set_dir (w, WIRE_DECODE);
|
sanei_w_set_dir (w, WIRE_DECODE);
|
||||||
if (w->status)
|
if (w->status)
|
||||||
|
@ -583,8 +906,8 @@ init (Wire * w)
|
||||||
reply.version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR,
|
reply.version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR,
|
||||||
SANEI_NET_PROTOCOL_VERSION);
|
SANEI_NET_PROTOCOL_VERSION);
|
||||||
|
|
||||||
DBG (DBG_WARN, "init: access by %s@%s accepted\n",
|
DBG (DBG_WARN, "init: access granted to %s@%s\n",
|
||||||
default_username, remote_hostname);
|
default_username, remote_ip);
|
||||||
|
|
||||||
if (status == SANE_STATUS_GOOD)
|
if (status == SANE_STATUS_GOOD)
|
||||||
{
|
{
|
||||||
|
@ -612,6 +935,108 @@ init (Wire * w)
|
||||||
return 0;
|
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
|
static int
|
||||||
start_scan (Wire * w, int h, SANE_Start_Reply * reply)
|
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;
|
return fd;
|
||||||
}
|
}
|
||||||
|
#endif /* SANED_USES_AF_INDEP */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
store_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen)
|
store_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen)
|
||||||
|
@ -958,7 +1384,7 @@ process_request (Wire * w)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DBG (DBG_MSG, "process_request: access to resource `%s' accepted\n",
|
DBG (DBG_MSG, "process_request: access to resource `%s' granted\n",
|
||||||
resource);
|
resource);
|
||||||
free (resource);
|
free (resource);
|
||||||
memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */
|
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);
|
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)
|
if (reply.status == SANE_STATUS_GOOD)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
|
@ -1126,6 +1597,7 @@ process_request (Wire * w)
|
||||||
else
|
else
|
||||||
DBG (DBG_MSG, "process_request: access to data port from %s\n",
|
DBG (DBG_MSG, "process_request: access to data port from %s\n",
|
||||||
inet_ntoa (sin.sin_addr));
|
inet_ntoa (sin.sin_addr));
|
||||||
|
#endif /* SANED_USES_AF_INDEP */
|
||||||
|
|
||||||
if (data_fd < 0)
|
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
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -1287,7 +2027,7 @@ main (int argc, char *argv[])
|
||||||
p = getprotobyname ("tcp");
|
p = getprotobyname ("tcp");
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
{
|
{
|
||||||
DBG (DBG_WARN, "main:: cannot look up `tcp' protocol number");
|
DBG (DBG_WARN, "main: cannot look up `tcp' protocol number");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
level = p->p_proto;
|
level = p->p_proto;
|
||||||
|
@ -1310,3 +2050,4 @@ main (int argc, char *argv[])
|
||||||
process_request (&wire);
|
process_request (&wire);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* SANED_USES_AF_INDEP */
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
/* Should we disable SCSI generic v3? */
|
/* Should we disable SCSI generic v3? */
|
||||||
#undef DISABLE_LINUX_SG_IO
|
#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. */
|
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||||
#undef HAVE_ALLOCA
|
#undef HAVE_ALLOCA
|
||||||
|
|
||||||
|
@ -51,9 +54,15 @@
|
||||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||||
#undef HAVE_FCNTL_H
|
#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. */
|
/* Define to 1 if you have the `getenv' function. */
|
||||||
#undef HAVE_GETENV
|
#undef HAVE_GETENV
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `getnameinfo' function. */
|
||||||
|
#undef HAVE_GETNAMEINFO
|
||||||
|
|
||||||
/* Define to 1 if you have the `getpagesize' function. */
|
/* Define to 1 if you have the `getpagesize' function. */
|
||||||
#undef HAVE_GETPAGESIZE
|
#undef HAVE_GETPAGESIZE
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue