1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 1997 David Mosberger-Tang 3141cc406Sopenharmony_ci Copyright (C) 2003, 2008 Julien BLACHE <jb@jblache.org> 4141cc406Sopenharmony_ci AF-independent code + IPv6, Avahi support 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This file is part of the SANE package. 7141cc406Sopenharmony_ci 8141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 9141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 10141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 11141cc406Sopenharmony_ci License, or (at your option) any later version. 12141cc406Sopenharmony_ci 13141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 14141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 15141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16141cc406Sopenharmony_ci General Public License for more details. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 19141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 22141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 25141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 26141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 27141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 28141cc406Sopenharmony_ci account of linking the SANE library code into it. 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 31141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 32141cc406Sopenharmony_ci License. 33141cc406Sopenharmony_ci 34141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 35141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 36141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 37141cc406Sopenharmony_ci 38141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 39141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 40141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 41141cc406Sopenharmony_ci 42141cc406Sopenharmony_ci This file implements a SANE network-based meta backend. */ 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_ci#ifdef _AIX 45141cc406Sopenharmony_ci# include "../include/lalloca.h" /* MUST come first for AIX! */ 46141cc406Sopenharmony_ci#endif 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci#include "../include/sane/config.h" 49141cc406Sopenharmony_ci#include "../include/lalloca.h" 50141cc406Sopenharmony_ci#include "../include/_stdint.h" 51141cc406Sopenharmony_ci 52141cc406Sopenharmony_ci#include <errno.h> 53141cc406Sopenharmony_ci#include <fcntl.h> 54141cc406Sopenharmony_ci#include <limits.h> 55141cc406Sopenharmony_ci#include <stdlib.h> 56141cc406Sopenharmony_ci#include <string.h> 57141cc406Sopenharmony_ci#include <unistd.h> 58141cc406Sopenharmony_ci#ifdef HAVE_LIBC_H 59141cc406Sopenharmony_ci# include <libc.h> /* NeXTStep/OpenStep */ 60141cc406Sopenharmony_ci#endif 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci#include <sys/time.h> 63141cc406Sopenharmony_ci#include <sys/types.h> 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ci#include <netinet/in.h> 66141cc406Sopenharmony_ci#include <netdb.h> /* OS/2 needs this _after_ <netinet/in.h>, grrr... */ 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ci#if WITH_AVAHI 69141cc406Sopenharmony_ci# include <avahi-client/client.h> 70141cc406Sopenharmony_ci# include <avahi-client/lookup.h> 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci# include <avahi-common/thread-watch.h> 73141cc406Sopenharmony_ci# include <avahi-common/malloc.h> 74141cc406Sopenharmony_ci# include <avahi-common/error.h> 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci# define SANED_SERVICE_DNS "_sane-port._tcp" 77141cc406Sopenharmony_ci 78141cc406Sopenharmony_cistatic AvahiClient *avahi_client = NULL; 79141cc406Sopenharmony_cistatic AvahiThreadedPoll *avahi_thread = NULL; 80141cc406Sopenharmony_cistatic AvahiServiceBrowser *avahi_browser = NULL; 81141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_ci#include "../include/sane/sane.h" 84141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 85141cc406Sopenharmony_ci#include "../include/sane/sanei_net.h" 86141cc406Sopenharmony_ci#include "../include/sane/sanei_codec_bin.h" 87141cc406Sopenharmony_ci#include "net.h" 88141cc406Sopenharmony_ci 89141cc406Sopenharmony_ci#define BACKEND_NAME net 90141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 91141cc406Sopenharmony_ci 92141cc406Sopenharmony_ci#ifndef PATH_MAX 93141cc406Sopenharmony_ci# define PATH_MAX 1024 94141cc406Sopenharmony_ci#endif 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 97141cc406Sopenharmony_ci#define NET_CONFIG_FILE "net.conf" 98141cc406Sopenharmony_ci 99141cc406Sopenharmony_ci/* Please increase version number with every change 100141cc406Sopenharmony_ci (don't forget to update net.desc) */ 101141cc406Sopenharmony_ci 102141cc406Sopenharmony_ci/* define the version string depending on which network code is used */ 103141cc406Sopenharmony_ci#if defined (HAVE_GETADDRINFO) && defined (HAVE_GETNAMEINFO) 104141cc406Sopenharmony_ci# define NET_USES_AF_INDEP 105141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 106141cc406Sopenharmony_ci# define NET_VERSION "1.0.14 (AF-indep+IPv6)" 107141cc406Sopenharmony_ci# else 108141cc406Sopenharmony_ci# define NET_VERSION "1.0.14 (AF-indep)" 109141cc406Sopenharmony_ci# endif /* ENABLE_IPV6 */ 110141cc406Sopenharmony_ci#else 111141cc406Sopenharmony_ci# undef ENABLE_IPV6 112141cc406Sopenharmony_ci# define NET_VERSION "1.0.14" 113141cc406Sopenharmony_ci#endif /* HAVE_GETADDRINFO && HAVE_GETNAMEINFO */ 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_cistatic SANE_Auth_Callback auth_callback; 116141cc406Sopenharmony_cistatic Net_Device *first_device; 117141cc406Sopenharmony_cistatic Net_Scanner *first_handle; 118141cc406Sopenharmony_cistatic const SANE_Device **devlist; 119141cc406Sopenharmony_cistatic int client_big_endian; /* 1 == big endian; 0 == little endian */ 120141cc406Sopenharmony_cistatic int server_big_endian; /* 1 == big endian; 0 == little endian */ 121141cc406Sopenharmony_cistatic int depth; /* bits per pixel */ 122141cc406Sopenharmony_cistatic int connect_timeout = -1; /* timeout for connection to saned */ 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_ci#ifndef NET_USES_AF_INDEP 125141cc406Sopenharmony_cistatic int saned_port; 126141cc406Sopenharmony_ci#endif /* !NET_USES_AF_INDEP */ 127141cc406Sopenharmony_ci 128141cc406Sopenharmony_ci/* This variable is only needed, if the depth is 16bit/channel and 129141cc406Sopenharmony_ci client/server have different endianness. A value of -1 means, that there's 130141cc406Sopenharmony_ci no hang over; otherwise the value has to be casted to SANE_Byte. hang_over 131141cc406Sopenharmony_ci means, that there is a remaining byte from a previous call to sane_read, 132141cc406Sopenharmony_ci which could not be byte-swapped, e.g. because the frontend requested an odd 133141cc406Sopenharmony_ci number of bytes. 134141cc406Sopenharmony_ci*/ 135141cc406Sopenharmony_cistatic int hang_over; 136141cc406Sopenharmony_ci 137141cc406Sopenharmony_ci/* This variable is only needed, if the depth is 16bit/channel and 138141cc406Sopenharmony_ci client/server have different endianness. A value of -1 means, that there's 139141cc406Sopenharmony_ci no left over; otherwise the value has to be casted to SANE_Byte. left_over 140141cc406Sopenharmony_ci means, that there is a remaining byte from a previous call to sane_read, 141141cc406Sopenharmony_ci which already is in the correct byte order, but could not be returned, 142141cc406Sopenharmony_ci e.g. because the frontend requested only one byte per call. 143141cc406Sopenharmony_ci*/ 144141cc406Sopenharmony_cistatic int left_over; 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci 147141cc406Sopenharmony_ci#ifdef NET_USES_AF_INDEP 148141cc406Sopenharmony_cistatic SANE_Status 149141cc406Sopenharmony_ciadd_device (const char *name, Net_Device ** ndp) 150141cc406Sopenharmony_ci{ 151141cc406Sopenharmony_ci struct addrinfo hints; 152141cc406Sopenharmony_ci struct addrinfo *res; 153141cc406Sopenharmony_ci struct addrinfo *resp; 154141cc406Sopenharmony_ci struct sockaddr_in *sin; 155141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 156141cc406Sopenharmony_ci struct sockaddr_in6 *sin6; 157141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci Net_Device *nd = NULL; 160141cc406Sopenharmony_ci 161141cc406Sopenharmony_ci int error; 162141cc406Sopenharmony_ci short sane_port = htons (6566); 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_ci DBG (1, "add_device: adding backend %s\n", name); 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_ci for (nd = first_device; nd; nd = nd->next) 167141cc406Sopenharmony_ci if (strcmp (nd->name, name) == 0) 168141cc406Sopenharmony_ci { 169141cc406Sopenharmony_ci DBG (1, "add_device: already in list\n"); 170141cc406Sopenharmony_ci 171141cc406Sopenharmony_ci if (ndp) 172141cc406Sopenharmony_ci *ndp = nd; 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 175141cc406Sopenharmony_ci } 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_ci memset (&hints, 0, sizeof(hints)); 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 180141cc406Sopenharmony_ci hints.ai_family = PF_UNSPEC; 181141cc406Sopenharmony_ci# else 182141cc406Sopenharmony_ci hints.ai_family = PF_INET; 183141cc406Sopenharmony_ci# endif /* ENABLE_IPV6 */ 184141cc406Sopenharmony_ci 185141cc406Sopenharmony_ci error = getaddrinfo (name, "sane-port", &hints, &res); 186141cc406Sopenharmony_ci if (error) 187141cc406Sopenharmony_ci { 188141cc406Sopenharmony_ci error = getaddrinfo (name, NULL, &hints, &res); 189141cc406Sopenharmony_ci if (error) 190141cc406Sopenharmony_ci { 191141cc406Sopenharmony_ci DBG (1, "add_device: error while getting address of host %s: %s\n", 192141cc406Sopenharmony_ci name, gai_strerror (error)); 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 195141cc406Sopenharmony_ci } 196141cc406Sopenharmony_ci else 197141cc406Sopenharmony_ci { 198141cc406Sopenharmony_ci for (resp = res; resp != NULL; resp = resp->ai_next) 199141cc406Sopenharmony_ci { 200141cc406Sopenharmony_ci switch (resp->ai_family) 201141cc406Sopenharmony_ci { 202141cc406Sopenharmony_ci case AF_INET: 203141cc406Sopenharmony_ci sin = (struct sockaddr_in *) resp->ai_addr; 204141cc406Sopenharmony_ci sin->sin_port = sane_port; 205141cc406Sopenharmony_ci break; 206141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 207141cc406Sopenharmony_ci case AF_INET6: 208141cc406Sopenharmony_ci sin6 = (struct sockaddr_in6 *) resp->ai_addr; 209141cc406Sopenharmony_ci sin6->sin6_port = sane_port; 210141cc406Sopenharmony_ci break; 211141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 212141cc406Sopenharmony_ci } 213141cc406Sopenharmony_ci } 214141cc406Sopenharmony_ci } 215141cc406Sopenharmony_ci } 216141cc406Sopenharmony_ci 217141cc406Sopenharmony_ci nd = malloc (sizeof (Net_Device)); 218141cc406Sopenharmony_ci if (!nd) 219141cc406Sopenharmony_ci { 220141cc406Sopenharmony_ci DBG (1, "add_device: not enough memory for Net_Device struct\n"); 221141cc406Sopenharmony_ci 222141cc406Sopenharmony_ci freeaddrinfo (res); 223141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 224141cc406Sopenharmony_ci } 225141cc406Sopenharmony_ci 226141cc406Sopenharmony_ci memset (nd, 0, sizeof (Net_Device)); 227141cc406Sopenharmony_ci nd->name = strdup (name); 228141cc406Sopenharmony_ci if (!nd->name) 229141cc406Sopenharmony_ci { 230141cc406Sopenharmony_ci DBG (1, "add_device: not enough memory to duplicate name\n"); 231141cc406Sopenharmony_ci free(nd); 232141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 233141cc406Sopenharmony_ci } 234141cc406Sopenharmony_ci 235141cc406Sopenharmony_ci nd->addr = res; 236141cc406Sopenharmony_ci nd->ctl = -1; 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_ci nd->next = first_device; 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci first_device = nd; 241141cc406Sopenharmony_ci 242141cc406Sopenharmony_ci if (ndp) 243141cc406Sopenharmony_ci *ndp = nd; 244141cc406Sopenharmony_ci DBG (2, "add_device: backend %s added\n", name); 245141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 246141cc406Sopenharmony_ci} 247141cc406Sopenharmony_ci 248141cc406Sopenharmony_ci#else /* !NET_USES_AF_INDEP */ 249141cc406Sopenharmony_ci 250141cc406Sopenharmony_cistatic SANE_Status 251141cc406Sopenharmony_ciadd_device (const char *name, Net_Device ** ndp) 252141cc406Sopenharmony_ci{ 253141cc406Sopenharmony_ci struct hostent *he; 254141cc406Sopenharmony_ci Net_Device *nd; 255141cc406Sopenharmony_ci struct sockaddr_in *sin; 256141cc406Sopenharmony_ci 257141cc406Sopenharmony_ci DBG (1, "add_device: adding backend %s\n", name); 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_ci for (nd = first_device; nd; nd = nd->next) 260141cc406Sopenharmony_ci if (strcmp (nd->name, name) == 0) 261141cc406Sopenharmony_ci { 262141cc406Sopenharmony_ci DBG (1, "add_device: already in list\n"); 263141cc406Sopenharmony_ci 264141cc406Sopenharmony_ci if (ndp) 265141cc406Sopenharmony_ci *ndp = nd; 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 268141cc406Sopenharmony_ci } 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci he = gethostbyname (name); 271141cc406Sopenharmony_ci if (!he) 272141cc406Sopenharmony_ci { 273141cc406Sopenharmony_ci DBG (1, "add_device: can't get address of host %s\n", name); 274141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 275141cc406Sopenharmony_ci } 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci if (he->h_addrtype != AF_INET) 278141cc406Sopenharmony_ci { 279141cc406Sopenharmony_ci DBG (1, "add_device: don't know how to deal with addr family %d\n", 280141cc406Sopenharmony_ci he->h_addrtype); 281141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 282141cc406Sopenharmony_ci } 283141cc406Sopenharmony_ci 284141cc406Sopenharmony_ci nd = malloc (sizeof (*nd)); 285141cc406Sopenharmony_ci if (!nd) 286141cc406Sopenharmony_ci { 287141cc406Sopenharmony_ci DBG (1, "add_device: not enough memory for Net_Device struct\n"); 288141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 289141cc406Sopenharmony_ci } 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ci memset (nd, 0, sizeof (*nd)); 292141cc406Sopenharmony_ci nd->name = strdup (name); 293141cc406Sopenharmony_ci if (!nd->name) 294141cc406Sopenharmony_ci { 295141cc406Sopenharmony_ci DBG (1, "add_device: not enough memory to duplicate name\n"); 296141cc406Sopenharmony_ci free (nd); 297141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 298141cc406Sopenharmony_ci } 299141cc406Sopenharmony_ci nd->addr.sa_family = he->h_addrtype; 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci sin = (struct sockaddr_in *) &nd->addr; 302141cc406Sopenharmony_ci memcpy (&sin->sin_addr, he->h_addr_list[0], he->h_length); 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci nd->ctl = -1; 305141cc406Sopenharmony_ci nd->next = first_device; 306141cc406Sopenharmony_ci first_device = nd; 307141cc406Sopenharmony_ci if (ndp) 308141cc406Sopenharmony_ci *ndp = nd; 309141cc406Sopenharmony_ci DBG (2, "add_device: backend %s added\n", name); 310141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 311141cc406Sopenharmony_ci} 312141cc406Sopenharmony_ci#endif /* NET_USES_AF_INDEP */ 313141cc406Sopenharmony_ci 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_ci#ifdef NET_USES_AF_INDEP 316141cc406Sopenharmony_cistatic SANE_Status 317141cc406Sopenharmony_ciconnect_dev (Net_Device * dev) 318141cc406Sopenharmony_ci{ 319141cc406Sopenharmony_ci struct addrinfo *addrp; 320141cc406Sopenharmony_ci 321141cc406Sopenharmony_ci SANE_Word version_code; 322141cc406Sopenharmony_ci SANE_Init_Reply reply; 323141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_IO_ERROR; 324141cc406Sopenharmony_ci SANE_Init_Req req; 325141cc406Sopenharmony_ci SANE_Bool connected = SANE_FALSE; 326141cc406Sopenharmony_ci#ifdef TCP_NODELAY 327141cc406Sopenharmony_ci int on = 1; 328141cc406Sopenharmony_ci int level = -1; 329141cc406Sopenharmony_ci#endif 330141cc406Sopenharmony_ci struct timeval tv; 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_ci int i; 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ci DBG (2, "connect_dev: trying to connect to %s\n", dev->name); 335141cc406Sopenharmony_ci 336141cc406Sopenharmony_ci for (addrp = dev->addr, i = 0; (addrp != NULL) && (connected == SANE_FALSE); addrp = addrp->ai_next, i++) 337141cc406Sopenharmony_ci { 338141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 339141cc406Sopenharmony_ci if ((addrp->ai_family != AF_INET) && (addrp->ai_family != AF_INET6)) 340141cc406Sopenharmony_ci# else /* !ENABLE_IPV6 */ 341141cc406Sopenharmony_ci if (addrp->ai_family != AF_INET) 342141cc406Sopenharmony_ci# endif /* ENABLE_IPV6 */ 343141cc406Sopenharmony_ci { 344141cc406Sopenharmony_ci DBG (1, "connect_dev: [%d] don't know how to deal with addr family %d\n", 345141cc406Sopenharmony_ci i, addrp->ai_family); 346141cc406Sopenharmony_ci continue; 347141cc406Sopenharmony_ci } 348141cc406Sopenharmony_ci 349141cc406Sopenharmony_ci dev->ctl = socket (addrp->ai_family, SOCK_STREAM, 0); 350141cc406Sopenharmony_ci if (dev->ctl < 0) 351141cc406Sopenharmony_ci { 352141cc406Sopenharmony_ci DBG (1, "connect_dev: [%d] failed to obtain socket (%s)\n", 353141cc406Sopenharmony_ci i, strerror (errno)); 354141cc406Sopenharmony_ci dev->ctl = -1; 355141cc406Sopenharmony_ci continue; 356141cc406Sopenharmony_ci } 357141cc406Sopenharmony_ci 358141cc406Sopenharmony_ci /* Set SO_SNDTIMEO for the connection to saned */ 359141cc406Sopenharmony_ci if (connect_timeout > 0) 360141cc406Sopenharmony_ci { 361141cc406Sopenharmony_ci tv.tv_sec = connect_timeout; 362141cc406Sopenharmony_ci tv.tv_usec = 0; 363141cc406Sopenharmony_ci 364141cc406Sopenharmony_ci if (setsockopt (dev->ctl, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) 365141cc406Sopenharmony_ci { 366141cc406Sopenharmony_ci DBG (1, "connect_dev: [%d] failed to set SO_SNDTIMEO (%s)\n", i, strerror (errno)); 367141cc406Sopenharmony_ci } 368141cc406Sopenharmony_ci } 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ci if (connect (dev->ctl, addrp->ai_addr, addrp->ai_addrlen) < 0) 371141cc406Sopenharmony_ci { 372141cc406Sopenharmony_ci DBG (1, "connect_dev: [%d] failed to connect (%s)\n", i, strerror (errno)); 373141cc406Sopenharmony_ci dev->ctl = -1; 374141cc406Sopenharmony_ci continue; 375141cc406Sopenharmony_ci } 376141cc406Sopenharmony_ci DBG (3, "connect_dev: [%d] connection succeeded (%s)\n", i, (addrp->ai_family == AF_INET6) ? "IPv6" : "IPv4"); 377141cc406Sopenharmony_ci dev->addr_used = addrp; 378141cc406Sopenharmony_ci connected = SANE_TRUE; 379141cc406Sopenharmony_ci } 380141cc406Sopenharmony_ci 381141cc406Sopenharmony_ci if (connected != SANE_TRUE) 382141cc406Sopenharmony_ci { 383141cc406Sopenharmony_ci DBG (1, "connect_dev: couldn't connect to host (see messages above)\n"); 384141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 385141cc406Sopenharmony_ci } 386141cc406Sopenharmony_ci 387141cc406Sopenharmony_ci#else /* !NET_USES_AF_INDEP */ 388141cc406Sopenharmony_ci 389141cc406Sopenharmony_cistatic SANE_Status 390141cc406Sopenharmony_ciconnect_dev (Net_Device * dev) 391141cc406Sopenharmony_ci{ 392141cc406Sopenharmony_ci struct sockaddr_in *sin; 393141cc406Sopenharmony_ci SANE_Word version_code; 394141cc406Sopenharmony_ci SANE_Init_Reply reply; 395141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_IO_ERROR; 396141cc406Sopenharmony_ci SANE_Init_Req req; 397141cc406Sopenharmony_ci#ifdef TCP_NODELAY 398141cc406Sopenharmony_ci int on = 1; 399141cc406Sopenharmony_ci int level = -1; 400141cc406Sopenharmony_ci#endif 401141cc406Sopenharmony_ci struct timeval tv; 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_ci DBG (2, "connect_dev: trying to connect to %s\n", dev->name); 404141cc406Sopenharmony_ci 405141cc406Sopenharmony_ci if (dev->addr.sa_family != AF_INET) 406141cc406Sopenharmony_ci { 407141cc406Sopenharmony_ci DBG (1, "connect_dev: don't know how to deal with addr family %d\n", 408141cc406Sopenharmony_ci dev->addr.sa_family); 409141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 410141cc406Sopenharmony_ci } 411141cc406Sopenharmony_ci 412141cc406Sopenharmony_ci dev->ctl = socket (dev->addr.sa_family, SOCK_STREAM, 0); 413141cc406Sopenharmony_ci if (dev->ctl < 0) 414141cc406Sopenharmony_ci { 415141cc406Sopenharmony_ci DBG (1, "connect_dev: failed to obtain socket (%s)\n", 416141cc406Sopenharmony_ci strerror (errno)); 417141cc406Sopenharmony_ci dev->ctl = -1; 418141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 419141cc406Sopenharmony_ci } 420141cc406Sopenharmony_ci sin = (struct sockaddr_in *) &dev->addr; 421141cc406Sopenharmony_ci sin->sin_port = saned_port; 422141cc406Sopenharmony_ci 423141cc406Sopenharmony_ci 424141cc406Sopenharmony_ci /* Set SO_SNDTIMEO for the connection to saned */ 425141cc406Sopenharmony_ci if (connect_timeout > 0) 426141cc406Sopenharmony_ci { 427141cc406Sopenharmony_ci tv.tv_sec = connect_timeout; 428141cc406Sopenharmony_ci tv.tv_usec = 0; 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ci if (setsockopt (dev->ctl, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) 431141cc406Sopenharmony_ci { 432141cc406Sopenharmony_ci DBG (1, "connect_dev: failed to set SO_SNDTIMEO (%s)\n", strerror (errno)); 433141cc406Sopenharmony_ci } 434141cc406Sopenharmony_ci } 435141cc406Sopenharmony_ci 436141cc406Sopenharmony_ci if (connect (dev->ctl, &dev->addr, sizeof (dev->addr)) < 0) 437141cc406Sopenharmony_ci { 438141cc406Sopenharmony_ci DBG (1, "connect_dev: failed to connect (%s)\n", strerror (errno)); 439141cc406Sopenharmony_ci dev->ctl = -1; 440141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 441141cc406Sopenharmony_ci } 442141cc406Sopenharmony_ci DBG (3, "connect_dev: connection succeeded\n"); 443141cc406Sopenharmony_ci#endif /* NET_USES_AF_INDEP */ 444141cc406Sopenharmony_ci 445141cc406Sopenharmony_ci /* We're connected now, so reset SO_SNDTIMEO to the default value of 0 */ 446141cc406Sopenharmony_ci if (connect_timeout > 0) 447141cc406Sopenharmony_ci { 448141cc406Sopenharmony_ci tv.tv_sec = 0; 449141cc406Sopenharmony_ci tv.tv_usec = 0; 450141cc406Sopenharmony_ci 451141cc406Sopenharmony_ci if (setsockopt (dev->ctl, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) 452141cc406Sopenharmony_ci { 453141cc406Sopenharmony_ci DBG (1, "connect_dev: failed to reset SO_SNDTIMEO (%s)\n", strerror (errno)); 454141cc406Sopenharmony_ci } 455141cc406Sopenharmony_ci } 456141cc406Sopenharmony_ci 457141cc406Sopenharmony_ci#ifdef TCP_NODELAY 458141cc406Sopenharmony_ci# ifdef SOL_TCP 459141cc406Sopenharmony_ci level = SOL_TCP; 460141cc406Sopenharmony_ci# else /* !SOL_TCP */ 461141cc406Sopenharmony_ci /* Look up the protocol level in the protocols database. */ 462141cc406Sopenharmony_ci { 463141cc406Sopenharmony_ci struct protoent *p; 464141cc406Sopenharmony_ci p = getprotobyname ("tcp"); 465141cc406Sopenharmony_ci if (p == 0) 466141cc406Sopenharmony_ci DBG (1, "connect_dev: cannot look up `tcp' protocol number"); 467141cc406Sopenharmony_ci else 468141cc406Sopenharmony_ci level = p->p_proto; 469141cc406Sopenharmony_ci } 470141cc406Sopenharmony_ci# endif /* SOL_TCP */ 471141cc406Sopenharmony_ci 472141cc406Sopenharmony_ci if (level == -1 || 473141cc406Sopenharmony_ci setsockopt (dev->ctl, level, TCP_NODELAY, &on, sizeof (on))) 474141cc406Sopenharmony_ci DBG (1, "connect_dev: failed to put send socket in TCP_NODELAY mode (%s)", 475141cc406Sopenharmony_ci strerror (errno)); 476141cc406Sopenharmony_ci#endif /* !TCP_NODELAY */ 477141cc406Sopenharmony_ci 478141cc406Sopenharmony_ci DBG (2, "connect_dev: sanei_w_init\n"); 479141cc406Sopenharmony_ci sanei_w_init (&dev->wire, sanei_codec_bin_init); 480141cc406Sopenharmony_ci dev->wire.io.fd = dev->ctl; 481141cc406Sopenharmony_ci dev->wire.io.read = read; 482141cc406Sopenharmony_ci dev->wire.io.write = write; 483141cc406Sopenharmony_ci 484141cc406Sopenharmony_ci /* exchange version codes with the server: */ 485141cc406Sopenharmony_ci req.version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 486141cc406Sopenharmony_ci SANEI_NET_PROTOCOL_VERSION); 487141cc406Sopenharmony_ci req.username = getlogin (); 488141cc406Sopenharmony_ci DBG (2, "connect_dev: net_init (user=%s, local version=%d.%d.%d)\n", 489141cc406Sopenharmony_ci req.username, V_MAJOR, V_MINOR, SANEI_NET_PROTOCOL_VERSION); 490141cc406Sopenharmony_ci sanei_w_call (&dev->wire, SANE_NET_INIT, 491141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_init_req, &req, 492141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_init_reply, &reply); 493141cc406Sopenharmony_ci 494141cc406Sopenharmony_ci if (dev->wire.status != 0) 495141cc406Sopenharmony_ci { 496141cc406Sopenharmony_ci DBG (1, "connect_dev: argument marshalling error (%s)\n", 497141cc406Sopenharmony_ci strerror (dev->wire.status)); 498141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 499141cc406Sopenharmony_ci goto fail; 500141cc406Sopenharmony_ci } 501141cc406Sopenharmony_ci 502141cc406Sopenharmony_ci status = reply.status; 503141cc406Sopenharmony_ci version_code = reply.version_code; 504141cc406Sopenharmony_ci DBG (2, "connect_dev: freeing init reply (status=%s, remote " 505141cc406Sopenharmony_ci "version=%d.%d.%d)\n", sane_strstatus (status), 506141cc406Sopenharmony_ci SANE_VERSION_MAJOR (version_code), 507141cc406Sopenharmony_ci SANE_VERSION_MINOR (version_code), SANE_VERSION_BUILD (version_code)); 508141cc406Sopenharmony_ci sanei_w_free (&dev->wire, (WireCodecFunc) sanei_w_init_reply, &reply); 509141cc406Sopenharmony_ci 510141cc406Sopenharmony_ci if (status != 0) 511141cc406Sopenharmony_ci { 512141cc406Sopenharmony_ci DBG (1, "connect_dev: access to %s denied\n", dev->name); 513141cc406Sopenharmony_ci goto fail; 514141cc406Sopenharmony_ci } 515141cc406Sopenharmony_ci if (SANE_VERSION_MAJOR (version_code) != V_MAJOR) 516141cc406Sopenharmony_ci { 517141cc406Sopenharmony_ci DBG (1, "connect_dev: major version mismatch: got %d, expected %d\n", 518141cc406Sopenharmony_ci SANE_VERSION_MAJOR (version_code), V_MAJOR); 519141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 520141cc406Sopenharmony_ci goto fail; 521141cc406Sopenharmony_ci } 522141cc406Sopenharmony_ci if (SANE_VERSION_BUILD (version_code) != SANEI_NET_PROTOCOL_VERSION 523141cc406Sopenharmony_ci && SANE_VERSION_BUILD (version_code) != 2) 524141cc406Sopenharmony_ci { 525141cc406Sopenharmony_ci DBG (1, "connect_dev: network protocol version mismatch: " 526141cc406Sopenharmony_ci "got %d, expected %d\n", 527141cc406Sopenharmony_ci SANE_VERSION_BUILD (version_code), SANEI_NET_PROTOCOL_VERSION); 528141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 529141cc406Sopenharmony_ci goto fail; 530141cc406Sopenharmony_ci } 531141cc406Sopenharmony_ci dev->wire.version = SANE_VERSION_BUILD (version_code); 532141cc406Sopenharmony_ci DBG (4, "connect_dev: done\n"); 533141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 534141cc406Sopenharmony_ci 535141cc406Sopenharmony_cifail: 536141cc406Sopenharmony_ci DBG (2, "connect_dev: closing connection to %s\n", dev->name); 537141cc406Sopenharmony_ci close (dev->ctl); 538141cc406Sopenharmony_ci dev->ctl = -1; 539141cc406Sopenharmony_ci return status; 540141cc406Sopenharmony_ci} 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci 543141cc406Sopenharmony_cistatic SANE_Status 544141cc406Sopenharmony_cifetch_options (Net_Scanner * s) 545141cc406Sopenharmony_ci{ 546141cc406Sopenharmony_ci int option_number; 547141cc406Sopenharmony_ci DBG (3, "fetch_options: %p\n", (void *) s); 548141cc406Sopenharmony_ci 549141cc406Sopenharmony_ci if (s->opt.num_options) 550141cc406Sopenharmony_ci { 551141cc406Sopenharmony_ci DBG (2, "fetch_options: %d option descriptors cached... freeing\n", 552141cc406Sopenharmony_ci s->opt.num_options); 553141cc406Sopenharmony_ci sanei_w_set_dir (&s->hw->wire, WIRE_FREE); 554141cc406Sopenharmony_ci s->hw->wire.status = 0; 555141cc406Sopenharmony_ci sanei_w_option_descriptor_array (&s->hw->wire, &s->opt); 556141cc406Sopenharmony_ci if (s->hw->wire.status) 557141cc406Sopenharmony_ci { 558141cc406Sopenharmony_ci DBG (1, "fetch_options: failed to free old list (%s)\n", 559141cc406Sopenharmony_ci strerror (s->hw->wire.status)); 560141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 561141cc406Sopenharmony_ci } 562141cc406Sopenharmony_ci } 563141cc406Sopenharmony_ci DBG (3, "fetch_options: get_option_descriptors\n"); 564141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_GET_OPTION_DESCRIPTORS, 565141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &s->handle, 566141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_option_descriptor_array, &s->opt); 567141cc406Sopenharmony_ci if (s->hw->wire.status) 568141cc406Sopenharmony_ci { 569141cc406Sopenharmony_ci DBG (1, "fetch_options: failed to get option descriptors (%s)\n", 570141cc406Sopenharmony_ci strerror (s->hw->wire.status)); 571141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 572141cc406Sopenharmony_ci } 573141cc406Sopenharmony_ci 574141cc406Sopenharmony_ci if (s->local_opt.num_options == 0) 575141cc406Sopenharmony_ci { 576141cc406Sopenharmony_ci DBG (3, "fetch_options: creating %d local option descriptors\n", 577141cc406Sopenharmony_ci s->opt.num_options); 578141cc406Sopenharmony_ci s->local_opt.desc = 579141cc406Sopenharmony_ci malloc (s->opt.num_options * sizeof (s->local_opt.desc)); 580141cc406Sopenharmony_ci if (!s->local_opt.desc) 581141cc406Sopenharmony_ci { 582141cc406Sopenharmony_ci DBG (1, "fetch_options: couldn't malloc s->local_opt.desc\n"); 583141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 584141cc406Sopenharmony_ci } 585141cc406Sopenharmony_ci for (option_number = 0; 586141cc406Sopenharmony_ci option_number < s->opt.num_options; 587141cc406Sopenharmony_ci option_number++) 588141cc406Sopenharmony_ci { 589141cc406Sopenharmony_ci s->local_opt.desc[option_number] = 590141cc406Sopenharmony_ci malloc (sizeof (SANE_Option_Descriptor)); 591141cc406Sopenharmony_ci if (!s->local_opt.desc[option_number]) 592141cc406Sopenharmony_ci { 593141cc406Sopenharmony_ci DBG (1, "fetch_options: couldn't malloc " 594141cc406Sopenharmony_ci "s->local_opt.desc[%d]\n", option_number); 595141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 596141cc406Sopenharmony_ci } 597141cc406Sopenharmony_ci } 598141cc406Sopenharmony_ci s->local_opt.num_options = s->opt.num_options; 599141cc406Sopenharmony_ci } 600141cc406Sopenharmony_ci else if (s->local_opt.num_options != s->opt.num_options) 601141cc406Sopenharmony_ci { 602141cc406Sopenharmony_ci DBG (1, "fetch_options: option number count changed during runtime?\n"); 603141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 604141cc406Sopenharmony_ci } 605141cc406Sopenharmony_ci 606141cc406Sopenharmony_ci DBG (3, "fetch_options: copying %d option descriptors\n", 607141cc406Sopenharmony_ci s->opt.num_options); 608141cc406Sopenharmony_ci 609141cc406Sopenharmony_ci for (option_number = 0; option_number < s->opt.num_options; option_number++) 610141cc406Sopenharmony_ci { 611141cc406Sopenharmony_ci memcpy (s->local_opt.desc[option_number], s->opt.desc[option_number], 612141cc406Sopenharmony_ci sizeof (SANE_Option_Descriptor)); 613141cc406Sopenharmony_ci } 614141cc406Sopenharmony_ci 615141cc406Sopenharmony_ci s->options_valid = 1; 616141cc406Sopenharmony_ci DBG (3, "fetch_options: %d options fetched\n", s->opt.num_options); 617141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 618141cc406Sopenharmony_ci} 619141cc406Sopenharmony_ci 620141cc406Sopenharmony_cistatic SANE_Status 621141cc406Sopenharmony_cido_cancel (Net_Scanner * s) 622141cc406Sopenharmony_ci{ 623141cc406Sopenharmony_ci DBG (2, "do_cancel: %p\n", (void *) s); 624141cc406Sopenharmony_ci s->hw->auth_active = 0; 625141cc406Sopenharmony_ci if (s->data >= 0) 626141cc406Sopenharmony_ci { 627141cc406Sopenharmony_ci DBG (3, "do_cancel: closing data pipe\n"); 628141cc406Sopenharmony_ci close (s->data); 629141cc406Sopenharmony_ci s->data = -1; 630141cc406Sopenharmony_ci } 631141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 632141cc406Sopenharmony_ci} 633141cc406Sopenharmony_ci 634141cc406Sopenharmony_cistatic void 635141cc406Sopenharmony_cido_authorization (Net_Device * dev, SANE_String resource) 636141cc406Sopenharmony_ci{ 637141cc406Sopenharmony_ci SANE_Authorization_Req req; 638141cc406Sopenharmony_ci SANE_Char username[SANE_MAX_USERNAME_LEN]; 639141cc406Sopenharmony_ci SANE_Char password[SANE_MAX_PASSWORD_LEN]; 640141cc406Sopenharmony_ci char *net_resource; 641141cc406Sopenharmony_ci 642141cc406Sopenharmony_ci DBG (2, "do_authorization: dev=%p resource=%s\n", (void *) dev, resource); 643141cc406Sopenharmony_ci 644141cc406Sopenharmony_ci dev->auth_active = 1; 645141cc406Sopenharmony_ci 646141cc406Sopenharmony_ci memset (&req, 0, sizeof (req)); 647141cc406Sopenharmony_ci memset (username, 0, sizeof (SANE_Char) * SANE_MAX_USERNAME_LEN); 648141cc406Sopenharmony_ci memset (password, 0, sizeof (SANE_Char) * SANE_MAX_PASSWORD_LEN); 649141cc406Sopenharmony_ci 650141cc406Sopenharmony_ci net_resource = malloc (strlen (resource) + 6 + strlen (dev->name)); 651141cc406Sopenharmony_ci 652141cc406Sopenharmony_ci if (net_resource != NULL) 653141cc406Sopenharmony_ci { 654141cc406Sopenharmony_ci sprintf (net_resource, "net:%s:%s", dev->name, resource); 655141cc406Sopenharmony_ci if (auth_callback) 656141cc406Sopenharmony_ci { 657141cc406Sopenharmony_ci DBG (2, "do_authorization: invoking auth_callback, resource = %s\n", 658141cc406Sopenharmony_ci net_resource); 659141cc406Sopenharmony_ci (*auth_callback) (net_resource, username, password); 660141cc406Sopenharmony_ci } 661141cc406Sopenharmony_ci else 662141cc406Sopenharmony_ci DBG (1, "do_authorization: no auth_callback present\n"); 663141cc406Sopenharmony_ci free (net_resource); 664141cc406Sopenharmony_ci } 665141cc406Sopenharmony_ci else /* Is this necessary? If we don't have these few bytes we will get 666141cc406Sopenharmony_ci in trouble later anyway */ 667141cc406Sopenharmony_ci { 668141cc406Sopenharmony_ci DBG (1, "do_authorization: not enough memory for net_resource\n"); 669141cc406Sopenharmony_ci if (auth_callback) 670141cc406Sopenharmony_ci { 671141cc406Sopenharmony_ci DBG (2, "do_authorization: invoking auth_callback, resource = %s\n", 672141cc406Sopenharmony_ci resource); 673141cc406Sopenharmony_ci (*auth_callback) (resource, username, password); 674141cc406Sopenharmony_ci } 675141cc406Sopenharmony_ci else 676141cc406Sopenharmony_ci DBG (1, "do_authorization: no auth_callback present\n"); 677141cc406Sopenharmony_ci } 678141cc406Sopenharmony_ci 679141cc406Sopenharmony_ci if (dev->auth_active) 680141cc406Sopenharmony_ci { 681141cc406Sopenharmony_ci SANE_Word ack; 682141cc406Sopenharmony_ci 683141cc406Sopenharmony_ci req.resource = resource; 684141cc406Sopenharmony_ci req.username = username; 685141cc406Sopenharmony_ci req.password = password; 686141cc406Sopenharmony_ci DBG (2, "do_authorization: relaying authentication data\n"); 687141cc406Sopenharmony_ci sanei_w_call (&dev->wire, SANE_NET_AUTHORIZE, 688141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_authorization_req, &req, 689141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &ack); 690141cc406Sopenharmony_ci } 691141cc406Sopenharmony_ci else 692141cc406Sopenharmony_ci DBG (1, "do_authorization: auth_active is false... strange\n"); 693141cc406Sopenharmony_ci} 694141cc406Sopenharmony_ci 695141cc406Sopenharmony_ci 696141cc406Sopenharmony_ci#if WITH_AVAHI 697141cc406Sopenharmony_cistatic void 698141cc406Sopenharmony_cinet_avahi_resolve_callback (AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, 699141cc406Sopenharmony_ci AvahiResolverEvent event, const char *name, const char *type, 700141cc406Sopenharmony_ci const char *domain, const char *host_name, const AvahiAddress *address, 701141cc406Sopenharmony_ci uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, 702141cc406Sopenharmony_ci void *userdata) 703141cc406Sopenharmony_ci{ 704141cc406Sopenharmony_ci char a[AVAHI_ADDRESS_STR_MAX]; 705141cc406Sopenharmony_ci char *t; 706141cc406Sopenharmony_ci 707141cc406Sopenharmony_ci /* unused */ 708141cc406Sopenharmony_ci (void) interface; 709141cc406Sopenharmony_ci (void) protocol; 710141cc406Sopenharmony_ci (void) userdata; 711141cc406Sopenharmony_ci 712141cc406Sopenharmony_ci if (!r) 713141cc406Sopenharmony_ci return; 714141cc406Sopenharmony_ci 715141cc406Sopenharmony_ci switch (event) 716141cc406Sopenharmony_ci { 717141cc406Sopenharmony_ci case AVAHI_RESOLVER_FAILURE: 718141cc406Sopenharmony_ci DBG (1, "net_avahi_resolve_callback: failed to resolve service '%s' of type '%s' in domain '%s': %s\n", 719141cc406Sopenharmony_ci name, type, domain, avahi_strerror (avahi_client_errno (avahi_service_resolver_get_client (r)))); 720141cc406Sopenharmony_ci break; 721141cc406Sopenharmony_ci 722141cc406Sopenharmony_ci case AVAHI_RESOLVER_FOUND: 723141cc406Sopenharmony_ci DBG (3, "net_avahi_resolve_callback: service '%s' of type '%s' in domain '%s':\n", name, type, domain); 724141cc406Sopenharmony_ci 725141cc406Sopenharmony_ci avahi_address_snprint(a, sizeof (a), address); 726141cc406Sopenharmony_ci t = avahi_string_list_to_string (txt); 727141cc406Sopenharmony_ci 728141cc406Sopenharmony_ci DBG (3, "\t%s:%u (%s)\n\tTXT=%s\n\tcookie is %u\n\tis_local: %i\n\tour_own: %i\n" 729141cc406Sopenharmony_ci "\twide_area: %i\n\tmulticast: %i\n\tcached: %i\n", 730141cc406Sopenharmony_ci host_name, port, a, t, avahi_string_list_get_service_cookie (txt), 731141cc406Sopenharmony_ci !!(flags & AVAHI_LOOKUP_RESULT_LOCAL), !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN), 732141cc406Sopenharmony_ci !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA), !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST), 733141cc406Sopenharmony_ci !!(flags & AVAHI_LOOKUP_RESULT_CACHED)); 734141cc406Sopenharmony_ci 735141cc406Sopenharmony_ci /* TODO: evaluate TXT record */ 736141cc406Sopenharmony_ci 737141cc406Sopenharmony_ci /* Try first with the name */ 738141cc406Sopenharmony_ci if (add_device (host_name, NULL) != SANE_STATUS_GOOD) 739141cc406Sopenharmony_ci { 740141cc406Sopenharmony_ci DBG (1, "net_avahi_resolve_callback: couldn't add backend with name %s\n", host_name); 741141cc406Sopenharmony_ci 742141cc406Sopenharmony_ci /* Then try the raw IP address */ 743141cc406Sopenharmony_ci if (add_device (t, NULL) != SANE_STATUS_GOOD) 744141cc406Sopenharmony_ci DBG (1, "net_avahi_resolve_callback: couldn't add backend with IP address %s either\n", t); 745141cc406Sopenharmony_ci } 746141cc406Sopenharmony_ci 747141cc406Sopenharmony_ci avahi_free (t); 748141cc406Sopenharmony_ci break; 749141cc406Sopenharmony_ci } 750141cc406Sopenharmony_ci 751141cc406Sopenharmony_ci avahi_service_resolver_free(r); 752141cc406Sopenharmony_ci} 753141cc406Sopenharmony_ci 754141cc406Sopenharmony_cistatic void 755141cc406Sopenharmony_cinet_avahi_browse_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, 756141cc406Sopenharmony_ci AvahiBrowserEvent event, const char *name, const char *type, 757141cc406Sopenharmony_ci const char *domain, AvahiLookupResultFlags flags, void *userdata) 758141cc406Sopenharmony_ci{ 759141cc406Sopenharmony_ci AvahiProtocol proto; 760141cc406Sopenharmony_ci 761141cc406Sopenharmony_ci /* unused */ 762141cc406Sopenharmony_ci (void) flags; 763141cc406Sopenharmony_ci (void) userdata; 764141cc406Sopenharmony_ci 765141cc406Sopenharmony_ci if (!b) 766141cc406Sopenharmony_ci return; 767141cc406Sopenharmony_ci 768141cc406Sopenharmony_ci switch (event) 769141cc406Sopenharmony_ci { 770141cc406Sopenharmony_ci case AVAHI_BROWSER_FAILURE: 771141cc406Sopenharmony_ci DBG (1, "net_avahi_browse_callback: %s\n", avahi_strerror (avahi_client_errno (avahi_service_browser_get_client (b)))); 772141cc406Sopenharmony_ci avahi_threaded_poll_quit (avahi_thread); 773141cc406Sopenharmony_ci return; 774141cc406Sopenharmony_ci 775141cc406Sopenharmony_ci case AVAHI_BROWSER_NEW: 776141cc406Sopenharmony_ci DBG (3, "net_avahi_browse_callback: NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); 777141cc406Sopenharmony_ci 778141cc406Sopenharmony_ci /* The server will actually be added to our list in the resolver callback */ 779141cc406Sopenharmony_ci 780141cc406Sopenharmony_ci /* The resolver object will be freed in the resolver callback, or by 781141cc406Sopenharmony_ci * the server if it terminates before the callback is called. 782141cc406Sopenharmony_ci */ 783141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 784141cc406Sopenharmony_ci proto = AVAHI_PROTO_UNSPEC; 785141cc406Sopenharmony_ci#else 786141cc406Sopenharmony_ci proto = AVAHI_PROTO_INET; 787141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 788141cc406Sopenharmony_ci if (!(avahi_service_resolver_new (avahi_client, interface, protocol, name, type, domain, proto, 0, net_avahi_resolve_callback, NULL))) 789141cc406Sopenharmony_ci DBG (2, "net_avahi_browse_callback: failed to resolve service '%s': %s\n", name, avahi_strerror (avahi_client_errno (avahi_client))); 790141cc406Sopenharmony_ci break; 791141cc406Sopenharmony_ci 792141cc406Sopenharmony_ci case AVAHI_BROWSER_REMOVE: 793141cc406Sopenharmony_ci DBG (3, "net_avahi_browse_callback: REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); 794141cc406Sopenharmony_ci /* With the current architecture, we cannot safely remove a server from the list */ 795141cc406Sopenharmony_ci break; 796141cc406Sopenharmony_ci 797141cc406Sopenharmony_ci case AVAHI_BROWSER_ALL_FOR_NOW: 798141cc406Sopenharmony_ci case AVAHI_BROWSER_CACHE_EXHAUSTED: 799141cc406Sopenharmony_ci DBG (3, "net_avahi_browse_callback: %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); 800141cc406Sopenharmony_ci break; 801141cc406Sopenharmony_ci } 802141cc406Sopenharmony_ci} 803141cc406Sopenharmony_ci 804141cc406Sopenharmony_cistatic void 805141cc406Sopenharmony_cinet_avahi_callback (AvahiClient *c, AvahiClientState state, void * userdata) 806141cc406Sopenharmony_ci{ 807141cc406Sopenharmony_ci AvahiProtocol proto; 808141cc406Sopenharmony_ci int error; 809141cc406Sopenharmony_ci 810141cc406Sopenharmony_ci /* unused */ 811141cc406Sopenharmony_ci (void) userdata; 812141cc406Sopenharmony_ci 813141cc406Sopenharmony_ci if (!c) 814141cc406Sopenharmony_ci return; 815141cc406Sopenharmony_ci 816141cc406Sopenharmony_ci switch (state) 817141cc406Sopenharmony_ci { 818141cc406Sopenharmony_ci case AVAHI_CLIENT_CONNECTING: 819141cc406Sopenharmony_ci break; 820141cc406Sopenharmony_ci 821141cc406Sopenharmony_ci case AVAHI_CLIENT_S_COLLISION: 822141cc406Sopenharmony_ci case AVAHI_CLIENT_S_REGISTERING: 823141cc406Sopenharmony_ci case AVAHI_CLIENT_S_RUNNING: 824141cc406Sopenharmony_ci if (avahi_browser) 825141cc406Sopenharmony_ci return; 826141cc406Sopenharmony_ci 827141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 828141cc406Sopenharmony_ci proto = AVAHI_PROTO_UNSPEC; 829141cc406Sopenharmony_ci#else 830141cc406Sopenharmony_ci proto = AVAHI_PROTO_INET; 831141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 832141cc406Sopenharmony_ci 833141cc406Sopenharmony_ci avahi_browser = avahi_service_browser_new (c, AVAHI_IF_UNSPEC, proto, SANED_SERVICE_DNS, NULL, 0, net_avahi_browse_callback, NULL); 834141cc406Sopenharmony_ci if (avahi_browser == NULL) 835141cc406Sopenharmony_ci { 836141cc406Sopenharmony_ci DBG (1, "net_avahi_callback: could not create service browser: %s\n", avahi_strerror (avahi_client_errno (c))); 837141cc406Sopenharmony_ci avahi_threaded_poll_quit (avahi_thread); 838141cc406Sopenharmony_ci } 839141cc406Sopenharmony_ci break; 840141cc406Sopenharmony_ci 841141cc406Sopenharmony_ci case AVAHI_CLIENT_FAILURE: 842141cc406Sopenharmony_ci error = avahi_client_errno (c); 843141cc406Sopenharmony_ci 844141cc406Sopenharmony_ci if (error == AVAHI_ERR_DISCONNECTED) 845141cc406Sopenharmony_ci { 846141cc406Sopenharmony_ci /* Server disappeared - try to reconnect */ 847141cc406Sopenharmony_ci if (avahi_browser) 848141cc406Sopenharmony_ci { 849141cc406Sopenharmony_ci avahi_service_browser_free (avahi_browser); 850141cc406Sopenharmony_ci avahi_browser = NULL; 851141cc406Sopenharmony_ci } 852141cc406Sopenharmony_ci 853141cc406Sopenharmony_ci avahi_client_free (avahi_client); 854141cc406Sopenharmony_ci avahi_client = NULL; 855141cc406Sopenharmony_ci 856141cc406Sopenharmony_ci avahi_client = avahi_client_new (avahi_threaded_poll_get (avahi_thread), AVAHI_CLIENT_NO_FAIL, net_avahi_callback, NULL, &error); 857141cc406Sopenharmony_ci if (avahi_client == NULL) 858141cc406Sopenharmony_ci { 859141cc406Sopenharmony_ci DBG (1, "net_avahi_init: could not create Avahi client: %s\n", avahi_strerror (error)); 860141cc406Sopenharmony_ci avahi_threaded_poll_quit (avahi_thread); 861141cc406Sopenharmony_ci } 862141cc406Sopenharmony_ci } 863141cc406Sopenharmony_ci else 864141cc406Sopenharmony_ci { 865141cc406Sopenharmony_ci /* Another error happened - game over */ 866141cc406Sopenharmony_ci DBG (1, "net_avahi_callback: server connection failure: %s\n", avahi_strerror (error)); 867141cc406Sopenharmony_ci avahi_threaded_poll_quit (avahi_thread); 868141cc406Sopenharmony_ci } 869141cc406Sopenharmony_ci break; 870141cc406Sopenharmony_ci } 871141cc406Sopenharmony_ci} 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci 874141cc406Sopenharmony_cistatic void 875141cc406Sopenharmony_cinet_avahi_init (void) 876141cc406Sopenharmony_ci{ 877141cc406Sopenharmony_ci int error; 878141cc406Sopenharmony_ci 879141cc406Sopenharmony_ci avahi_thread = avahi_threaded_poll_new (); 880141cc406Sopenharmony_ci if (avahi_thread == NULL) 881141cc406Sopenharmony_ci { 882141cc406Sopenharmony_ci DBG (1, "net_avahi_init: could not create threaded poll object\n"); 883141cc406Sopenharmony_ci goto fail; 884141cc406Sopenharmony_ci } 885141cc406Sopenharmony_ci 886141cc406Sopenharmony_ci avahi_client = avahi_client_new (avahi_threaded_poll_get (avahi_thread), AVAHI_CLIENT_NO_FAIL, net_avahi_callback, NULL, &error); 887141cc406Sopenharmony_ci if (avahi_client == NULL) 888141cc406Sopenharmony_ci { 889141cc406Sopenharmony_ci DBG (1, "net_avahi_init: could not create Avahi client: %s\n", avahi_strerror (error)); 890141cc406Sopenharmony_ci goto fail; 891141cc406Sopenharmony_ci } 892141cc406Sopenharmony_ci 893141cc406Sopenharmony_ci if (avahi_threaded_poll_start (avahi_thread) < 0) 894141cc406Sopenharmony_ci { 895141cc406Sopenharmony_ci DBG (1, "net_avahi_init: Avahi thread failed to start\n"); 896141cc406Sopenharmony_ci goto fail; 897141cc406Sopenharmony_ci } 898141cc406Sopenharmony_ci 899141cc406Sopenharmony_ci /* All done */ 900141cc406Sopenharmony_ci return; 901141cc406Sopenharmony_ci 902141cc406Sopenharmony_ci fail: 903141cc406Sopenharmony_ci DBG (1, "net_avahi_init: Avahi init failed, support disabled\n"); 904141cc406Sopenharmony_ci 905141cc406Sopenharmony_ci if (avahi_client) 906141cc406Sopenharmony_ci { 907141cc406Sopenharmony_ci avahi_client_free (avahi_client); 908141cc406Sopenharmony_ci avahi_client = NULL; 909141cc406Sopenharmony_ci } 910141cc406Sopenharmony_ci 911141cc406Sopenharmony_ci if (avahi_thread) 912141cc406Sopenharmony_ci { 913141cc406Sopenharmony_ci avahi_threaded_poll_free (avahi_thread); 914141cc406Sopenharmony_ci avahi_thread = NULL; 915141cc406Sopenharmony_ci } 916141cc406Sopenharmony_ci} 917141cc406Sopenharmony_ci 918141cc406Sopenharmony_cistatic void 919141cc406Sopenharmony_cinet_avahi_cleanup (void) 920141cc406Sopenharmony_ci{ 921141cc406Sopenharmony_ci if (!avahi_thread) 922141cc406Sopenharmony_ci return; 923141cc406Sopenharmony_ci 924141cc406Sopenharmony_ci DBG (1, "net_avahi_cleanup: stopping thread\n"); 925141cc406Sopenharmony_ci 926141cc406Sopenharmony_ci avahi_threaded_poll_stop (avahi_thread); 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci if (avahi_browser) 929141cc406Sopenharmony_ci avahi_service_browser_free (avahi_browser); 930141cc406Sopenharmony_ci 931141cc406Sopenharmony_ci if (avahi_client) 932141cc406Sopenharmony_ci avahi_client_free (avahi_client); 933141cc406Sopenharmony_ci 934141cc406Sopenharmony_ci avahi_threaded_poll_free (avahi_thread); 935141cc406Sopenharmony_ci 936141cc406Sopenharmony_ci DBG (1, "net_avahi_cleanup: done\n"); 937141cc406Sopenharmony_ci} 938141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 939141cc406Sopenharmony_ci 940141cc406Sopenharmony_ci 941141cc406Sopenharmony_ciSANE_Status 942141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 943141cc406Sopenharmony_ci{ 944141cc406Sopenharmony_ci char device_name[PATH_MAX]; 945141cc406Sopenharmony_ci const char *optval; 946141cc406Sopenharmony_ci const char *env; 947141cc406Sopenharmony_ci size_t len; 948141cc406Sopenharmony_ci FILE *fp; 949141cc406Sopenharmony_ci short ns = 0x1234; 950141cc406Sopenharmony_ci unsigned char *p = (unsigned char *)(&ns); 951141cc406Sopenharmony_ci 952141cc406Sopenharmony_ci#ifndef NET_USES_AF_INDEP 953141cc406Sopenharmony_ci struct servent *serv; 954141cc406Sopenharmony_ci#endif /* !NET_USES_AF_INDEP */ 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ci DBG_INIT (); 957141cc406Sopenharmony_ci 958141cc406Sopenharmony_ci DBG (2, "sane_init: authorize %s null, version_code %s null\n", (authorize) ? "!=" : "==", 959141cc406Sopenharmony_ci (version_code) ? "!=" : "=="); 960141cc406Sopenharmony_ci 961141cc406Sopenharmony_ci devlist = NULL; 962141cc406Sopenharmony_ci first_device = NULL; 963141cc406Sopenharmony_ci first_handle = NULL; 964141cc406Sopenharmony_ci 965141cc406Sopenharmony_ci#if WITH_AVAHI 966141cc406Sopenharmony_ci net_avahi_init (); 967141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 968141cc406Sopenharmony_ci 969141cc406Sopenharmony_ci auth_callback = authorize; 970141cc406Sopenharmony_ci 971141cc406Sopenharmony_ci /* Return the version number of the sane-backends package to allow 972141cc406Sopenharmony_ci the frontend to print them. This is done only for net and dll, 973141cc406Sopenharmony_ci because these backends are usually called by the frontend. */ 974141cc406Sopenharmony_ci if (version_code) 975141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_DLL_V_MAJOR, SANE_DLL_V_MINOR, 976141cc406Sopenharmony_ci SANE_DLL_V_BUILD); 977141cc406Sopenharmony_ci 978141cc406Sopenharmony_ci DBG (1, "sane_init: SANE net backend version %s from %s\n", NET_VERSION, 979141cc406Sopenharmony_ci PACKAGE_STRING); 980141cc406Sopenharmony_ci 981141cc406Sopenharmony_ci /* determine (client) machine byte order */ 982141cc406Sopenharmony_ci if (*p == 0x12) 983141cc406Sopenharmony_ci { 984141cc406Sopenharmony_ci client_big_endian = 1; 985141cc406Sopenharmony_ci DBG (3, "sane_init: Client has big endian byte order\n"); 986141cc406Sopenharmony_ci } 987141cc406Sopenharmony_ci else 988141cc406Sopenharmony_ci { 989141cc406Sopenharmony_ci client_big_endian = 0; 990141cc406Sopenharmony_ci DBG (3, "sane_init: Client has little endian byte order\n"); 991141cc406Sopenharmony_ci } 992141cc406Sopenharmony_ci 993141cc406Sopenharmony_ci#ifndef NET_USES_AF_INDEP 994141cc406Sopenharmony_ci DBG (2, "sane_init: determining sane service port\n"); 995141cc406Sopenharmony_ci serv = getservbyname ("sane-port", "tcp"); 996141cc406Sopenharmony_ci 997141cc406Sopenharmony_ci if (serv) 998141cc406Sopenharmony_ci { 999141cc406Sopenharmony_ci DBG (2, "sane_init: found port %d\n", ntohs (serv->s_port)); 1000141cc406Sopenharmony_ci saned_port = serv->s_port; 1001141cc406Sopenharmony_ci } 1002141cc406Sopenharmony_ci else 1003141cc406Sopenharmony_ci { 1004141cc406Sopenharmony_ci saned_port = htons (6566); 1005141cc406Sopenharmony_ci DBG (1, "sane_init: could not find `sane-port' service (%s); using default " 1006141cc406Sopenharmony_ci "port %d\n", strerror (errno), ntohs (saned_port)); 1007141cc406Sopenharmony_ci } 1008141cc406Sopenharmony_ci#endif /* !NET_USES_AF_INDEP */ 1009141cc406Sopenharmony_ci 1010141cc406Sopenharmony_ci DBG (2, "sane_init: searching for config file\n"); 1011141cc406Sopenharmony_ci fp = sanei_config_open (NET_CONFIG_FILE); 1012141cc406Sopenharmony_ci if (fp) 1013141cc406Sopenharmony_ci { 1014141cc406Sopenharmony_ci while (sanei_config_read (device_name, sizeof (device_name), fp)) 1015141cc406Sopenharmony_ci { 1016141cc406Sopenharmony_ci if (device_name[0] == '#') /* ignore line comments */ 1017141cc406Sopenharmony_ci continue; 1018141cc406Sopenharmony_ci len = strlen (device_name); 1019141cc406Sopenharmony_ci 1020141cc406Sopenharmony_ci if (!len) 1021141cc406Sopenharmony_ci continue; /* ignore empty lines */ 1022141cc406Sopenharmony_ci 1023141cc406Sopenharmony_ci /* 1024141cc406Sopenharmony_ci * Check for net backend options. 1025141cc406Sopenharmony_ci * Anything that isn't an option is a saned host. 1026141cc406Sopenharmony_ci */ 1027141cc406Sopenharmony_ci if (strstr(device_name, "connect_timeout") != NULL) 1028141cc406Sopenharmony_ci { 1029141cc406Sopenharmony_ci /* Look for the = sign; if it's not there, error out */ 1030141cc406Sopenharmony_ci optval = strchr(device_name, '='); 1031141cc406Sopenharmony_ci 1032141cc406Sopenharmony_ci if (!optval) 1033141cc406Sopenharmony_ci continue; 1034141cc406Sopenharmony_ci 1035141cc406Sopenharmony_ci optval = sanei_config_skip_whitespace (++optval); 1036141cc406Sopenharmony_ci if ((optval != NULL) && (*optval != '\0')) 1037141cc406Sopenharmony_ci { 1038141cc406Sopenharmony_ci connect_timeout = atoi(optval); 1039141cc406Sopenharmony_ci 1040141cc406Sopenharmony_ci DBG (2, "sane_init: connect timeout set to %d seconds\n", connect_timeout); 1041141cc406Sopenharmony_ci } 1042141cc406Sopenharmony_ci 1043141cc406Sopenharmony_ci continue; 1044141cc406Sopenharmony_ci } 1045141cc406Sopenharmony_ci#if WITH_AVAHI 1046141cc406Sopenharmony_ci avahi_threaded_poll_lock (avahi_thread); 1047141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 1048141cc406Sopenharmony_ci DBG (2, "sane_init: trying to add %s\n", device_name); 1049141cc406Sopenharmony_ci add_device (device_name, 0); 1050141cc406Sopenharmony_ci#if WITH_AVAHI 1051141cc406Sopenharmony_ci avahi_threaded_poll_unlock (avahi_thread); 1052141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 1053141cc406Sopenharmony_ci } 1054141cc406Sopenharmony_ci 1055141cc406Sopenharmony_ci fclose (fp); 1056141cc406Sopenharmony_ci DBG (2, "sane_init: done reading config\n"); 1057141cc406Sopenharmony_ci } 1058141cc406Sopenharmony_ci else 1059141cc406Sopenharmony_ci DBG (1, "sane_init: could not open config file (%s): %s\n", 1060141cc406Sopenharmony_ci NET_CONFIG_FILE, strerror (errno)); 1061141cc406Sopenharmony_ci 1062141cc406Sopenharmony_ci DBG (2, "sane_init: evaluating environment variable SANE_NET_HOSTS\n"); 1063141cc406Sopenharmony_ci env = getenv ("SANE_NET_HOSTS"); 1064141cc406Sopenharmony_ci if (env) 1065141cc406Sopenharmony_ci { 1066141cc406Sopenharmony_ci char *copy, *next, *host; 1067141cc406Sopenharmony_ci if ((copy = strdup (env)) != NULL) 1068141cc406Sopenharmony_ci { 1069141cc406Sopenharmony_ci next = copy; 1070141cc406Sopenharmony_ci while ((host = strsep (&next, ":"))) 1071141cc406Sopenharmony_ci { 1072141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1073141cc406Sopenharmony_ci if (host[0] == '[') 1074141cc406Sopenharmony_ci { 1075141cc406Sopenharmony_ci /* skip '[' (host[0]) */ 1076141cc406Sopenharmony_ci host++; 1077141cc406Sopenharmony_ci /* get the rest of the IPv6 addr (we're screwed if ] is missing) 1078141cc406Sopenharmony_ci * Is it worth checking for the matching ] ? Not for now. */ 1079141cc406Sopenharmony_ci strsep (&next, "]"); 1080141cc406Sopenharmony_ci /* add back the ":" that got removed by the strsep() */ 1081141cc406Sopenharmony_ci host[strlen (host)] = ':'; 1082141cc406Sopenharmony_ci /* host now holds the IPv6 address */ 1083141cc406Sopenharmony_ci 1084141cc406Sopenharmony_ci /* skip the ':' that could be after ] (avoids a call to strsep() */ 1085141cc406Sopenharmony_ci if (next[0] == ':') 1086141cc406Sopenharmony_ci next++; 1087141cc406Sopenharmony_ci } 1088141cc406Sopenharmony_ci 1089141cc406Sopenharmony_ci /* 1090141cc406Sopenharmony_ci * if the IPv6 is last in the list, the strsep() call in the while() 1091141cc406Sopenharmony_ci * will return a string with the first char being '\0'. Skip it. 1092141cc406Sopenharmony_ci */ 1093141cc406Sopenharmony_ci if (host[0] == '\0') 1094141cc406Sopenharmony_ci continue; 1095141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1096141cc406Sopenharmony_ci#if WITH_AVAHI 1097141cc406Sopenharmony_ci avahi_threaded_poll_lock (avahi_thread); 1098141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 1099141cc406Sopenharmony_ci DBG (2, "sane_init: trying to add %s\n", host); 1100141cc406Sopenharmony_ci add_device (host, 0); 1101141cc406Sopenharmony_ci#if WITH_AVAHI 1102141cc406Sopenharmony_ci avahi_threaded_poll_unlock (avahi_thread); 1103141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 1104141cc406Sopenharmony_ci } 1105141cc406Sopenharmony_ci free (copy); 1106141cc406Sopenharmony_ci } 1107141cc406Sopenharmony_ci else 1108141cc406Sopenharmony_ci DBG (1, "sane_init: not enough memory to duplicate " 1109141cc406Sopenharmony_ci "environment variable\n"); 1110141cc406Sopenharmony_ci } 1111141cc406Sopenharmony_ci 1112141cc406Sopenharmony_ci DBG (2, "sane_init: evaluating environment variable SANE_NET_TIMEOUT\n"); 1113141cc406Sopenharmony_ci env = getenv ("SANE_NET_TIMEOUT"); 1114141cc406Sopenharmony_ci if (env) 1115141cc406Sopenharmony_ci { 1116141cc406Sopenharmony_ci connect_timeout = atoi(env); 1117141cc406Sopenharmony_ci DBG (2, "sane_init: connect timeout set to %d seconds from env\n", connect_timeout); 1118141cc406Sopenharmony_ci } 1119141cc406Sopenharmony_ci 1120141cc406Sopenharmony_ci DBG (2, "sane_init: done\n"); 1121141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1122141cc406Sopenharmony_ci} 1123141cc406Sopenharmony_ci 1124141cc406Sopenharmony_civoid 1125141cc406Sopenharmony_cisane_exit (void) 1126141cc406Sopenharmony_ci{ 1127141cc406Sopenharmony_ci Net_Scanner *handle, *next_handle; 1128141cc406Sopenharmony_ci Net_Device *dev, *next_device; 1129141cc406Sopenharmony_ci int i; 1130141cc406Sopenharmony_ci 1131141cc406Sopenharmony_ci DBG (1, "sane_exit: exiting\n"); 1132141cc406Sopenharmony_ci 1133141cc406Sopenharmony_ci#if WITH_AVAHI 1134141cc406Sopenharmony_ci net_avahi_cleanup (); 1135141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 1136141cc406Sopenharmony_ci 1137141cc406Sopenharmony_ci /* first, close all handles: */ 1138141cc406Sopenharmony_ci for (handle = first_handle; handle; handle = next_handle) 1139141cc406Sopenharmony_ci { 1140141cc406Sopenharmony_ci next_handle = handle->next; 1141141cc406Sopenharmony_ci sane_close (handle); 1142141cc406Sopenharmony_ci } 1143141cc406Sopenharmony_ci first_handle = 0; 1144141cc406Sopenharmony_ci 1145141cc406Sopenharmony_ci /* now close all devices: */ 1146141cc406Sopenharmony_ci for (dev = first_device; dev; dev = next_device) 1147141cc406Sopenharmony_ci { 1148141cc406Sopenharmony_ci next_device = dev->next; 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci DBG (2, "sane_exit: closing dev %p, ctl=%d\n", (void *) dev, dev->ctl); 1151141cc406Sopenharmony_ci 1152141cc406Sopenharmony_ci if (dev->ctl >= 0) 1153141cc406Sopenharmony_ci { 1154141cc406Sopenharmony_ci sanei_w_call (&dev->wire, SANE_NET_EXIT, 1155141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_void, 0, 1156141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_void, 0); 1157141cc406Sopenharmony_ci sanei_w_exit (&dev->wire); 1158141cc406Sopenharmony_ci close (dev->ctl); 1159141cc406Sopenharmony_ci } 1160141cc406Sopenharmony_ci if (dev->name) 1161141cc406Sopenharmony_ci free ((void *) dev->name); 1162141cc406Sopenharmony_ci 1163141cc406Sopenharmony_ci#ifdef NET_USES_AF_INDEP 1164141cc406Sopenharmony_ci if (dev->addr) 1165141cc406Sopenharmony_ci freeaddrinfo(dev->addr); 1166141cc406Sopenharmony_ci#endif /* NET_USES_AF_INDEP */ 1167141cc406Sopenharmony_ci 1168141cc406Sopenharmony_ci free (dev); 1169141cc406Sopenharmony_ci } 1170141cc406Sopenharmony_ci if (devlist) 1171141cc406Sopenharmony_ci { 1172141cc406Sopenharmony_ci for (i = 0; devlist[i]; ++i) 1173141cc406Sopenharmony_ci { 1174141cc406Sopenharmony_ci if (devlist[i]->vendor) 1175141cc406Sopenharmony_ci free ((void *) devlist[i]->vendor); 1176141cc406Sopenharmony_ci if (devlist[i]->model) 1177141cc406Sopenharmony_ci free ((void *) devlist[i]->model); 1178141cc406Sopenharmony_ci if (devlist[i]->type) 1179141cc406Sopenharmony_ci free ((void *) devlist[i]->type); 1180141cc406Sopenharmony_ci free ((void *) devlist[i]); 1181141cc406Sopenharmony_ci } 1182141cc406Sopenharmony_ci free (devlist); 1183141cc406Sopenharmony_ci } 1184141cc406Sopenharmony_ci DBG (3, "sane_exit: finished.\n"); 1185141cc406Sopenharmony_ci} 1186141cc406Sopenharmony_ci 1187141cc406Sopenharmony_ci/* Note that a call to get_devices() implies that we'll have to 1188141cc406Sopenharmony_ci connect to all remote hosts. To avoid this, you can call 1189141cc406Sopenharmony_ci sane_open() directly (assuming you know the name of the 1190141cc406Sopenharmony_ci backend/device). This is appropriate for the command-line 1191141cc406Sopenharmony_ci interface of SANE, for example. 1192141cc406Sopenharmony_ci */ 1193141cc406Sopenharmony_ciSANE_Status 1194141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 1195141cc406Sopenharmony_ci{ 1196141cc406Sopenharmony_ci static int devlist_size = 0, devlist_len = 0; 1197141cc406Sopenharmony_ci static const SANE_Device *empty_devlist[1] = { 0 }; 1198141cc406Sopenharmony_ci SANE_Get_Devices_Reply reply; 1199141cc406Sopenharmony_ci SANE_Status status; 1200141cc406Sopenharmony_ci Net_Device *dev; 1201141cc406Sopenharmony_ci char *full_name; 1202141cc406Sopenharmony_ci int i, num_devs; 1203141cc406Sopenharmony_ci size_t len; 1204141cc406Sopenharmony_ci#define ASSERT_SPACE(n) do \ 1205141cc406Sopenharmony_ci { \ 1206141cc406Sopenharmony_ci if (devlist_len + (n) > devlist_size) \ 1207141cc406Sopenharmony_ci { \ 1208141cc406Sopenharmony_ci devlist_size += (n) + 15; \ 1209141cc406Sopenharmony_ci if (devlist) \ 1210141cc406Sopenharmony_ci devlist = realloc (devlist, devlist_size * sizeof (devlist[0])); \ 1211141cc406Sopenharmony_ci else \ 1212141cc406Sopenharmony_ci devlist = malloc (devlist_size * sizeof (devlist[0])); \ 1213141cc406Sopenharmony_ci if (!devlist) \ 1214141cc406Sopenharmony_ci { \ 1215141cc406Sopenharmony_ci DBG (1, "sane_get_devices: not enough memory\n"); \ 1216141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; \ 1217141cc406Sopenharmony_ci } \ 1218141cc406Sopenharmony_ci } \ 1219141cc406Sopenharmony_ci } while (0) 1220141cc406Sopenharmony_ci 1221141cc406Sopenharmony_ci DBG (3, "sane_get_devices: local_only = %d\n", local_only); 1222141cc406Sopenharmony_ci 1223141cc406Sopenharmony_ci if (local_only) 1224141cc406Sopenharmony_ci { 1225141cc406Sopenharmony_ci *device_list = empty_devlist; 1226141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1227141cc406Sopenharmony_ci } 1228141cc406Sopenharmony_ci 1229141cc406Sopenharmony_ci if (devlist) 1230141cc406Sopenharmony_ci { 1231141cc406Sopenharmony_ci DBG (2, "sane_get_devices: freeing devlist\n"); 1232141cc406Sopenharmony_ci for (i = 0; devlist[i]; ++i) 1233141cc406Sopenharmony_ci { 1234141cc406Sopenharmony_ci if (devlist[i]->vendor) 1235141cc406Sopenharmony_ci free ((void *) devlist[i]->vendor); 1236141cc406Sopenharmony_ci if (devlist[i]->model) 1237141cc406Sopenharmony_ci free ((void *) devlist[i]->model); 1238141cc406Sopenharmony_ci if (devlist[i]->type) 1239141cc406Sopenharmony_ci free ((void *) devlist[i]->type); 1240141cc406Sopenharmony_ci free ((void *) devlist[i]); 1241141cc406Sopenharmony_ci } 1242141cc406Sopenharmony_ci free (devlist); 1243141cc406Sopenharmony_ci devlist = 0; 1244141cc406Sopenharmony_ci } 1245141cc406Sopenharmony_ci devlist_len = 0; 1246141cc406Sopenharmony_ci devlist_size = 0; 1247141cc406Sopenharmony_ci 1248141cc406Sopenharmony_ci for (dev = first_device; dev; dev = dev->next) 1249141cc406Sopenharmony_ci { 1250141cc406Sopenharmony_ci if (dev->ctl < 0) 1251141cc406Sopenharmony_ci { 1252141cc406Sopenharmony_ci status = connect_dev (dev); 1253141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1254141cc406Sopenharmony_ci { 1255141cc406Sopenharmony_ci DBG (1, "sane_get_devices: ignoring failure to connect to %s\n", 1256141cc406Sopenharmony_ci dev->name); 1257141cc406Sopenharmony_ci continue; 1258141cc406Sopenharmony_ci } 1259141cc406Sopenharmony_ci } 1260141cc406Sopenharmony_ci sanei_w_call (&dev->wire, SANE_NET_GET_DEVICES, 1261141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_void, 0, 1262141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_get_devices_reply, &reply); 1263141cc406Sopenharmony_ci if (reply.status != SANE_STATUS_GOOD) 1264141cc406Sopenharmony_ci { 1265141cc406Sopenharmony_ci DBG (1, "sane_get_devices: ignoring rpc-returned status %s\n", 1266141cc406Sopenharmony_ci sane_strstatus (reply.status)); 1267141cc406Sopenharmony_ci sanei_w_free (&dev->wire, 1268141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_get_devices_reply, &reply); 1269141cc406Sopenharmony_ci continue; 1270141cc406Sopenharmony_ci } 1271141cc406Sopenharmony_ci 1272141cc406Sopenharmony_ci /* count the number of devices for this backend: */ 1273141cc406Sopenharmony_ci for (num_devs = 0; reply.device_list[num_devs]; ++num_devs); 1274141cc406Sopenharmony_ci 1275141cc406Sopenharmony_ci ASSERT_SPACE (num_devs); 1276141cc406Sopenharmony_ci 1277141cc406Sopenharmony_ci for (i = 0; i < num_devs; ++i) 1278141cc406Sopenharmony_ci { 1279141cc406Sopenharmony_ci SANE_Device *rdev; 1280141cc406Sopenharmony_ci char *mem; 1281141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1282141cc406Sopenharmony_ci SANE_Bool IPv6 = SANE_FALSE; 1283141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1284141cc406Sopenharmony_ci 1285141cc406Sopenharmony_ci /* create a new device entry with a device name that is the 1286141cc406Sopenharmony_ci sum of the backend name a colon and the backend's device 1287141cc406Sopenharmony_ci name: */ 1288141cc406Sopenharmony_ci len = strlen (dev->name) + 1 + strlen (reply.device_list[i]->name); 1289141cc406Sopenharmony_ci 1290141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1291141cc406Sopenharmony_ci if (strchr (dev->name, ':') != NULL) 1292141cc406Sopenharmony_ci { 1293141cc406Sopenharmony_ci len += 2; 1294141cc406Sopenharmony_ci IPv6 = SANE_TRUE; 1295141cc406Sopenharmony_ci } 1296141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1297141cc406Sopenharmony_ci 1298141cc406Sopenharmony_ci mem = malloc (sizeof (*dev) + len + 1); 1299141cc406Sopenharmony_ci if (!mem) 1300141cc406Sopenharmony_ci { 1301141cc406Sopenharmony_ci DBG (1, "sane_get_devices: not enough free memory\n"); 1302141cc406Sopenharmony_ci sanei_w_free (&dev->wire, 1303141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_get_devices_reply, 1304141cc406Sopenharmony_ci &reply); 1305141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1306141cc406Sopenharmony_ci } 1307141cc406Sopenharmony_ci 1308141cc406Sopenharmony_ci memset (mem, 0, sizeof (*dev) + len); 1309141cc406Sopenharmony_ci full_name = mem + sizeof (*dev); 1310141cc406Sopenharmony_ci 1311141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1312141cc406Sopenharmony_ci if (IPv6 == SANE_TRUE) 1313141cc406Sopenharmony_ci strcat (full_name, "["); 1314141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1315141cc406Sopenharmony_ci 1316141cc406Sopenharmony_ci strcat (full_name, dev->name); 1317141cc406Sopenharmony_ci 1318141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1319141cc406Sopenharmony_ci if (IPv6 == SANE_TRUE) 1320141cc406Sopenharmony_ci strcat (full_name, "]"); 1321141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1322141cc406Sopenharmony_ci 1323141cc406Sopenharmony_ci strcat (full_name, ":"); 1324141cc406Sopenharmony_ci strcat (full_name, reply.device_list[i]->name); 1325141cc406Sopenharmony_ci DBG (3, "sane_get_devices: got %s\n", full_name); 1326141cc406Sopenharmony_ci 1327141cc406Sopenharmony_ci rdev = (SANE_Device *) mem; 1328141cc406Sopenharmony_ci rdev->name = full_name; 1329141cc406Sopenharmony_ci rdev->vendor = strdup (reply.device_list[i]->vendor); 1330141cc406Sopenharmony_ci rdev->model = strdup (reply.device_list[i]->model); 1331141cc406Sopenharmony_ci rdev->type = strdup (reply.device_list[i]->type); 1332141cc406Sopenharmony_ci 1333141cc406Sopenharmony_ci if ((!rdev->vendor) || (!rdev->model) || (!rdev->type)) 1334141cc406Sopenharmony_ci { 1335141cc406Sopenharmony_ci DBG (1, "sane_get_devices: not enough free memory\n"); 1336141cc406Sopenharmony_ci if (rdev->vendor) 1337141cc406Sopenharmony_ci free ((void *) rdev->vendor); 1338141cc406Sopenharmony_ci if (rdev->model) 1339141cc406Sopenharmony_ci free ((void *) rdev->model); 1340141cc406Sopenharmony_ci if (rdev->type) 1341141cc406Sopenharmony_ci free ((void *) rdev->type); 1342141cc406Sopenharmony_ci free (rdev); 1343141cc406Sopenharmony_ci sanei_w_free (&dev->wire, 1344141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_get_devices_reply, 1345141cc406Sopenharmony_ci &reply); 1346141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1347141cc406Sopenharmony_ci } 1348141cc406Sopenharmony_ci 1349141cc406Sopenharmony_ci devlist[devlist_len++] = rdev; 1350141cc406Sopenharmony_ci } 1351141cc406Sopenharmony_ci /* now free up the rpc return value: */ 1352141cc406Sopenharmony_ci sanei_w_free (&dev->wire, 1353141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_get_devices_reply, &reply); 1354141cc406Sopenharmony_ci } 1355141cc406Sopenharmony_ci 1356141cc406Sopenharmony_ci /* terminate device list with NULL entry: */ 1357141cc406Sopenharmony_ci ASSERT_SPACE (1); 1358141cc406Sopenharmony_ci devlist[devlist_len++] = 0; 1359141cc406Sopenharmony_ci 1360141cc406Sopenharmony_ci *device_list = devlist; 1361141cc406Sopenharmony_ci DBG (2, "sane_get_devices: finished (%d devices)\n", devlist_len - 1); 1362141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1363141cc406Sopenharmony_ci} 1364141cc406Sopenharmony_ci 1365141cc406Sopenharmony_ciSANE_Status 1366141cc406Sopenharmony_cisane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) 1367141cc406Sopenharmony_ci{ 1368141cc406Sopenharmony_ci SANE_Open_Reply reply; 1369141cc406Sopenharmony_ci const char *dev_name; 1370141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1371141cc406Sopenharmony_ci const char *tmp_name; 1372141cc406Sopenharmony_ci SANE_Bool v6addr = SANE_FALSE; 1373141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1374141cc406Sopenharmony_ci SANE_String nd_name; 1375141cc406Sopenharmony_ci SANE_Status status; 1376141cc406Sopenharmony_ci SANE_Word handle; 1377141cc406Sopenharmony_ci SANE_Word ack; 1378141cc406Sopenharmony_ci Net_Device *dev; 1379141cc406Sopenharmony_ci Net_Scanner *s; 1380141cc406Sopenharmony_ci int need_auth; 1381141cc406Sopenharmony_ci 1382141cc406Sopenharmony_ci DBG (3, "sane_open(\"%s\")\n", full_name); 1383141cc406Sopenharmony_ci 1384141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1385141cc406Sopenharmony_ci /* 1386141cc406Sopenharmony_ci * Check whether a numerical IPv6 host was specified 1387141cc406Sopenharmony_ci * [2001:42:42::12] <== check for '[' as full_name[0] 1388141cc406Sopenharmony_ci * ex: [2001:42:42::12]:test:0 (syntax taken from Apache 2) 1389141cc406Sopenharmony_ci */ 1390141cc406Sopenharmony_ci if (full_name[0] == '[') 1391141cc406Sopenharmony_ci { 1392141cc406Sopenharmony_ci v6addr = SANE_TRUE; 1393141cc406Sopenharmony_ci tmp_name = strchr (full_name, ']'); 1394141cc406Sopenharmony_ci if (!tmp_name) 1395141cc406Sopenharmony_ci { 1396141cc406Sopenharmony_ci DBG (1, "sane_open: incorrect host address: missing matching ']'\n"); 1397141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1398141cc406Sopenharmony_ci } 1399141cc406Sopenharmony_ci } 1400141cc406Sopenharmony_ci else 1401141cc406Sopenharmony_ci tmp_name = full_name; 1402141cc406Sopenharmony_ci 1403141cc406Sopenharmony_ci dev_name = strchr (tmp_name, ':'); 1404141cc406Sopenharmony_ci#else /* !ENABLE_IPV6 */ 1405141cc406Sopenharmony_ci 1406141cc406Sopenharmony_ci dev_name = strchr (full_name, ':'); 1407141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1408141cc406Sopenharmony_ci 1409141cc406Sopenharmony_ci if (dev_name) 1410141cc406Sopenharmony_ci { 1411141cc406Sopenharmony_ci#ifdef strndupa 1412141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 1413141cc406Sopenharmony_ci if (v6addr == SANE_TRUE) 1414141cc406Sopenharmony_ci nd_name = strndupa (full_name + 1, dev_name - full_name - 2); 1415141cc406Sopenharmony_ci else 1416141cc406Sopenharmony_ci nd_name = strndupa (full_name, dev_name - full_name); 1417141cc406Sopenharmony_ci 1418141cc406Sopenharmony_ci# else /* !ENABLE_IPV6 */ 1419141cc406Sopenharmony_ci 1420141cc406Sopenharmony_ci nd_name = strndupa (full_name, dev_name - full_name); 1421141cc406Sopenharmony_ci# endif /* ENABLE_IPV6 */ 1422141cc406Sopenharmony_ci 1423141cc406Sopenharmony_ci if (!nd_name) 1424141cc406Sopenharmony_ci { 1425141cc406Sopenharmony_ci DBG (1, "sane_open: not enough free memory\n"); 1426141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1427141cc406Sopenharmony_ci } 1428141cc406Sopenharmony_ci#else 1429141cc406Sopenharmony_ci char *tmp; 1430141cc406Sopenharmony_ci 1431141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 1432141cc406Sopenharmony_ci if (v6addr == SANE_TRUE) 1433141cc406Sopenharmony_ci tmp = alloca (dev_name - full_name - 2 + 1); 1434141cc406Sopenharmony_ci else 1435141cc406Sopenharmony_ci tmp = alloca (dev_name - full_name + 1); 1436141cc406Sopenharmony_ci 1437141cc406Sopenharmony_ci# else /* !ENABLE_IPV6 */ 1438141cc406Sopenharmony_ci 1439141cc406Sopenharmony_ci tmp = alloca (dev_name - full_name + 1); 1440141cc406Sopenharmony_ci# endif /* ENABLE_IPV6 */ 1441141cc406Sopenharmony_ci 1442141cc406Sopenharmony_ci if (!tmp) 1443141cc406Sopenharmony_ci { 1444141cc406Sopenharmony_ci DBG (1, "sane_open: not enough free memory\n"); 1445141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1446141cc406Sopenharmony_ci } 1447141cc406Sopenharmony_ci 1448141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 1449141cc406Sopenharmony_ci if (v6addr == SANE_TRUE) 1450141cc406Sopenharmony_ci { 1451141cc406Sopenharmony_ci memcpy (tmp, full_name + 1, dev_name - full_name - 2); 1452141cc406Sopenharmony_ci tmp[dev_name - full_name - 2] = '\0'; 1453141cc406Sopenharmony_ci } 1454141cc406Sopenharmony_ci else 1455141cc406Sopenharmony_ci { 1456141cc406Sopenharmony_ci memcpy (tmp, full_name, dev_name - full_name); 1457141cc406Sopenharmony_ci tmp[dev_name - full_name] = '\0'; 1458141cc406Sopenharmony_ci } 1459141cc406Sopenharmony_ci 1460141cc406Sopenharmony_ci# else /* !ENABLE_IPV6 */ 1461141cc406Sopenharmony_ci 1462141cc406Sopenharmony_ci memcpy (tmp, full_name, dev_name - full_name); 1463141cc406Sopenharmony_ci tmp[dev_name - full_name] = '\0'; 1464141cc406Sopenharmony_ci# endif /* ENABLE_IPV6 */ 1465141cc406Sopenharmony_ci 1466141cc406Sopenharmony_ci nd_name = tmp; 1467141cc406Sopenharmony_ci#endif 1468141cc406Sopenharmony_ci ++dev_name; /* skip colon */ 1469141cc406Sopenharmony_ci } 1470141cc406Sopenharmony_ci else 1471141cc406Sopenharmony_ci { 1472141cc406Sopenharmony_ci /* if no colon interpret full_name as the host name; an empty 1473141cc406Sopenharmony_ci device name will cause us to open the first device of that 1474141cc406Sopenharmony_ci host. */ 1475141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1476141cc406Sopenharmony_ci if (v6addr == SANE_TRUE) 1477141cc406Sopenharmony_ci { 1478141cc406Sopenharmony_ci nd_name = alloca (strlen (full_name) - 2 + 1); 1479141cc406Sopenharmony_ci if (!nd_name) 1480141cc406Sopenharmony_ci { 1481141cc406Sopenharmony_ci DBG (1, "sane_open: not enough free memory\n"); 1482141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1483141cc406Sopenharmony_ci } 1484141cc406Sopenharmony_ci memcpy (nd_name, full_name + 1, strlen (full_name) - 2); 1485141cc406Sopenharmony_ci nd_name[strlen (full_name) - 2] = '\0'; 1486141cc406Sopenharmony_ci } 1487141cc406Sopenharmony_ci else 1488141cc406Sopenharmony_ci nd_name = (char *) full_name; 1489141cc406Sopenharmony_ci 1490141cc406Sopenharmony_ci#else /* !ENABLE_IPV6 */ 1491141cc406Sopenharmony_ci 1492141cc406Sopenharmony_ci nd_name = (char *) full_name; 1493141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1494141cc406Sopenharmony_ci 1495141cc406Sopenharmony_ci dev_name = ""; 1496141cc406Sopenharmony_ci } 1497141cc406Sopenharmony_ci DBG (2, "sane_open: host = %s, device = %s\n", nd_name, dev_name); 1498141cc406Sopenharmony_ci 1499141cc406Sopenharmony_ci if (!nd_name[0]) 1500141cc406Sopenharmony_ci { 1501141cc406Sopenharmony_ci /* Unlike other backends, we never allow an empty backend-name. 1502141cc406Sopenharmony_ci Otherwise, it's possible that sane_open("") will result in 1503141cc406Sopenharmony_ci endless looping (consider the case where NET is the first 1504141cc406Sopenharmony_ci backend...) */ 1505141cc406Sopenharmony_ci 1506141cc406Sopenharmony_ci DBG (1, "sane_open: empty backend name is not allowed\n"); 1507141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1508141cc406Sopenharmony_ci } 1509141cc406Sopenharmony_ci else 1510141cc406Sopenharmony_ci for (dev = first_device; dev; dev = dev->next) 1511141cc406Sopenharmony_ci if (strcmp (dev->name, nd_name) == 0) 1512141cc406Sopenharmony_ci break; 1513141cc406Sopenharmony_ci 1514141cc406Sopenharmony_ci if (!dev) 1515141cc406Sopenharmony_ci { 1516141cc406Sopenharmony_ci DBG (1, 1517141cc406Sopenharmony_ci "sane_open: device %s not found, trying to register it anyway\n", 1518141cc406Sopenharmony_ci nd_name); 1519141cc406Sopenharmony_ci#if WITH_AVAHI 1520141cc406Sopenharmony_ci avahi_threaded_poll_lock (avahi_thread); 1521141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 1522141cc406Sopenharmony_ci status = add_device (nd_name, &dev); 1523141cc406Sopenharmony_ci#if WITH_AVAHI 1524141cc406Sopenharmony_ci avahi_threaded_poll_unlock (avahi_thread); 1525141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 1526141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1527141cc406Sopenharmony_ci { 1528141cc406Sopenharmony_ci DBG (1, "sane_open: could not open device\n"); 1529141cc406Sopenharmony_ci return status; 1530141cc406Sopenharmony_ci } 1531141cc406Sopenharmony_ci } 1532141cc406Sopenharmony_ci else 1533141cc406Sopenharmony_ci DBG (2, "sane_open: device found in list\n"); 1534141cc406Sopenharmony_ci 1535141cc406Sopenharmony_ci if (dev->ctl < 0) 1536141cc406Sopenharmony_ci { 1537141cc406Sopenharmony_ci DBG (2, "sane_open: device not connected yet...\n"); 1538141cc406Sopenharmony_ci status = connect_dev (dev); 1539141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1540141cc406Sopenharmony_ci { 1541141cc406Sopenharmony_ci DBG (1, "sane_open: could not connect to device\n"); 1542141cc406Sopenharmony_ci return status; 1543141cc406Sopenharmony_ci } 1544141cc406Sopenharmony_ci } 1545141cc406Sopenharmony_ci 1546141cc406Sopenharmony_ci DBG (3, "sane_open: net_open\n"); 1547141cc406Sopenharmony_ci sanei_w_call (&dev->wire, SANE_NET_OPEN, 1548141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_string, &dev_name, 1549141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_open_reply, &reply); 1550141cc406Sopenharmony_ci do 1551141cc406Sopenharmony_ci { 1552141cc406Sopenharmony_ci if (dev->wire.status != 0) 1553141cc406Sopenharmony_ci { 1554141cc406Sopenharmony_ci DBG (1, "sane_open: open rpc call failed (%s)\n", 1555141cc406Sopenharmony_ci strerror (dev->wire.status)); 1556141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1557141cc406Sopenharmony_ci } 1558141cc406Sopenharmony_ci 1559141cc406Sopenharmony_ci status = reply.status; 1560141cc406Sopenharmony_ci handle = reply.handle; 1561141cc406Sopenharmony_ci need_auth = (reply.resource_to_authorize != 0); 1562141cc406Sopenharmony_ci 1563141cc406Sopenharmony_ci if (need_auth) 1564141cc406Sopenharmony_ci { 1565141cc406Sopenharmony_ci DBG (3, "sane_open: authorization required\n"); 1566141cc406Sopenharmony_ci do_authorization (dev, reply.resource_to_authorize); 1567141cc406Sopenharmony_ci 1568141cc406Sopenharmony_ci sanei_w_free (&dev->wire, (WireCodecFunc) sanei_w_open_reply, 1569141cc406Sopenharmony_ci &reply); 1570141cc406Sopenharmony_ci 1571141cc406Sopenharmony_ci if (dev->wire.direction != WIRE_DECODE) 1572141cc406Sopenharmony_ci sanei_w_set_dir (&dev->wire, WIRE_DECODE); 1573141cc406Sopenharmony_ci sanei_w_open_reply (&dev->wire, &reply); 1574141cc406Sopenharmony_ci 1575141cc406Sopenharmony_ci continue; 1576141cc406Sopenharmony_ci } 1577141cc406Sopenharmony_ci else 1578141cc406Sopenharmony_ci sanei_w_free (&dev->wire, (WireCodecFunc) sanei_w_open_reply, &reply); 1579141cc406Sopenharmony_ci 1580141cc406Sopenharmony_ci if (need_auth && !dev->auth_active) 1581141cc406Sopenharmony_ci { 1582141cc406Sopenharmony_ci DBG (2, "sane_open: open cancelled\n"); 1583141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1584141cc406Sopenharmony_ci } 1585141cc406Sopenharmony_ci 1586141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1587141cc406Sopenharmony_ci { 1588141cc406Sopenharmony_ci DBG (1, "sane_open: remote open failed\n"); 1589141cc406Sopenharmony_ci return reply.status; 1590141cc406Sopenharmony_ci } 1591141cc406Sopenharmony_ci } 1592141cc406Sopenharmony_ci while (need_auth); 1593141cc406Sopenharmony_ci 1594141cc406Sopenharmony_ci s = malloc (sizeof (*s)); 1595141cc406Sopenharmony_ci if (!s) 1596141cc406Sopenharmony_ci { 1597141cc406Sopenharmony_ci DBG (1, "sane_open: not enough free memory\n"); 1598141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1599141cc406Sopenharmony_ci } 1600141cc406Sopenharmony_ci 1601141cc406Sopenharmony_ci memset (s, 0, sizeof (*s)); 1602141cc406Sopenharmony_ci s->hw = dev; 1603141cc406Sopenharmony_ci s->handle = handle; 1604141cc406Sopenharmony_ci s->data = -1; 1605141cc406Sopenharmony_ci s->next = first_handle; 1606141cc406Sopenharmony_ci s->local_opt.desc = 0; 1607141cc406Sopenharmony_ci s->local_opt.num_options = 0; 1608141cc406Sopenharmony_ci 1609141cc406Sopenharmony_ci DBG (3, "sane_open: getting option descriptors\n"); 1610141cc406Sopenharmony_ci status = fetch_options (s); 1611141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1612141cc406Sopenharmony_ci { 1613141cc406Sopenharmony_ci DBG (1, "sane_open: fetch_options failed (%s), closing device again\n", 1614141cc406Sopenharmony_ci sane_strstatus (status)); 1615141cc406Sopenharmony_ci 1616141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_CLOSE, 1617141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &s->handle, 1618141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &ack); 1619141cc406Sopenharmony_ci 1620141cc406Sopenharmony_ci free (s); 1621141cc406Sopenharmony_ci 1622141cc406Sopenharmony_ci return status; 1623141cc406Sopenharmony_ci } 1624141cc406Sopenharmony_ci 1625141cc406Sopenharmony_ci first_handle = s; 1626141cc406Sopenharmony_ci *meta_handle = s; 1627141cc406Sopenharmony_ci 1628141cc406Sopenharmony_ci DBG (3, "sane_open: success\n"); 1629141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1630141cc406Sopenharmony_ci} 1631141cc406Sopenharmony_ci 1632141cc406Sopenharmony_civoid 1633141cc406Sopenharmony_cisane_close (SANE_Handle handle) 1634141cc406Sopenharmony_ci{ 1635141cc406Sopenharmony_ci Net_Scanner *prev, *s; 1636141cc406Sopenharmony_ci SANE_Word ack; 1637141cc406Sopenharmony_ci int option_number; 1638141cc406Sopenharmony_ci 1639141cc406Sopenharmony_ci DBG (3, "sane_close: handle %p\n", handle); 1640141cc406Sopenharmony_ci 1641141cc406Sopenharmony_ci prev = 0; 1642141cc406Sopenharmony_ci for (s = first_handle; s; s = s->next) 1643141cc406Sopenharmony_ci { 1644141cc406Sopenharmony_ci if (s == handle) 1645141cc406Sopenharmony_ci break; 1646141cc406Sopenharmony_ci prev = s; 1647141cc406Sopenharmony_ci } 1648141cc406Sopenharmony_ci if (!s) 1649141cc406Sopenharmony_ci { 1650141cc406Sopenharmony_ci DBG (1, "sane_close: invalid handle %p\n", handle); 1651141cc406Sopenharmony_ci return; /* oops, not a handle we know about */ 1652141cc406Sopenharmony_ci } 1653141cc406Sopenharmony_ci if (prev) 1654141cc406Sopenharmony_ci prev->next = s->next; 1655141cc406Sopenharmony_ci else 1656141cc406Sopenharmony_ci first_handle = s->next; 1657141cc406Sopenharmony_ci 1658141cc406Sopenharmony_ci if (s->opt.num_options) 1659141cc406Sopenharmony_ci { 1660141cc406Sopenharmony_ci DBG (2, "sane_close: removing cached option descriptors\n"); 1661141cc406Sopenharmony_ci sanei_w_set_dir (&s->hw->wire, WIRE_FREE); 1662141cc406Sopenharmony_ci s->hw->wire.status = 0; 1663141cc406Sopenharmony_ci sanei_w_option_descriptor_array (&s->hw->wire, &s->opt); 1664141cc406Sopenharmony_ci if (s->hw->wire.status) 1665141cc406Sopenharmony_ci DBG (1, "sane_close: couldn't free sanei_w_option_descriptor_array " 1666141cc406Sopenharmony_ci "(%s)\n", sane_strstatus (s->hw->wire.status)); 1667141cc406Sopenharmony_ci } 1668141cc406Sopenharmony_ci 1669141cc406Sopenharmony_ci DBG (2, "sane_close: removing local option descriptors\n"); 1670141cc406Sopenharmony_ci for (option_number = 0; option_number < s->local_opt.num_options; 1671141cc406Sopenharmony_ci option_number++) 1672141cc406Sopenharmony_ci free (s->local_opt.desc[option_number]); 1673141cc406Sopenharmony_ci if (s->local_opt.desc) 1674141cc406Sopenharmony_ci free (s->local_opt.desc); 1675141cc406Sopenharmony_ci 1676141cc406Sopenharmony_ci DBG (2, "sane_close: net_close\n"); 1677141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_CLOSE, 1678141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &s->handle, 1679141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &ack); 1680141cc406Sopenharmony_ci if (s->data >= 0) 1681141cc406Sopenharmony_ci { 1682141cc406Sopenharmony_ci DBG (2, "sane_close: closing data pipe\n"); 1683141cc406Sopenharmony_ci close (s->data); 1684141cc406Sopenharmony_ci } 1685141cc406Sopenharmony_ci free (s); 1686141cc406Sopenharmony_ci DBG (2, "sane_close: done\n"); 1687141cc406Sopenharmony_ci} 1688141cc406Sopenharmony_ci 1689141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 1690141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 1691141cc406Sopenharmony_ci{ 1692141cc406Sopenharmony_ci Net_Scanner *s = handle; 1693141cc406Sopenharmony_ci SANE_Status status; 1694141cc406Sopenharmony_ci 1695141cc406Sopenharmony_ci DBG (3, "sane_get_option_descriptor: option %d\n", option); 1696141cc406Sopenharmony_ci 1697141cc406Sopenharmony_ci if (!s->options_valid) 1698141cc406Sopenharmony_ci { 1699141cc406Sopenharmony_ci DBG (3, "sane_get_option_descriptor: getting option descriptors\n"); 1700141cc406Sopenharmony_ci status = fetch_options (s); 1701141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1702141cc406Sopenharmony_ci { 1703141cc406Sopenharmony_ci DBG (1, "sane_get_option_descriptor: fetch_options failed (%s)\n", 1704141cc406Sopenharmony_ci sane_strstatus (status)); 1705141cc406Sopenharmony_ci return 0; 1706141cc406Sopenharmony_ci } 1707141cc406Sopenharmony_ci } 1708141cc406Sopenharmony_ci 1709141cc406Sopenharmony_ci if (((SANE_Word) option >= s->opt.num_options) || (option < 0)) 1710141cc406Sopenharmony_ci { 1711141cc406Sopenharmony_ci DBG (2, "sane_get_option_descriptor: invalid option number\n"); 1712141cc406Sopenharmony_ci return 0; 1713141cc406Sopenharmony_ci } 1714141cc406Sopenharmony_ci return s->local_opt.desc[option]; 1715141cc406Sopenharmony_ci} 1716141cc406Sopenharmony_ci 1717141cc406Sopenharmony_ciSANE_Status 1718141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 1719141cc406Sopenharmony_ci SANE_Action action, void *value, SANE_Word * info) 1720141cc406Sopenharmony_ci{ 1721141cc406Sopenharmony_ci Net_Scanner *s = handle; 1722141cc406Sopenharmony_ci SANE_Control_Option_Req req; 1723141cc406Sopenharmony_ci SANE_Control_Option_Reply reply; 1724141cc406Sopenharmony_ci SANE_Status status; 1725141cc406Sopenharmony_ci size_t value_size; 1726141cc406Sopenharmony_ci int need_auth; 1727141cc406Sopenharmony_ci SANE_Word local_info; 1728141cc406Sopenharmony_ci 1729141cc406Sopenharmony_ci DBG (3, "sane_control_option: option %d, action %d\n", option, action); 1730141cc406Sopenharmony_ci 1731141cc406Sopenharmony_ci if (!s->options_valid) 1732141cc406Sopenharmony_ci { 1733141cc406Sopenharmony_ci DBG (1, "sane_control_option: FRONTEND BUG: option descriptors reload needed\n"); 1734141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1735141cc406Sopenharmony_ci } 1736141cc406Sopenharmony_ci 1737141cc406Sopenharmony_ci if (((SANE_Word) option >= s->opt.num_options) || (option < 0)) 1738141cc406Sopenharmony_ci { 1739141cc406Sopenharmony_ci DBG (1, "sane_control_option: invalid option number\n"); 1740141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1741141cc406Sopenharmony_ci } 1742141cc406Sopenharmony_ci 1743141cc406Sopenharmony_ci switch (s->opt.desc[option]->type) 1744141cc406Sopenharmony_ci { 1745141cc406Sopenharmony_ci case SANE_TYPE_BUTTON: 1746141cc406Sopenharmony_ci case SANE_TYPE_GROUP: /* shouldn't happen... */ 1747141cc406Sopenharmony_ci /* the SANE standard defines that the option size of a BUTTON or 1748141cc406Sopenharmony_ci GROUP is IGNORED. */ 1749141cc406Sopenharmony_ci value_size = 0; 1750141cc406Sopenharmony_ci break; 1751141cc406Sopenharmony_ci case SANE_TYPE_STRING: /* strings can be smaller than size */ 1752141cc406Sopenharmony_ci value_size = s->opt.desc[option]->size; 1753141cc406Sopenharmony_ci if ((action == SANE_ACTION_SET_VALUE) 1754141cc406Sopenharmony_ci && (((SANE_Int) strlen ((SANE_String) value) + 1) 1755141cc406Sopenharmony_ci < s->opt.desc[option]->size)) 1756141cc406Sopenharmony_ci value_size = strlen ((SANE_String) value) + 1; 1757141cc406Sopenharmony_ci break; 1758141cc406Sopenharmony_ci default: 1759141cc406Sopenharmony_ci value_size = s->opt.desc[option]->size; 1760141cc406Sopenharmony_ci break; 1761141cc406Sopenharmony_ci } 1762141cc406Sopenharmony_ci 1763141cc406Sopenharmony_ci /* Avoid leaking memory bits */ 1764141cc406Sopenharmony_ci if (value && (action != SANE_ACTION_SET_VALUE)) 1765141cc406Sopenharmony_ci memset (value, 0, value_size); 1766141cc406Sopenharmony_ci 1767141cc406Sopenharmony_ci /* for SET_AUTO the parameter ``value'' is ignored */ 1768141cc406Sopenharmony_ci if (action == SANE_ACTION_SET_AUTO) 1769141cc406Sopenharmony_ci value_size = 0; 1770141cc406Sopenharmony_ci 1771141cc406Sopenharmony_ci req.handle = s->handle; 1772141cc406Sopenharmony_ci req.option = option; 1773141cc406Sopenharmony_ci req.action = action; 1774141cc406Sopenharmony_ci req.value_type = s->opt.desc[option]->type; 1775141cc406Sopenharmony_ci req.value_size = value_size; 1776141cc406Sopenharmony_ci req.value = value; 1777141cc406Sopenharmony_ci 1778141cc406Sopenharmony_ci local_info = 0; 1779141cc406Sopenharmony_ci 1780141cc406Sopenharmony_ci DBG (3, "sane_control_option: remote control option\n"); 1781141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_CONTROL_OPTION, 1782141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_control_option_req, &req, 1783141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_control_option_reply, &reply); 1784141cc406Sopenharmony_ci 1785141cc406Sopenharmony_ci do 1786141cc406Sopenharmony_ci { 1787141cc406Sopenharmony_ci status = reply.status; 1788141cc406Sopenharmony_ci need_auth = (reply.resource_to_authorize != 0); 1789141cc406Sopenharmony_ci if (need_auth) 1790141cc406Sopenharmony_ci { 1791141cc406Sopenharmony_ci DBG (3, "sane_control_option: auth required\n"); 1792141cc406Sopenharmony_ci do_authorization (s->hw, reply.resource_to_authorize); 1793141cc406Sopenharmony_ci sanei_w_free (&s->hw->wire, 1794141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_control_option_reply, &reply); 1795141cc406Sopenharmony_ci 1796141cc406Sopenharmony_ci sanei_w_set_dir (&s->hw->wire, WIRE_DECODE); 1797141cc406Sopenharmony_ci 1798141cc406Sopenharmony_ci sanei_w_control_option_reply (&s->hw->wire, &reply); 1799141cc406Sopenharmony_ci continue; 1800141cc406Sopenharmony_ci 1801141cc406Sopenharmony_ci } 1802141cc406Sopenharmony_ci else if (status == SANE_STATUS_GOOD) 1803141cc406Sopenharmony_ci { 1804141cc406Sopenharmony_ci local_info = reply.info; 1805141cc406Sopenharmony_ci 1806141cc406Sopenharmony_ci if (info) 1807141cc406Sopenharmony_ci *info = reply.info; 1808141cc406Sopenharmony_ci if (value_size > 0) 1809141cc406Sopenharmony_ci { 1810141cc406Sopenharmony_ci if ((SANE_Word) value_size == reply.value_size) 1811141cc406Sopenharmony_ci memcpy (value, reply.value, reply.value_size); 1812141cc406Sopenharmony_ci else 1813141cc406Sopenharmony_ci DBG (1, "sane_control_option: size changed from %d to %d\n", 1814141cc406Sopenharmony_ci s->opt.desc[option]->size, reply.value_size); 1815141cc406Sopenharmony_ci } 1816141cc406Sopenharmony_ci 1817141cc406Sopenharmony_ci if (reply.info & SANE_INFO_RELOAD_OPTIONS) 1818141cc406Sopenharmony_ci s->options_valid = 0; 1819141cc406Sopenharmony_ci } 1820141cc406Sopenharmony_ci sanei_w_free (&s->hw->wire, 1821141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_control_option_reply, &reply); 1822141cc406Sopenharmony_ci if (need_auth && !s->hw->auth_active) 1823141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1824141cc406Sopenharmony_ci } 1825141cc406Sopenharmony_ci while (need_auth); 1826141cc406Sopenharmony_ci 1827141cc406Sopenharmony_ci DBG (2, "sane_control_option: remote done (%s, info %x)\n", sane_strstatus (status), local_info); 1828141cc406Sopenharmony_ci 1829141cc406Sopenharmony_ci if ((status == SANE_STATUS_GOOD) && (info == NULL) && (local_info & SANE_INFO_RELOAD_OPTIONS)) 1830141cc406Sopenharmony_ci { 1831141cc406Sopenharmony_ci DBG (2, "sane_control_option: reloading options as frontend does not care\n"); 1832141cc406Sopenharmony_ci 1833141cc406Sopenharmony_ci status = fetch_options (s); 1834141cc406Sopenharmony_ci 1835141cc406Sopenharmony_ci DBG (2, "sane_control_option: reload done (%s)\n", sane_strstatus (status)); 1836141cc406Sopenharmony_ci } 1837141cc406Sopenharmony_ci 1838141cc406Sopenharmony_ci DBG (2, "sane_control_option: done (%s, info %x)\n", sane_strstatus (status), local_info); 1839141cc406Sopenharmony_ci 1840141cc406Sopenharmony_ci return status; 1841141cc406Sopenharmony_ci} 1842141cc406Sopenharmony_ci 1843141cc406Sopenharmony_ciSANE_Status 1844141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 1845141cc406Sopenharmony_ci{ 1846141cc406Sopenharmony_ci Net_Scanner *s = handle; 1847141cc406Sopenharmony_ci SANE_Get_Parameters_Reply reply; 1848141cc406Sopenharmony_ci SANE_Status status; 1849141cc406Sopenharmony_ci 1850141cc406Sopenharmony_ci DBG (3, "sane_get_parameters\n"); 1851141cc406Sopenharmony_ci 1852141cc406Sopenharmony_ci if (!params) 1853141cc406Sopenharmony_ci { 1854141cc406Sopenharmony_ci DBG (1, "sane_get_parameters: parameter params not supplied\n"); 1855141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1856141cc406Sopenharmony_ci } 1857141cc406Sopenharmony_ci 1858141cc406Sopenharmony_ci DBG (3, "sane_get_parameters: remote get parameters\n"); 1859141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_GET_PARAMETERS, 1860141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &s->handle, 1861141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_get_parameters_reply, &reply); 1862141cc406Sopenharmony_ci 1863141cc406Sopenharmony_ci status = reply.status; 1864141cc406Sopenharmony_ci *params = reply.params; 1865141cc406Sopenharmony_ci depth = reply.params.depth; 1866141cc406Sopenharmony_ci sanei_w_free (&s->hw->wire, 1867141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_get_parameters_reply, &reply); 1868141cc406Sopenharmony_ci 1869141cc406Sopenharmony_ci DBG (3, "sane_get_parameters: returned status %s\n", 1870141cc406Sopenharmony_ci sane_strstatus (status)); 1871141cc406Sopenharmony_ci return status; 1872141cc406Sopenharmony_ci} 1873141cc406Sopenharmony_ci 1874141cc406Sopenharmony_ci#ifdef NET_USES_AF_INDEP 1875141cc406Sopenharmony_ciSANE_Status 1876141cc406Sopenharmony_cisane_start (SANE_Handle handle) 1877141cc406Sopenharmony_ci{ 1878141cc406Sopenharmony_ci Net_Scanner *s = handle; 1879141cc406Sopenharmony_ci SANE_Start_Reply reply; 1880141cc406Sopenharmony_ci struct sockaddr_in sin; 1881141cc406Sopenharmony_ci struct sockaddr *sa; 1882141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1883141cc406Sopenharmony_ci struct sockaddr_in6 sin6; 1884141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1885141cc406Sopenharmony_ci SANE_Status status; 1886141cc406Sopenharmony_ci int fd, need_auth; 1887141cc406Sopenharmony_ci socklen_t len; 1888141cc406Sopenharmony_ci uint16_t port; /* Internet-specific */ 1889141cc406Sopenharmony_ci 1890141cc406Sopenharmony_ci 1891141cc406Sopenharmony_ci DBG (3, "sane_start\n"); 1892141cc406Sopenharmony_ci 1893141cc406Sopenharmony_ci hang_over = -1; 1894141cc406Sopenharmony_ci left_over = -1; 1895141cc406Sopenharmony_ci 1896141cc406Sopenharmony_ci if (s->data >= 0) 1897141cc406Sopenharmony_ci { 1898141cc406Sopenharmony_ci DBG (2, "sane_start: data pipe already exists\n"); 1899141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1900141cc406Sopenharmony_ci } 1901141cc406Sopenharmony_ci 1902141cc406Sopenharmony_ci /* Do this ahead of time so in case anything fails, we can 1903141cc406Sopenharmony_ci recover gracefully (without hanging our server). */ 1904141cc406Sopenharmony_ci 1905141cc406Sopenharmony_ci switch (s->hw->addr_used->ai_family) 1906141cc406Sopenharmony_ci { 1907141cc406Sopenharmony_ci case AF_INET: 1908141cc406Sopenharmony_ci len = sizeof (sin); 1909141cc406Sopenharmony_ci sa = (struct sockaddr *) &sin; 1910141cc406Sopenharmony_ci break; 1911141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1912141cc406Sopenharmony_ci case AF_INET6: 1913141cc406Sopenharmony_ci len = sizeof (sin6); 1914141cc406Sopenharmony_ci sa = (struct sockaddr *) &sin6; 1915141cc406Sopenharmony_ci break; 1916141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1917141cc406Sopenharmony_ci default: 1918141cc406Sopenharmony_ci DBG (1, "sane_start: unknown address family : %d\n", 1919141cc406Sopenharmony_ci s->hw->addr_used->ai_family); 1920141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1921141cc406Sopenharmony_ci } 1922141cc406Sopenharmony_ci 1923141cc406Sopenharmony_ci if (getpeername (s->hw->ctl, sa, &len) < 0) 1924141cc406Sopenharmony_ci { 1925141cc406Sopenharmony_ci DBG (1, "sane_start: getpeername() failed (%s)\n", strerror (errno)); 1926141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1927141cc406Sopenharmony_ci } 1928141cc406Sopenharmony_ci 1929141cc406Sopenharmony_ci fd = socket (s->hw->addr_used->ai_family, SOCK_STREAM, 0); 1930141cc406Sopenharmony_ci if (fd < 0) 1931141cc406Sopenharmony_ci { 1932141cc406Sopenharmony_ci DBG (1, "sane_start: socket() failed (%s)\n", strerror (errno)); 1933141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1934141cc406Sopenharmony_ci } 1935141cc406Sopenharmony_ci 1936141cc406Sopenharmony_ci DBG (3, "sane_start: remote start\n"); 1937141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_START, 1938141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &s->handle, 1939141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_start_reply, &reply); 1940141cc406Sopenharmony_ci do 1941141cc406Sopenharmony_ci { 1942141cc406Sopenharmony_ci status = reply.status; 1943141cc406Sopenharmony_ci port = reply.port; 1944141cc406Sopenharmony_ci if (reply.byte_order == 0x1234) 1945141cc406Sopenharmony_ci { 1946141cc406Sopenharmony_ci server_big_endian = 0; 1947141cc406Sopenharmony_ci DBG (1, "sane_start: server has little endian byte order\n"); 1948141cc406Sopenharmony_ci } 1949141cc406Sopenharmony_ci else 1950141cc406Sopenharmony_ci { 1951141cc406Sopenharmony_ci server_big_endian = 1; 1952141cc406Sopenharmony_ci DBG (1, "sane_start: server has big endian byte order\n"); 1953141cc406Sopenharmony_ci } 1954141cc406Sopenharmony_ci 1955141cc406Sopenharmony_ci need_auth = (reply.resource_to_authorize != 0); 1956141cc406Sopenharmony_ci if (need_auth) 1957141cc406Sopenharmony_ci { 1958141cc406Sopenharmony_ci DBG (3, "sane_start: auth required\n"); 1959141cc406Sopenharmony_ci do_authorization (s->hw, reply.resource_to_authorize); 1960141cc406Sopenharmony_ci 1961141cc406Sopenharmony_ci sanei_w_free (&s->hw->wire, 1962141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_start_reply, &reply); 1963141cc406Sopenharmony_ci 1964141cc406Sopenharmony_ci sanei_w_set_dir (&s->hw->wire, WIRE_DECODE); 1965141cc406Sopenharmony_ci 1966141cc406Sopenharmony_ci sanei_w_start_reply (&s->hw->wire, &reply); 1967141cc406Sopenharmony_ci 1968141cc406Sopenharmony_ci continue; 1969141cc406Sopenharmony_ci } 1970141cc406Sopenharmony_ci sanei_w_free (&s->hw->wire, (WireCodecFunc) sanei_w_start_reply, 1971141cc406Sopenharmony_ci &reply); 1972141cc406Sopenharmony_ci if (need_auth && !s->hw->auth_active) 1973141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1974141cc406Sopenharmony_ci 1975141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1976141cc406Sopenharmony_ci { 1977141cc406Sopenharmony_ci DBG (1, "sane_start: remote start failed (%s)\n", 1978141cc406Sopenharmony_ci sane_strstatus (status)); 1979141cc406Sopenharmony_ci close (fd); 1980141cc406Sopenharmony_ci return status; 1981141cc406Sopenharmony_ci } 1982141cc406Sopenharmony_ci } 1983141cc406Sopenharmony_ci while (need_auth); 1984141cc406Sopenharmony_ci DBG (3, "sane_start: remote start finished, data at port %hu\n", port); 1985141cc406Sopenharmony_ci 1986141cc406Sopenharmony_ci switch (s->hw->addr_used->ai_family) 1987141cc406Sopenharmony_ci { 1988141cc406Sopenharmony_ci case AF_INET: 1989141cc406Sopenharmony_ci sin.sin_port = htons (port); 1990141cc406Sopenharmony_ci break; 1991141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1992141cc406Sopenharmony_ci case AF_INET6: 1993141cc406Sopenharmony_ci sin6.sin6_port = htons (port); 1994141cc406Sopenharmony_ci break; 1995141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1996141cc406Sopenharmony_ci } 1997141cc406Sopenharmony_ci 1998141cc406Sopenharmony_ci if (connect (fd, sa, len) < 0) 1999141cc406Sopenharmony_ci { 2000141cc406Sopenharmony_ci DBG (1, "sane_start: connect() failed (%s)\n", strerror (errno)); 2001141cc406Sopenharmony_ci close (fd); 2002141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2003141cc406Sopenharmony_ci } 2004141cc406Sopenharmony_ci shutdown (fd, 1); 2005141cc406Sopenharmony_ci s->data = fd; 2006141cc406Sopenharmony_ci s->reclen_buf_offset = 0; 2007141cc406Sopenharmony_ci s->bytes_remaining = 0; 2008141cc406Sopenharmony_ci DBG (3, "sane_start: done (%s)\n", sane_strstatus (status)); 2009141cc406Sopenharmony_ci return status; 2010141cc406Sopenharmony_ci} 2011141cc406Sopenharmony_ci 2012141cc406Sopenharmony_ci#else /* !NET_USES_AF_INDEP */ 2013141cc406Sopenharmony_ci 2014141cc406Sopenharmony_ciSANE_Status 2015141cc406Sopenharmony_cisane_start (SANE_Handle handle) 2016141cc406Sopenharmony_ci{ 2017141cc406Sopenharmony_ci Net_Scanner *s = handle; 2018141cc406Sopenharmony_ci SANE_Start_Reply reply; 2019141cc406Sopenharmony_ci struct sockaddr_in sin; 2020141cc406Sopenharmony_ci SANE_Status status; 2021141cc406Sopenharmony_ci int fd, need_auth; 2022141cc406Sopenharmony_ci socklen_t len; 2023141cc406Sopenharmony_ci uint16_t port; /* Internet-specific */ 2024141cc406Sopenharmony_ci 2025141cc406Sopenharmony_ci 2026141cc406Sopenharmony_ci DBG (3, "sane_start\n"); 2027141cc406Sopenharmony_ci 2028141cc406Sopenharmony_ci hang_over = -1; 2029141cc406Sopenharmony_ci left_over = -1; 2030141cc406Sopenharmony_ci 2031141cc406Sopenharmony_ci if (s->data >= 0) 2032141cc406Sopenharmony_ci { 2033141cc406Sopenharmony_ci DBG (2, "sane_start: data pipe already exists\n"); 2034141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2035141cc406Sopenharmony_ci } 2036141cc406Sopenharmony_ci 2037141cc406Sopenharmony_ci /* Do this ahead of time so in case anything fails, we can 2038141cc406Sopenharmony_ci recover gracefully (without hanging our server). */ 2039141cc406Sopenharmony_ci len = sizeof (sin); 2040141cc406Sopenharmony_ci if (getpeername (s->hw->ctl, (struct sockaddr *) &sin, &len) < 0) 2041141cc406Sopenharmony_ci { 2042141cc406Sopenharmony_ci DBG (1, "sane_start: getpeername() failed (%s)\n", strerror (errno)); 2043141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2044141cc406Sopenharmony_ci } 2045141cc406Sopenharmony_ci 2046141cc406Sopenharmony_ci fd = socket (s->hw->addr.sa_family, SOCK_STREAM, 0); 2047141cc406Sopenharmony_ci if (fd < 0) 2048141cc406Sopenharmony_ci { 2049141cc406Sopenharmony_ci DBG (1, "sane_start: socket() failed (%s)\n", strerror (errno)); 2050141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2051141cc406Sopenharmony_ci } 2052141cc406Sopenharmony_ci 2053141cc406Sopenharmony_ci DBG (3, "sane_start: remote start\n"); 2054141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_START, 2055141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &s->handle, 2056141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_start_reply, &reply); 2057141cc406Sopenharmony_ci do 2058141cc406Sopenharmony_ci { 2059141cc406Sopenharmony_ci 2060141cc406Sopenharmony_ci status = reply.status; 2061141cc406Sopenharmony_ci port = reply.port; 2062141cc406Sopenharmony_ci if (reply.byte_order == 0x1234) 2063141cc406Sopenharmony_ci { 2064141cc406Sopenharmony_ci server_big_endian = 0; 2065141cc406Sopenharmony_ci DBG (1, "sane_start: server has little endian byte order\n"); 2066141cc406Sopenharmony_ci } 2067141cc406Sopenharmony_ci else 2068141cc406Sopenharmony_ci { 2069141cc406Sopenharmony_ci server_big_endian = 1; 2070141cc406Sopenharmony_ci DBG (1, "sane_start: server has big endian byte order\n"); 2071141cc406Sopenharmony_ci } 2072141cc406Sopenharmony_ci 2073141cc406Sopenharmony_ci need_auth = (reply.resource_to_authorize != 0); 2074141cc406Sopenharmony_ci if (need_auth) 2075141cc406Sopenharmony_ci { 2076141cc406Sopenharmony_ci DBG (3, "sane_start: auth required\n"); 2077141cc406Sopenharmony_ci do_authorization (s->hw, reply.resource_to_authorize); 2078141cc406Sopenharmony_ci 2079141cc406Sopenharmony_ci sanei_w_free (&s->hw->wire, 2080141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_start_reply, &reply); 2081141cc406Sopenharmony_ci 2082141cc406Sopenharmony_ci sanei_w_set_dir (&s->hw->wire, WIRE_DECODE); 2083141cc406Sopenharmony_ci 2084141cc406Sopenharmony_ci sanei_w_start_reply (&s->hw->wire, &reply); 2085141cc406Sopenharmony_ci 2086141cc406Sopenharmony_ci continue; 2087141cc406Sopenharmony_ci } 2088141cc406Sopenharmony_ci sanei_w_free (&s->hw->wire, (WireCodecFunc) sanei_w_start_reply, 2089141cc406Sopenharmony_ci &reply); 2090141cc406Sopenharmony_ci if (need_auth && !s->hw->auth_active) 2091141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 2092141cc406Sopenharmony_ci 2093141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2094141cc406Sopenharmony_ci { 2095141cc406Sopenharmony_ci DBG (1, "sane_start: remote start failed (%s)\n", 2096141cc406Sopenharmony_ci sane_strstatus (status)); 2097141cc406Sopenharmony_ci close (fd); 2098141cc406Sopenharmony_ci return status; 2099141cc406Sopenharmony_ci } 2100141cc406Sopenharmony_ci } 2101141cc406Sopenharmony_ci while (need_auth); 2102141cc406Sopenharmony_ci DBG (3, "sane_start: remote start finished, data at port %hu\n", port); 2103141cc406Sopenharmony_ci sin.sin_port = htons (port); 2104141cc406Sopenharmony_ci 2105141cc406Sopenharmony_ci if (connect (fd, (struct sockaddr *) &sin, len) < 0) 2106141cc406Sopenharmony_ci { 2107141cc406Sopenharmony_ci DBG (1, "sane_start: connect() failed (%s)\n", strerror (errno)); 2108141cc406Sopenharmony_ci close (fd); 2109141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2110141cc406Sopenharmony_ci } 2111141cc406Sopenharmony_ci shutdown (fd, 1); 2112141cc406Sopenharmony_ci s->data = fd; 2113141cc406Sopenharmony_ci s->reclen_buf_offset = 0; 2114141cc406Sopenharmony_ci s->bytes_remaining = 0; 2115141cc406Sopenharmony_ci DBG (3, "sane_start: done (%s)\n", sane_strstatus (status)); 2116141cc406Sopenharmony_ci return status; 2117141cc406Sopenharmony_ci} 2118141cc406Sopenharmony_ci#endif /* NET_USES_AF_INDEP */ 2119141cc406Sopenharmony_ci 2120141cc406Sopenharmony_ci 2121141cc406Sopenharmony_ciSANE_Status 2122141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, 2123141cc406Sopenharmony_ci SANE_Int * length) 2124141cc406Sopenharmony_ci{ 2125141cc406Sopenharmony_ci Net_Scanner *s = handle; 2126141cc406Sopenharmony_ci ssize_t nread; 2127141cc406Sopenharmony_ci SANE_Int cnt; 2128141cc406Sopenharmony_ci SANE_Int start_cnt; 2129141cc406Sopenharmony_ci SANE_Int end_cnt; 2130141cc406Sopenharmony_ci SANE_Byte swap_buf; 2131141cc406Sopenharmony_ci SANE_Byte temp_hang_over; 2132141cc406Sopenharmony_ci int is_even; 2133141cc406Sopenharmony_ci 2134141cc406Sopenharmony_ci DBG (3, "sane_read: handle=%p, data=%p, max_length=%d, length=%p\n", 2135141cc406Sopenharmony_ci handle, (void *) data, max_length, (void *) length); 2136141cc406Sopenharmony_ci if (!length) 2137141cc406Sopenharmony_ci { 2138141cc406Sopenharmony_ci DBG (1, "sane_read: length == NULL\n"); 2139141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2140141cc406Sopenharmony_ci } 2141141cc406Sopenharmony_ci 2142141cc406Sopenharmony_ci is_even = 1; 2143141cc406Sopenharmony_ci *length = 0; 2144141cc406Sopenharmony_ci 2145141cc406Sopenharmony_ci /* If there's a left over, i.e. a byte already in the correct byte order, 2146141cc406Sopenharmony_ci return it immediately; otherwise read may fail with a SANE_STATUS_EOF and 2147141cc406Sopenharmony_ci the caller never can read the last byte */ 2148141cc406Sopenharmony_ci if ((depth == 16) && (server_big_endian != client_big_endian)) 2149141cc406Sopenharmony_ci { 2150141cc406Sopenharmony_ci if (left_over > -1) 2151141cc406Sopenharmony_ci { 2152141cc406Sopenharmony_ci DBG (3, "sane_read: left_over from previous call, return " 2153141cc406Sopenharmony_ci "immediately\n"); 2154141cc406Sopenharmony_ci /* return the byte, we've currently scanned; hang_over becomes 2155141cc406Sopenharmony_ci left_over */ 2156141cc406Sopenharmony_ci *data = (SANE_Byte) left_over; 2157141cc406Sopenharmony_ci left_over = -1; 2158141cc406Sopenharmony_ci *length = 1; 2159141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2160141cc406Sopenharmony_ci } 2161141cc406Sopenharmony_ci } 2162141cc406Sopenharmony_ci 2163141cc406Sopenharmony_ci if (s->data < 0) 2164141cc406Sopenharmony_ci { 2165141cc406Sopenharmony_ci DBG (1, "sane_read: data pipe doesn't exist, scan cancelled?\n"); 2166141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 2167141cc406Sopenharmony_ci } 2168141cc406Sopenharmony_ci 2169141cc406Sopenharmony_ci if (s->bytes_remaining == 0) 2170141cc406Sopenharmony_ci { 2171141cc406Sopenharmony_ci /* boy, is this painful or what? */ 2172141cc406Sopenharmony_ci 2173141cc406Sopenharmony_ci DBG (4, "sane_read: reading packet length\n"); 2174141cc406Sopenharmony_ci nread = read (s->data, s->reclen_buf + s->reclen_buf_offset, 2175141cc406Sopenharmony_ci 4 - s->reclen_buf_offset); 2176141cc406Sopenharmony_ci if (nread < 0) 2177141cc406Sopenharmony_ci { 2178141cc406Sopenharmony_ci DBG (3, "sane_read: read failed (%s)\n", strerror (errno)); 2179141cc406Sopenharmony_ci if (errno == EAGAIN) 2180141cc406Sopenharmony_ci { 2181141cc406Sopenharmony_ci DBG (3, "sane_read: try again later\n"); 2182141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2183141cc406Sopenharmony_ci } 2184141cc406Sopenharmony_ci else 2185141cc406Sopenharmony_ci { 2186141cc406Sopenharmony_ci DBG (1, "sane_read: cancelling read\n"); 2187141cc406Sopenharmony_ci do_cancel (s); 2188141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2189141cc406Sopenharmony_ci } 2190141cc406Sopenharmony_ci } 2191141cc406Sopenharmony_ci DBG (4, "sane_read: read %lu bytes, %d from 4 total\n", (u_long) nread, 2192141cc406Sopenharmony_ci s->reclen_buf_offset); 2193141cc406Sopenharmony_ci s->reclen_buf_offset += nread; 2194141cc406Sopenharmony_ci if (s->reclen_buf_offset < 4) 2195141cc406Sopenharmony_ci { 2196141cc406Sopenharmony_ci DBG (4, "sane_read: enough for now\n"); 2197141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2198141cc406Sopenharmony_ci } 2199141cc406Sopenharmony_ci 2200141cc406Sopenharmony_ci s->reclen_buf_offset = 0; 2201141cc406Sopenharmony_ci s->bytes_remaining = (((u_long) s->reclen_buf[0] << 24) 2202141cc406Sopenharmony_ci | ((u_long) s->reclen_buf[1] << 16) 2203141cc406Sopenharmony_ci | ((u_long) s->reclen_buf[2] << 8) 2204141cc406Sopenharmony_ci | ((u_long) s->reclen_buf[3] << 0)); 2205141cc406Sopenharmony_ci DBG (3, "sane_read: next record length=%ld bytes\n", 2206141cc406Sopenharmony_ci (long) s->bytes_remaining); 2207141cc406Sopenharmony_ci if (s->bytes_remaining == 0xffffffff) 2208141cc406Sopenharmony_ci { 2209141cc406Sopenharmony_ci char ch; 2210141cc406Sopenharmony_ci 2211141cc406Sopenharmony_ci DBG (2, "sane_read: received error signal\n"); 2212141cc406Sopenharmony_ci 2213141cc406Sopenharmony_ci /* turn off non-blocking I/O (s->data will be closed anyhow): */ 2214141cc406Sopenharmony_ci fcntl (s->data, F_SETFL, 0); 2215141cc406Sopenharmony_ci 2216141cc406Sopenharmony_ci /* read the status byte: */ 2217141cc406Sopenharmony_ci if (read (s->data, &ch, sizeof (ch)) != 1) 2218141cc406Sopenharmony_ci { 2219141cc406Sopenharmony_ci DBG (1, "sane_read: failed to read error code\n"); 2220141cc406Sopenharmony_ci ch = SANE_STATUS_IO_ERROR; 2221141cc406Sopenharmony_ci } 2222141cc406Sopenharmony_ci DBG (1, "sane_read: error code %s\n", 2223141cc406Sopenharmony_ci sane_strstatus ((SANE_Status) ch)); 2224141cc406Sopenharmony_ci do_cancel (s); 2225141cc406Sopenharmony_ci return (SANE_Status) ch; 2226141cc406Sopenharmony_ci } 2227141cc406Sopenharmony_ci } 2228141cc406Sopenharmony_ci 2229141cc406Sopenharmony_ci if (max_length > (SANE_Int) s->bytes_remaining) 2230141cc406Sopenharmony_ci max_length = s->bytes_remaining; 2231141cc406Sopenharmony_ci 2232141cc406Sopenharmony_ci nread = read (s->data, data, max_length); 2233141cc406Sopenharmony_ci 2234141cc406Sopenharmony_ci if (nread < 0) 2235141cc406Sopenharmony_ci { 2236141cc406Sopenharmony_ci DBG (2, "sane_read: error code %s\n", strerror (errno)); 2237141cc406Sopenharmony_ci if (errno == EAGAIN) 2238141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2239141cc406Sopenharmony_ci else 2240141cc406Sopenharmony_ci { 2241141cc406Sopenharmony_ci DBG (1, "sane_read: cancelling scan\n"); 2242141cc406Sopenharmony_ci do_cancel (s); 2243141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2244141cc406Sopenharmony_ci } 2245141cc406Sopenharmony_ci } 2246141cc406Sopenharmony_ci 2247141cc406Sopenharmony_ci s->bytes_remaining -= nread; 2248141cc406Sopenharmony_ci 2249141cc406Sopenharmony_ci *length = nread; 2250141cc406Sopenharmony_ci /* Check whether we are scanning with a depth of 16 bits/pixel and whether 2251141cc406Sopenharmony_ci server and client have different byte order. If this is true, then it's 2252141cc406Sopenharmony_ci necessary to check whether read returned an odd number. If an odd number 2253141cc406Sopenharmony_ci has been returned, we must save the last byte. 2254141cc406Sopenharmony_ci */ 2255141cc406Sopenharmony_ci if ((depth == 16) && (server_big_endian != client_big_endian)) 2256141cc406Sopenharmony_ci { 2257141cc406Sopenharmony_ci DBG (1,"sane_read: client/server have different byte order; " 2258141cc406Sopenharmony_ci "must swap\n"); 2259141cc406Sopenharmony_ci /* special case: 1 byte scanned and hang_over */ 2260141cc406Sopenharmony_ci if ((nread == 1) && (hang_over > -1)) 2261141cc406Sopenharmony_ci { 2262141cc406Sopenharmony_ci /* return the byte, we've currently scanned; hang_over becomes 2263141cc406Sopenharmony_ci left_over */ 2264141cc406Sopenharmony_ci left_over = hang_over; 2265141cc406Sopenharmony_ci hang_over = -1; 2266141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2267141cc406Sopenharmony_ci } 2268141cc406Sopenharmony_ci /* check whether an even or an odd number of bytes has been scanned */ 2269141cc406Sopenharmony_ci if ((nread % 2) == 0) 2270141cc406Sopenharmony_ci is_even = 1; 2271141cc406Sopenharmony_ci else 2272141cc406Sopenharmony_ci is_even = 0; 2273141cc406Sopenharmony_ci /* check, whether there's a hang over from a previous call; 2274141cc406Sopenharmony_ci in this case we memcopy the data up one byte */ 2275141cc406Sopenharmony_ci if ((nread > 1) && (hang_over > -1)) 2276141cc406Sopenharmony_ci { 2277141cc406Sopenharmony_ci /* store last byte */ 2278141cc406Sopenharmony_ci temp_hang_over = *(data + nread - 1); 2279141cc406Sopenharmony_ci memmove (data + 1, data, nread - 1); 2280141cc406Sopenharmony_ci *data = (SANE_Byte) hang_over; 2281141cc406Sopenharmony_ci /* what happens with the last byte depends on whether the number 2282141cc406Sopenharmony_ci of bytes is even or odd */ 2283141cc406Sopenharmony_ci if (is_even == 1) 2284141cc406Sopenharmony_ci { 2285141cc406Sopenharmony_ci /* number of bytes is even; no new hang_over, exchange last 2286141cc406Sopenharmony_ci byte with hang over; last byte becomes left_over */ 2287141cc406Sopenharmony_ci left_over = *(data + nread - 1); 2288141cc406Sopenharmony_ci *(data + nread - 1) = temp_hang_over; 2289141cc406Sopenharmony_ci hang_over = -1; 2290141cc406Sopenharmony_ci start_cnt = 0; 2291141cc406Sopenharmony_ci /* last byte already swapped */ 2292141cc406Sopenharmony_ci end_cnt = nread - 2; 2293141cc406Sopenharmony_ci } 2294141cc406Sopenharmony_ci else 2295141cc406Sopenharmony_ci { 2296141cc406Sopenharmony_ci /* number of bytes is odd; last byte becomes new hang_over */ 2297141cc406Sopenharmony_ci hang_over = temp_hang_over; 2298141cc406Sopenharmony_ci left_over = -1; 2299141cc406Sopenharmony_ci start_cnt = 0; 2300141cc406Sopenharmony_ci end_cnt = nread - 1; 2301141cc406Sopenharmony_ci } 2302141cc406Sopenharmony_ci } 2303141cc406Sopenharmony_ci else if (nread == 1) 2304141cc406Sopenharmony_ci { 2305141cc406Sopenharmony_ci /* if only one byte has been read, save it as hang_over and return 2306141cc406Sopenharmony_ci length=0 */ 2307141cc406Sopenharmony_ci hang_over = (int) *data; 2308141cc406Sopenharmony_ci *length = 0; 2309141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2310141cc406Sopenharmony_ci } 2311141cc406Sopenharmony_ci else 2312141cc406Sopenharmony_ci { 2313141cc406Sopenharmony_ci /* no hang_over; test for even or odd byte number */ 2314141cc406Sopenharmony_ci if(is_even == 1) 2315141cc406Sopenharmony_ci { 2316141cc406Sopenharmony_ci start_cnt = 0; 2317141cc406Sopenharmony_ci end_cnt = *length; 2318141cc406Sopenharmony_ci } 2319141cc406Sopenharmony_ci else 2320141cc406Sopenharmony_ci { 2321141cc406Sopenharmony_ci start_cnt = 0; 2322141cc406Sopenharmony_ci hang_over = *(data + *length - 1); 2323141cc406Sopenharmony_ci *length -= 1; 2324141cc406Sopenharmony_ci end_cnt = *length; 2325141cc406Sopenharmony_ci } 2326141cc406Sopenharmony_ci } 2327141cc406Sopenharmony_ci /* swap the bytes */ 2328141cc406Sopenharmony_ci for (cnt = start_cnt; cnt < end_cnt - 1; cnt += 2) 2329141cc406Sopenharmony_ci { 2330141cc406Sopenharmony_ci swap_buf = *(data + cnt); 2331141cc406Sopenharmony_ci *(data + cnt) = *(data + cnt + 1); 2332141cc406Sopenharmony_ci *(data + cnt + 1) = swap_buf; 2333141cc406Sopenharmony_ci } 2334141cc406Sopenharmony_ci } 2335141cc406Sopenharmony_ci DBG (3, "sane_read: %lu bytes read, %lu remaining\n", (u_long) nread, 2336141cc406Sopenharmony_ci (u_long) s->bytes_remaining); 2337141cc406Sopenharmony_ci 2338141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2339141cc406Sopenharmony_ci} 2340141cc406Sopenharmony_ci 2341141cc406Sopenharmony_civoid 2342141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 2343141cc406Sopenharmony_ci{ 2344141cc406Sopenharmony_ci Net_Scanner *s = handle; 2345141cc406Sopenharmony_ci SANE_Word ack; 2346141cc406Sopenharmony_ci 2347141cc406Sopenharmony_ci DBG (3, "sane_cancel: sending net_cancel\n"); 2348141cc406Sopenharmony_ci 2349141cc406Sopenharmony_ci sanei_w_call (&s->hw->wire, SANE_NET_CANCEL, 2350141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &s->handle, 2351141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_word, &ack); 2352141cc406Sopenharmony_ci do_cancel (s); 2353141cc406Sopenharmony_ci DBG (4, "sane_cancel: done\n"); 2354141cc406Sopenharmony_ci} 2355141cc406Sopenharmony_ci 2356141cc406Sopenharmony_ciSANE_Status 2357141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 2358141cc406Sopenharmony_ci{ 2359141cc406Sopenharmony_ci Net_Scanner *s = handle; 2360141cc406Sopenharmony_ci 2361141cc406Sopenharmony_ci DBG (3, "sane_set_io_mode: non_blocking = %d\n", non_blocking); 2362141cc406Sopenharmony_ci if (s->data < 0) 2363141cc406Sopenharmony_ci { 2364141cc406Sopenharmony_ci DBG (1, "sane_set_io_mode: pipe doesn't exist\n"); 2365141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2366141cc406Sopenharmony_ci } 2367141cc406Sopenharmony_ci 2368141cc406Sopenharmony_ci if (fcntl (s->data, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) 2369141cc406Sopenharmony_ci { 2370141cc406Sopenharmony_ci DBG (1, "sane_set_io_mode: fcntl failed (%s)\n", strerror (errno)); 2371141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 2372141cc406Sopenharmony_ci } 2373141cc406Sopenharmony_ci 2374141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2375141cc406Sopenharmony_ci} 2376141cc406Sopenharmony_ci 2377141cc406Sopenharmony_ciSANE_Status 2378141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd) 2379141cc406Sopenharmony_ci{ 2380141cc406Sopenharmony_ci Net_Scanner *s = handle; 2381141cc406Sopenharmony_ci 2382141cc406Sopenharmony_ci DBG (3, "sane_get_select_fd\n"); 2383141cc406Sopenharmony_ci 2384141cc406Sopenharmony_ci if (s->data < 0) 2385141cc406Sopenharmony_ci { 2386141cc406Sopenharmony_ci DBG (1, "sane_get_select_fd: pipe doesn't exist\n"); 2387141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2388141cc406Sopenharmony_ci } 2389141cc406Sopenharmony_ci 2390141cc406Sopenharmony_ci *fd = s->data; 2391141cc406Sopenharmony_ci DBG (3, "sane_get_select_fd: done; *fd = %d\n", *fd); 2392141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2393141cc406Sopenharmony_ci} 2394