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