1141cc406Sopenharmony_ci/* SANE - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2008  2012 by Louis Lagendijk
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   SANE is free software; you can redistribute it and/or modify it
8141cc406Sopenharmony_ci   under the terms of the GNU General Public License as published by
9141cc406Sopenharmony_ci   the Free Software Foundation; either version 2 of the License, or
10141cc406Sopenharmony_ci   (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   SANE is distributed in the hope that it will be useful, but WITHOUT
13141cc406Sopenharmony_ci   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14141cc406Sopenharmony_ci   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15141cc406Sopenharmony_ci   License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with sane; see the file COPYING.
19141cc406Sopenharmony_ci   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
43141cc406Sopenharmony_ci#undef BACKEND_NAME
44141cc406Sopenharmony_ci#define BACKEND_NAME bjnp
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci#include  "../include/sane/config.h"
47141cc406Sopenharmony_ci#include  "../include/sane/sane.h"
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci/*
50141cc406Sopenharmony_ci * Standard types etc
51141cc406Sopenharmony_ci */
52141cc406Sopenharmony_ci#ifdef HAVE_STDLIB_H
53141cc406Sopenharmony_ci#include <stdlib.h>
54141cc406Sopenharmony_ci#endif
55141cc406Sopenharmony_ci#ifdef HAVE_STRING_H
56141cc406Sopenharmony_ci#include <string.h>
57141cc406Sopenharmony_ci#endif
58141cc406Sopenharmony_ci#include <unistd.h>
59141cc406Sopenharmony_ci#include <stdio.h>
60141cc406Sopenharmony_ci#ifdef HAVE_STDINT_H
61141cc406Sopenharmony_ci#include <stdint.h>
62141cc406Sopenharmony_ci#endif
63141cc406Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H
64141cc406Sopenharmony_ci#include <sys/types.h>
65141cc406Sopenharmony_ci#endif
66141cc406Sopenharmony_ci#ifdef HAVE_SYS_TIME_H
67141cc406Sopenharmony_ci#include <sys/time.h>
68141cc406Sopenharmony_ci#endif
69141cc406Sopenharmony_ci#ifdef HAVE_LIMITS_H
70141cc406Sopenharmony_ci#include <limits.h>
71141cc406Sopenharmony_ci#endif
72141cc406Sopenharmony_ci#ifdef HAVE_UNISTD_H
73141cc406Sopenharmony_ci#include <unistd.h>
74141cc406Sopenharmony_ci#endif
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci/*
77141cc406Sopenharmony_ci * networking stuff
78141cc406Sopenharmony_ci */
79141cc406Sopenharmony_ci#ifdef HAVE_SYS_SOCKET_H
80141cc406Sopenharmony_ci#include <sys/socket.h>
81141cc406Sopenharmony_ci#endif
82141cc406Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
83141cc406Sopenharmony_ci#include <netinet/in.h>
84141cc406Sopenharmony_ci#endif
85141cc406Sopenharmony_ci#include <netinet/tcp.h>
86141cc406Sopenharmony_ci#include <arpa/inet.h>
87141cc406Sopenharmony_ci#include <netdb.h>
88141cc406Sopenharmony_ci#include <net/if.h>
89141cc406Sopenharmony_ci#ifdef HAVE_IFADDRS_H
90141cc406Sopenharmony_ci#include <ifaddrs.h>
91141cc406Sopenharmony_ci#endif
92141cc406Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H
93141cc406Sopenharmony_ci#include <sys/select.h>
94141cc406Sopenharmony_ci#endif
95141cc406Sopenharmony_ci#ifdef HAVE_PWD_H
96141cc406Sopenharmony_ci#include <pwd.h>
97141cc406Sopenharmony_ci#endif
98141cc406Sopenharmony_ci#include <errno.h>
99141cc406Sopenharmony_ci#ifdef HAVE_FCNTL_H
100141cc406Sopenharmony_ci#include <fcntl.h>
101141cc406Sopenharmony_ci#endif
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci#include "pixma_bjnp_private.h"
104141cc406Sopenharmony_ci#include "pixma_bjnp.h"
105141cc406Sopenharmony_ci/* #include "pixma_rename.h" */
106141cc406Sopenharmony_ci#include "pixma.h"
107141cc406Sopenharmony_ci#include "pixma_common.h"
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci#ifndef SSIZE_MAX
110141cc406Sopenharmony_ci# define SSIZE_MAX      LONG_MAX
111141cc406Sopenharmony_ci#endif
112141cc406Sopenharmony_ci#ifndef HOST_NAME_MAX
113141cc406Sopenharmony_ci# ifdef _POSIX_HOST_NAME_MAX
114141cc406Sopenharmony_ci#  define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
115141cc406Sopenharmony_ci# else
116141cc406Sopenharmony_ci#  define HOST_NAME_MAX 255
117141cc406Sopenharmony_ci# endif
118141cc406Sopenharmony_ci#endif
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci/* static data */
121141cc406Sopenharmony_cistatic bjnp_device_t device[BJNP_NO_DEVICES];
122141cc406Sopenharmony_cistatic int bjnp_no_devices = 0;
123141cc406Sopenharmony_ci
124141cc406Sopenharmony_ci/*
125141cc406Sopenharmony_ci * Private functions
126141cc406Sopenharmony_ci */
127141cc406Sopenharmony_ci
128141cc406Sopenharmony_cistatic const struct pixma_config_t *lookup_scanner(const char *makemodel,
129141cc406Sopenharmony_ci                                                   const struct pixma_config_t *const pixma_devices[])
130141cc406Sopenharmony_ci{
131141cc406Sopenharmony_ci  int i;
132141cc406Sopenharmony_ci  const struct pixma_config_t *cfg;
133141cc406Sopenharmony_ci  char *match;
134141cc406Sopenharmony_ci
135141cc406Sopenharmony_ci  for (i = 0; pixma_devices[i]; i++)
136141cc406Sopenharmony_ci    {
137141cc406Sopenharmony_ci      /* loop through the device classes (mp150, mp730 etc) */
138141cc406Sopenharmony_ci      for (cfg = pixma_devices[i]; cfg->name; cfg++)
139141cc406Sopenharmony_ci        {
140141cc406Sopenharmony_ci          /* loop through devices in class */
141141cc406Sopenharmony_ci          PDBG( bjnp_dbg( LOG_DEBUG3, "lookup_scanner: Checking for %s in %s\n", makemodel, cfg->model));
142141cc406Sopenharmony_ci          if ((match = strcasestr (makemodel, cfg->model)) != NULL)
143141cc406Sopenharmony_ci            {
144141cc406Sopenharmony_ci              /* possible match found, make sure it is not a partial match */
145141cc406Sopenharmony_ci              /* MP600 and MP600R are different models! */
146141cc406Sopenharmony_ci              /* some models contain ranges, so check for a '-' too */
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_ci              if ((match[strlen(cfg->model)] == ' ') ||
149141cc406Sopenharmony_ci                  (match[strlen(cfg->model)] == '\0') ||
150141cc406Sopenharmony_ci                  (match[strlen(cfg->model)] == '-'))
151141cc406Sopenharmony_ci                {
152141cc406Sopenharmony_ci                  PDBG( bjnp_dbg (LOG_DEBUG, "lookup_scanner: Scanner model found: Name %s(%s) matches %s\n", cfg->model, cfg->name, makemodel));
153141cc406Sopenharmony_ci                  return cfg;
154141cc406Sopenharmony_ci                }
155141cc406Sopenharmony_ci            }
156141cc406Sopenharmony_ci       }
157141cc406Sopenharmony_ci    }
158141cc406Sopenharmony_ci  PDBG( bjnp_dbg (LOG_DEBUG, "lookup_scanner: Scanner model %s not found, giving up!\n", makemodel));
159141cc406Sopenharmony_ci  return NULL;
160141cc406Sopenharmony_ci}
161141cc406Sopenharmony_ci
162141cc406Sopenharmony_cistatic void
163141cc406Sopenharmony_ciu8tohex (char *string, const uint8_t *value, int len )
164141cc406Sopenharmony_ci{
165141cc406Sopenharmony_ci  int i;
166141cc406Sopenharmony_ci  int x;
167141cc406Sopenharmony_ci  const char hdigit[16] =
168141cc406Sopenharmony_ci    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
169141cc406Sopenharmony_ci    'e', 'f'
170141cc406Sopenharmony_ci  };
171141cc406Sopenharmony_ci  for (i = 0; i < len; i++)
172141cc406Sopenharmony_ci    {
173141cc406Sopenharmony_ci      x = value[i];
174141cc406Sopenharmony_ci      string[ 2 * i ] = hdigit[(x >> 4) & 0xf];
175141cc406Sopenharmony_ci      string[ 2 * i + 1] = hdigit[x & 0xf];
176141cc406Sopenharmony_ci    }
177141cc406Sopenharmony_ci  string[2 * len ] = '\0';
178141cc406Sopenharmony_ci}
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_cistatic void
181141cc406Sopenharmony_ciu32tohex (uint32_t x, char *str)
182141cc406Sopenharmony_ci{
183141cc406Sopenharmony_ci  uint8_t uint8[4];
184141cc406Sopenharmony_ci  uint8[0] = (uint8_t)(x >> 24);
185141cc406Sopenharmony_ci  uint8[1] = (uint8_t)(x >> 16);
186141cc406Sopenharmony_ci  uint8[2] = (uint8_t)(x >> 8);
187141cc406Sopenharmony_ci  uint8[3] = (uint8_t)x ;
188141cc406Sopenharmony_ci  u8tohex(str, uint8, 4);
189141cc406Sopenharmony_ci}
190141cc406Sopenharmony_ci
191141cc406Sopenharmony_cistatic void
192141cc406Sopenharmony_cibjnp_hexdump (int level, const void *d_, unsigned len)
193141cc406Sopenharmony_ci{
194141cc406Sopenharmony_ci  const uint8_t *d = (const uint8_t *) (d_);
195141cc406Sopenharmony_ci  unsigned ofs, c, plen;
196141cc406Sopenharmony_ci  char line[100];               /* actually only 1+8+1+8*3+1+8*3+1 = 61 bytes needed */
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci  if (level > DBG_LEVEL)
199141cc406Sopenharmony_ci    return;
200141cc406Sopenharmony_ci  if (level == DBG_LEVEL)
201141cc406Sopenharmony_ci    /* if debuglevel == exact match and buffer contains more than 3 lines, print 2 lines + .... */
202141cc406Sopenharmony_ci    plen = (len > 64) ? 32: len;
203141cc406Sopenharmony_ci  else
204141cc406Sopenharmony_ci    plen = len;
205141cc406Sopenharmony_ci  ofs = 0;
206141cc406Sopenharmony_ci  while (ofs < plen)
207141cc406Sopenharmony_ci    {
208141cc406Sopenharmony_ci      char *p;
209141cc406Sopenharmony_ci      line[0] = ' ';
210141cc406Sopenharmony_ci      u32tohex (ofs, line + 1);
211141cc406Sopenharmony_ci      line[9] = ':';
212141cc406Sopenharmony_ci      p = line + 10;
213141cc406Sopenharmony_ci      for (c = 0; c != 16 && (ofs + c) < plen; c++)
214141cc406Sopenharmony_ci        {
215141cc406Sopenharmony_ci          u8tohex (p, d + ofs + c, 1);
216141cc406Sopenharmony_ci          p[2] = ' ';
217141cc406Sopenharmony_ci          p += 3;
218141cc406Sopenharmony_ci          if (c == 7)
219141cc406Sopenharmony_ci            {
220141cc406Sopenharmony_ci              p[0] = ' ';
221141cc406Sopenharmony_ci              p++;
222141cc406Sopenharmony_ci            }
223141cc406Sopenharmony_ci        }
224141cc406Sopenharmony_ci      p[0] = '\0';
225141cc406Sopenharmony_ci      bjnp_dbg (level, "%s\n", line);
226141cc406Sopenharmony_ci      ofs += c;
227141cc406Sopenharmony_ci    }
228141cc406Sopenharmony_ci  if (len > plen)
229141cc406Sopenharmony_ci    bjnp_dbg(level, "......\n");
230141cc406Sopenharmony_ci}
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_cistatic int sa_is_equal( const bjnp_sockaddr_t * sa1, const bjnp_sockaddr_t * sa2)
233141cc406Sopenharmony_ci{
234141cc406Sopenharmony_ci  if ((sa1 == NULL) || (sa2 == NULL) )
235141cc406Sopenharmony_ci    return 0;
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci  if (sa1->addr.sa_family == sa2-> addr.sa_family)
238141cc406Sopenharmony_ci    {
239141cc406Sopenharmony_ci      if( sa1 -> addr.sa_family == AF_INET)
240141cc406Sopenharmony_ci        {
241141cc406Sopenharmony_ci          if ( (sa1->ipv4.sin_port == sa2->ipv4.sin_port) &&
242141cc406Sopenharmony_ci               (sa1->ipv4.sin_addr.s_addr == sa2->ipv4.sin_addr.s_addr))
243141cc406Sopenharmony_ci            {
244141cc406Sopenharmony_ci            return 1;
245141cc406Sopenharmony_ci            }
246141cc406Sopenharmony_ci        }
247141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
248141cc406Sopenharmony_ci      else if (sa1 -> addr.sa_family == AF_INET6 )
249141cc406Sopenharmony_ci        {
250141cc406Sopenharmony_ci          if ( (sa1-> ipv6.sin6_port == sa2->ipv6.sin6_port) &&
251141cc406Sopenharmony_ci              (memcmp(&(sa1->ipv6.sin6_addr), &(sa2->ipv6.sin6_addr), sizeof(struct in6_addr)) == 0))
252141cc406Sopenharmony_ci            {
253141cc406Sopenharmony_ci              return 1;
254141cc406Sopenharmony_ci            }
255141cc406Sopenharmony_ci        }
256141cc406Sopenharmony_ci#endif
257141cc406Sopenharmony_ci    }
258141cc406Sopenharmony_ci    return 0;
259141cc406Sopenharmony_ci}
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_cistatic int
262141cc406Sopenharmony_cisa_size( const bjnp_sockaddr_t *sa)
263141cc406Sopenharmony_ci{
264141cc406Sopenharmony_ci  switch (sa -> addr.sa_family)
265141cc406Sopenharmony_ci    {
266141cc406Sopenharmony_ci      case AF_INET:
267141cc406Sopenharmony_ci        return (sizeof(struct sockaddr_in) );
268141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
269141cc406Sopenharmony_ci      case AF_INET6:
270141cc406Sopenharmony_ci        return (sizeof(struct sockaddr_in6) );
271141cc406Sopenharmony_ci#endif
272141cc406Sopenharmony_ci      default:
273141cc406Sopenharmony_ci        /* should not occur */
274141cc406Sopenharmony_ci        return sizeof( bjnp_sockaddr_t );
275141cc406Sopenharmony_ci    }
276141cc406Sopenharmony_ci}
277141cc406Sopenharmony_ci
278141cc406Sopenharmony_cistatic int
279141cc406Sopenharmony_ciget_protocol_family( const bjnp_sockaddr_t *sa)
280141cc406Sopenharmony_ci{
281141cc406Sopenharmony_ci  switch (sa -> addr.sa_family)
282141cc406Sopenharmony_ci    {
283141cc406Sopenharmony_ci      case AF_INET:
284141cc406Sopenharmony_ci        return PF_INET;
285141cc406Sopenharmony_ci        break;
286141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
287141cc406Sopenharmony_ci      case AF_INET6:
288141cc406Sopenharmony_ci        return PF_INET6;
289141cc406Sopenharmony_ci        break;
290141cc406Sopenharmony_ci#endif
291141cc406Sopenharmony_ci      default:
292141cc406Sopenharmony_ci        /* should not occur */
293141cc406Sopenharmony_ci        return -1;
294141cc406Sopenharmony_ci    }
295141cc406Sopenharmony_ci}
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_cistatic void
298141cc406Sopenharmony_ciget_address_info ( const bjnp_sockaddr_t *addr, char * addr_string, int *port)
299141cc406Sopenharmony_ci{
300141cc406Sopenharmony_ci  char tmp_addr[BJNP_HOST_MAX];
301141cc406Sopenharmony_ci  if ( addr->addr.sa_family == AF_INET)
302141cc406Sopenharmony_ci    {
303141cc406Sopenharmony_ci      inet_ntop( AF_INET, &(addr -> ipv4.sin_addr.s_addr), addr_string, BJNP_HOST_MAX);
304141cc406Sopenharmony_ci      *port = ntohs (addr->ipv4.sin_port);
305141cc406Sopenharmony_ci    }
306141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
307141cc406Sopenharmony_ci  else if (addr->addr.sa_family == AF_INET6)
308141cc406Sopenharmony_ci    {
309141cc406Sopenharmony_ci      inet_ntop( AF_INET6, addr -> ipv6.sin6_addr.s6_addr, tmp_addr, sizeof(tmp_addr) );
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ci      if (IN6_IS_ADDR_LINKLOCAL( &(addr -> ipv6.sin6_addr) ) )
312141cc406Sopenharmony_ci          sprintf(addr_string, "[%s%%%d]", tmp_addr, addr -> ipv6.sin6_scope_id);
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci      *port = ntohs (addr->ipv6.sin6_port);
315141cc406Sopenharmony_ci    }
316141cc406Sopenharmony_ci#endif
317141cc406Sopenharmony_ci  else
318141cc406Sopenharmony_ci    {
319141cc406Sopenharmony_ci      /* unknown address family, should not occur */
320141cc406Sopenharmony_ci      strcpy(addr_string, "Unknown address family");
321141cc406Sopenharmony_ci      *port = 0;
322141cc406Sopenharmony_ci    }
323141cc406Sopenharmony_ci}
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_cistatic int
326141cc406Sopenharmony_ciparse_IEEE1284_to_model (char *scanner_id, char *model)
327141cc406Sopenharmony_ci{
328141cc406Sopenharmony_ci/*
329141cc406Sopenharmony_ci * parses the  IEEE1284  ID of the scanner to retrieve make and model
330141cc406Sopenharmony_ci * of the scanner
331141cc406Sopenharmony_ci * Returns: 0 = not found
332141cc406Sopenharmony_ci *          1 = found, model is set
333141cc406Sopenharmony_ci */
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci  char s[BJNP_IEEE1284_MAX];
336141cc406Sopenharmony_ci  char *tok;
337141cc406Sopenharmony_ci  char * model_str;
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci  strncpy (s, scanner_id, BJNP_IEEE1284_MAX);
340141cc406Sopenharmony_ci  s[BJNP_IEEE1284_MAX - 1] = '\0';
341141cc406Sopenharmony_ci  model[0] = '\0';
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci  tok = strtok (s, ";");
344141cc406Sopenharmony_ci  while (tok != NULL)
345141cc406Sopenharmony_ci    {
346141cc406Sopenharmony_ci      /* MDL contains make and model */
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci      if (strncmp (tok, "MDL:", strlen("MDL:")) == 0)
349141cc406Sopenharmony_ci	{
350141cc406Sopenharmony_ci	  model_str = tok + strlen("MDL:");
351141cc406Sopenharmony_ci	  strncpy (model, model_str, BJNP_MODEL_MAX);
352141cc406Sopenharmony_ci	  model[BJNP_MODEL_MAX -1] = '\0';
353141cc406Sopenharmony_ci	  return 1;
354141cc406Sopenharmony_ci	}
355141cc406Sopenharmony_ci      tok = strtok (NULL, ";");
356141cc406Sopenharmony_ci    }
357141cc406Sopenharmony_ci  return 0;
358141cc406Sopenharmony_ci}
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_cistatic int
361141cc406Sopenharmony_cicharTo2byte (char *d, const char *s, int len)
362141cc406Sopenharmony_ci{
363141cc406Sopenharmony_ci  /*
364141cc406Sopenharmony_ci   * copy ASCII string to UTF-16 unicode string
365141cc406Sopenharmony_ci   * len is length of destination buffer
366141cc406Sopenharmony_ci   * Returns: number of characters copied
367141cc406Sopenharmony_ci   */
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci  int done = 0;
370141cc406Sopenharmony_ci  int copied = 0;
371141cc406Sopenharmony_ci  int i;
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci  len = len / 2;
374141cc406Sopenharmony_ci  for (i = 0; i < len; i++)
375141cc406Sopenharmony_ci    {
376141cc406Sopenharmony_ci      d[2 * i] = '\0';
377141cc406Sopenharmony_ci      if (s[i] == '\0')
378141cc406Sopenharmony_ci	{
379141cc406Sopenharmony_ci	  done = 1;
380141cc406Sopenharmony_ci	}
381141cc406Sopenharmony_ci      if (done == 0)
382141cc406Sopenharmony_ci	{
383141cc406Sopenharmony_ci	  d[2 * i + 1] = s[i];
384141cc406Sopenharmony_ci	  copied++;
385141cc406Sopenharmony_ci	}
386141cc406Sopenharmony_ci      else
387141cc406Sopenharmony_ci	d[2 * i + 1] = '\0';
388141cc406Sopenharmony_ci    }
389141cc406Sopenharmony_ci  return copied;
390141cc406Sopenharmony_ci}
391141cc406Sopenharmony_ci
392141cc406Sopenharmony_cistatic bjnp_protocol_defs_t *get_protocol_by_method( char *method)
393141cc406Sopenharmony_ci{
394141cc406Sopenharmony_ci  int i = 0;
395141cc406Sopenharmony_ci  while ( bjnp_protocol_defs[i].method_string != NULL)
396141cc406Sopenharmony_ci    {
397141cc406Sopenharmony_ci      if (strcmp(method, bjnp_protocol_defs[i].method_string) == 0)
398141cc406Sopenharmony_ci        {
399141cc406Sopenharmony_ci          return &bjnp_protocol_defs[i];
400141cc406Sopenharmony_ci        }
401141cc406Sopenharmony_ci      i++;
402141cc406Sopenharmony_ci    }
403141cc406Sopenharmony_ci  return NULL;
404141cc406Sopenharmony_ci}
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_cistatic bjnp_protocol_defs_t *get_protocol_by_proto_string( char *proto_string)
407141cc406Sopenharmony_ci{
408141cc406Sopenharmony_ci  int i = 0;
409141cc406Sopenharmony_ci  while ( bjnp_protocol_defs[i].proto_string != NULL)
410141cc406Sopenharmony_ci    {
411141cc406Sopenharmony_ci      if (strncmp(proto_string, bjnp_protocol_defs[i].proto_string, 4) == 0)
412141cc406Sopenharmony_ci        {
413141cc406Sopenharmony_ci          return &bjnp_protocol_defs[i];
414141cc406Sopenharmony_ci        }
415141cc406Sopenharmony_ci      i++;
416141cc406Sopenharmony_ci    }
417141cc406Sopenharmony_ci  return NULL;
418141cc406Sopenharmony_ci}
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_cistatic char *
421141cc406Sopenharmony_cigetusername (void)
422141cc406Sopenharmony_ci{
423141cc406Sopenharmony_ci  static char noname[] = "sane_pixma";
424141cc406Sopenharmony_ci  struct passwd *pwdent;
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci#ifdef HAVE_PWD_H
427141cc406Sopenharmony_ci  if (((pwdent = getpwuid (geteuid ())) != NULL) && (pwdent->pw_name != NULL))
428141cc406Sopenharmony_ci    return pwdent->pw_name;
429141cc406Sopenharmony_ci#endif
430141cc406Sopenharmony_ci  return noname;
431141cc406Sopenharmony_ci}
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_cistatic char *
435141cc406Sopenharmony_cidetermine_scanner_serial (const char *hostname, const char * mac_address, char *serial)
436141cc406Sopenharmony_ci{
437141cc406Sopenharmony_ci  char *dot;
438141cc406Sopenharmony_ci  char copy[BJNP_HOST_MAX];
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci  /* determine a "serial number" for the scanner */
441141cc406Sopenharmony_ci  /* if available we use the hostname or ipv4 address of the printer */
442141cc406Sopenharmony_ci  /* if we only have a literal ipv6 address, we use the mac-address */
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ci  strcpy(copy, hostname);
445141cc406Sopenharmony_ci  if (strlen (copy) >= SERIAL_MAX)
446141cc406Sopenharmony_ci    {
447141cc406Sopenharmony_ci      /* make the string fit into the serial */
448141cc406Sopenharmony_ci      /* if this is a FQDN, not an ip-address, remove domain part of the name */
449141cc406Sopenharmony_ci      if ((dot = strchr (copy, '.')) != NULL)
450141cc406Sopenharmony_ci        {
451141cc406Sopenharmony_ci          *dot = '\0';
452141cc406Sopenharmony_ci        }
453141cc406Sopenharmony_ci    }
454141cc406Sopenharmony_ci  /* check if name is still to long. If so use the mac-address */
455141cc406Sopenharmony_ci  if (strlen(copy) >= SERIAL_MAX)
456141cc406Sopenharmony_ci    {
457141cc406Sopenharmony_ci      strcpy(copy, mac_address);
458141cc406Sopenharmony_ci    }
459141cc406Sopenharmony_ci  strcpy( serial, copy );
460141cc406Sopenharmony_ci  return serial;
461141cc406Sopenharmony_ci}
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_cistatic int
464141cc406Sopenharmony_cisplit_uri (const char *devname, char *method, char *host, char *port,
465141cc406Sopenharmony_ci	   char *args)
466141cc406Sopenharmony_ci{
467141cc406Sopenharmony_ci  char copy[1024];
468141cc406Sopenharmony_ci  char *start;
469141cc406Sopenharmony_ci  char next;
470141cc406Sopenharmony_ci  int i;
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci  strncpy (copy, devname, 1024);
473141cc406Sopenharmony_ci  copy[1023] = '\0';
474141cc406Sopenharmony_ci  start = copy;
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci/*
477141cc406Sopenharmony_ci * retrieve method
478141cc406Sopenharmony_ci */
479141cc406Sopenharmony_ci  i = 0;
480141cc406Sopenharmony_ci  while ((start[i] != '\0') && (start[i] != ':'))
481141cc406Sopenharmony_ci    {
482141cc406Sopenharmony_ci      i++;
483141cc406Sopenharmony_ci    }
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_ci  if (((strncmp (start + i, "://", 3) != 0)) || (i > BJNP_METHOD_MAX -1 ))
486141cc406Sopenharmony_ci    {
487141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find method in %s (offset %d)\n",
488141cc406Sopenharmony_ci		       devname, i));
489141cc406Sopenharmony_ci      return -1;
490141cc406Sopenharmony_ci    }
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_ci  start[i] = '\0';
493141cc406Sopenharmony_ci  strcpy (method, start);
494141cc406Sopenharmony_ci  start = start + i + 3;
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci/*
497141cc406Sopenharmony_ci * retrieve host
498141cc406Sopenharmony_ci */
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci  if (start[0] == '[')
501141cc406Sopenharmony_ci    {
502141cc406Sopenharmony_ci      /* literal IPv6 address */
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci      char *end_of_address = strchr(start, ']');
505141cc406Sopenharmony_ci
506141cc406Sopenharmony_ci      if ( ( end_of_address == NULL) ||
507141cc406Sopenharmony_ci           ( (end_of_address[1] != ':') && (end_of_address[1] != '/' ) &&  (end_of_address[1] != '\0' )) ||
508141cc406Sopenharmony_ci           ( (end_of_address - start) >= BJNP_HOST_MAX ) )
509141cc406Sopenharmony_ci        {
510141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find hostname or address in %s\n", devname));
511141cc406Sopenharmony_ci          return -1;
512141cc406Sopenharmony_ci        }
513141cc406Sopenharmony_ci      next = end_of_address[1];
514141cc406Sopenharmony_ci      *end_of_address = '\0';
515141cc406Sopenharmony_ci      strcpy(host, start + 1);
516141cc406Sopenharmony_ci      start = end_of_address + 2;
517141cc406Sopenharmony_ci    }
518141cc406Sopenharmony_ci  else
519141cc406Sopenharmony_ci    {
520141cc406Sopenharmony_ci      i = 0;
521141cc406Sopenharmony_ci      while ((start[i] != '\0') && (start[i] != '/') && (start[i] != ':'))
522141cc406Sopenharmony_ci        {
523141cc406Sopenharmony_ci          i++;
524141cc406Sopenharmony_ci        }
525141cc406Sopenharmony_ci      next = start[i];
526141cc406Sopenharmony_ci      start[i] = '\0';
527141cc406Sopenharmony_ci      if ((i == 0) || (i >= BJNP_HOST_MAX ) )
528141cc406Sopenharmony_ci        {
529141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find hostname or address in %s\n", devname));
530141cc406Sopenharmony_ci          return -1;
531141cc406Sopenharmony_ci        }
532141cc406Sopenharmony_ci      strcpy (host, start);
533141cc406Sopenharmony_ci      start = start + i +1;
534141cc406Sopenharmony_ci    }
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci/*
538141cc406Sopenharmony_ci * retrieve port number
539141cc406Sopenharmony_ci */
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci  if (next != ':')
542141cc406Sopenharmony_ci    strcpy(port, "");
543141cc406Sopenharmony_ci  else
544141cc406Sopenharmony_ci    {
545141cc406Sopenharmony_ci      char *end_of_port = strchr(start, '/');
546141cc406Sopenharmony_ci      if (end_of_port == NULL)
547141cc406Sopenharmony_ci        {
548141cc406Sopenharmony_ci          next = '\0';
549141cc406Sopenharmony_ci        }
550141cc406Sopenharmony_ci      else
551141cc406Sopenharmony_ci        {
552141cc406Sopenharmony_ci          next = *end_of_port;
553141cc406Sopenharmony_ci          *end_of_port = '\0';
554141cc406Sopenharmony_ci        }
555141cc406Sopenharmony_ci      if ((strlen(start) == 0) || (strlen(start) >= BJNP_PORT_MAX ) )
556141cc406Sopenharmony_ci        {
557141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find port in %s (have \"%s\")\n", devname, start));
558141cc406Sopenharmony_ci          return -1;
559141cc406Sopenharmony_ci        }
560141cc406Sopenharmony_ci      strcpy(port, start);
561141cc406Sopenharmony_ci      start = end_of_port + 1;
562141cc406Sopenharmony_ci    }
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci/*
565141cc406Sopenharmony_ci * Retrieve arguments
566141cc406Sopenharmony_ci */
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci  if (next == '/')
569141cc406Sopenharmony_ci    {
570141cc406Sopenharmony_ci    i = strlen(start);
571141cc406Sopenharmony_ci    if ( i >= BJNP_ARGS_MAX)
572141cc406Sopenharmony_ci      {
573141cc406Sopenharmony_ci        PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Argument string too long in %s\n", devname));
574141cc406Sopenharmony_ci      }
575141cc406Sopenharmony_ci    strcpy (args, start);
576141cc406Sopenharmony_ci    }
577141cc406Sopenharmony_ci  else
578141cc406Sopenharmony_ci    strcpy (args, "");
579141cc406Sopenharmony_ci  return 0;
580141cc406Sopenharmony_ci}
581141cc406Sopenharmony_ci
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci
584141cc406Sopenharmony_cistatic void
585141cc406Sopenharmony_ciset_cmd_from_string (char* protocol_string, struct BJNP_command *cmd, char cmd_code, int payload_len)
586141cc406Sopenharmony_ci{
587141cc406Sopenharmony_ci  /*
588141cc406Sopenharmony_ci   * Set command buffer with command code, session_id and length of payload
589141cc406Sopenharmony_ci   * Returns: sequence number of command
590141cc406Sopenharmony_ci   */
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci  memcpy (cmd->BJNP_id, protocol_string, sizeof (cmd->BJNP_id));
593141cc406Sopenharmony_ci  cmd->dev_type = BJNP_CMD_SCAN;
594141cc406Sopenharmony_ci  cmd->cmd_code = cmd_code;
595141cc406Sopenharmony_ci  cmd->unknown1 = htons (0);
596141cc406Sopenharmony_ci
597141cc406Sopenharmony_ci  /* device not yet opened, use 0 for serial and session) */
598141cc406Sopenharmony_ci  cmd->seq_no = htons (0);
599141cc406Sopenharmony_ci  cmd->session_id = htons (0);
600141cc406Sopenharmony_ci  cmd->payload_len = htonl (payload_len);
601141cc406Sopenharmony_ci}
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_cistatic void
604141cc406Sopenharmony_ciset_cmd_for_dev (int devno, struct BJNP_command *cmd, char cmd_code, int payload_len)
605141cc406Sopenharmony_ci{
606141cc406Sopenharmony_ci  /*
607141cc406Sopenharmony_ci   * Set command buffer with command code, session_id and length of payload
608141cc406Sopenharmony_ci   * Returns: sequence number of command
609141cc406Sopenharmony_ci   */
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci  memcpy(cmd->BJNP_id, device[devno].protocol_string, sizeof (cmd->BJNP_id));
612141cc406Sopenharmony_ci  cmd->dev_type = BJNP_CMD_SCAN;
613141cc406Sopenharmony_ci  cmd->cmd_code = cmd_code;
614141cc406Sopenharmony_ci  cmd->unknown1 = htons (0);
615141cc406Sopenharmony_ci  cmd->seq_no = htons (++(device[devno].serial));
616141cc406Sopenharmony_ci  cmd->session_id = (cmd_code == CMD_UDP_POLL ) ? 0 : htons (device[devno].session_id);
617141cc406Sopenharmony_ci  device[devno].last_cmd = cmd_code;
618141cc406Sopenharmony_ci  cmd->payload_len = htonl (payload_len);
619141cc406Sopenharmony_ci}
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_cistatic int
622141cc406Sopenharmony_cibjnp_setup_udp_socket ( const int dev_no )
623141cc406Sopenharmony_ci{
624141cc406Sopenharmony_ci  /*
625141cc406Sopenharmony_ci   * Setup a udp socket for the given device
626141cc406Sopenharmony_ci   * Returns the socket or -1 in case of error
627141cc406Sopenharmony_ci   */
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci  int sockfd;
630141cc406Sopenharmony_ci  char addr_string[256];
631141cc406Sopenharmony_ci  int port;
632141cc406Sopenharmony_ci  bjnp_sockaddr_t * addr = device[dev_no].addr;
633141cc406Sopenharmony_ci
634141cc406Sopenharmony_ci  get_address_info( addr, addr_string, &port);
635141cc406Sopenharmony_ci
636141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG, "setup_udp_socket: Setting up a UDP socket, dest: %s  port %d\n",
637141cc406Sopenharmony_ci		   addr_string, port ) );
638141cc406Sopenharmony_ci
639141cc406Sopenharmony_ci  if ((sockfd = socket (get_protocol_family( addr ), SOCK_DGRAM, IPPROTO_UDP)) == -1)
640141cc406Sopenharmony_ci    {
641141cc406Sopenharmony_ci      PDBG (bjnp_dbg
642141cc406Sopenharmony_ci	    (LOG_CRIT, "setup_udp_socket: ERROR - can not open socket - %s\n",
643141cc406Sopenharmony_ci	     strerror (errno)));
644141cc406Sopenharmony_ci      return -1;
645141cc406Sopenharmony_ci    }
646141cc406Sopenharmony_ci
647141cc406Sopenharmony_ci  if (connect
648141cc406Sopenharmony_ci      (sockfd, &(device[dev_no].addr->addr), sa_size(device[dev_no].addr) )!= 0)
649141cc406Sopenharmony_ci    {
650141cc406Sopenharmony_ci      PDBG (bjnp_dbg
651141cc406Sopenharmony_ci	    (LOG_CRIT, "setup_udp_socket: ERROR - connect failed- %s\n",
652141cc406Sopenharmony_ci	     strerror (errno)));
653141cc406Sopenharmony_ci      close(sockfd);
654141cc406Sopenharmony_ci      return -1;
655141cc406Sopenharmony_ci    }
656141cc406Sopenharmony_ci  return sockfd;
657141cc406Sopenharmony_ci}
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_cistatic int
660141cc406Sopenharmony_ciudp_command (const int dev_no, char *command, int cmd_len, char *response,
661141cc406Sopenharmony_ci	     int resp_len)
662141cc406Sopenharmony_ci{
663141cc406Sopenharmony_ci  /*
664141cc406Sopenharmony_ci   * send udp command to given device and receive the response`
665141cc406Sopenharmony_ci   * returns: the length of the response or -1
666141cc406Sopenharmony_ci   */
667141cc406Sopenharmony_ci  int sockfd;
668141cc406Sopenharmony_ci  struct timeval timeout;
669141cc406Sopenharmony_ci  int result;
670141cc406Sopenharmony_ci  int try, attempt;
671141cc406Sopenharmony_ci  int numbytes;
672141cc406Sopenharmony_ci  fd_set fdset;
673141cc406Sopenharmony_ci  struct BJNP_command *resp = (struct BJNP_command *) response;
674141cc406Sopenharmony_ci  struct BJNP_command *cmd = (struct BJNP_command *) command;
675141cc406Sopenharmony_ci
676141cc406Sopenharmony_ci  if ( (sockfd = bjnp_setup_udp_socket(dev_no) ) == -1 )
677141cc406Sopenharmony_ci    {
678141cc406Sopenharmony_ci      PDBG (bjnp_dbg( LOG_CRIT, "udp_command: ERROR - Can not setup socket\n") );
679141cc406Sopenharmony_ci      return -1;
680141cc406Sopenharmony_ci    }
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci  for (try = 0; try < BJNP_UDP_RETRY_MAX; try++)
683141cc406Sopenharmony_ci    {
684141cc406Sopenharmony_ci      if ((numbytes = send (sockfd, command, cmd_len, 0)) != cmd_len)
685141cc406Sopenharmony_ci	{
686141cc406Sopenharmony_ci	  PDBG (bjnp_dbg
687141cc406Sopenharmony_ci		(LOG_NOTICE, "udp_command: ERROR - Sent %d bytes, expected %d\n",
688141cc406Sopenharmony_ci		 numbytes, cmd_len));
689141cc406Sopenharmony_ci	  continue;
690141cc406Sopenharmony_ci	}
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci      attempt = 0;
693141cc406Sopenharmony_ci
694141cc406Sopenharmony_ci      /* wait for data to be received, ignore signals being received */
695141cc406Sopenharmony_ci      /* skip late udp responses (they have an incorrect sequence number */
696141cc406Sopenharmony_ci      do
697141cc406Sopenharmony_ci	{
698141cc406Sopenharmony_ci	  FD_ZERO (&fdset);
699141cc406Sopenharmony_ci	  FD_SET (sockfd, &fdset);
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci	  timeout.tv_sec = device[dev_no].bjnp_ip_timeout /1000;
702141cc406Sopenharmony_ci	  timeout.tv_usec = device[dev_no].bjnp_ip_timeout %1000;
703141cc406Sopenharmony_ci	}
704141cc406Sopenharmony_ci      while (((result =
705141cc406Sopenharmony_ci	       select (sockfd + 1, &fdset, NULL, NULL, &timeout)) <= 0)
706141cc406Sopenharmony_ci	     && (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS)
707141cc406Sopenharmony_ci             && resp-> seq_no != cmd->seq_no);
708141cc406Sopenharmony_ci
709141cc406Sopenharmony_ci      if (result <= 0)
710141cc406Sopenharmony_ci	{
711141cc406Sopenharmony_ci	  PDBG (bjnp_dbg
712141cc406Sopenharmony_ci		(LOG_NOTICE, "udp_command: ERROR - select failed: %s\n",
713141cc406Sopenharmony_ci		 result == 0 ? "timed out" : strerror (errno)));
714141cc406Sopenharmony_ci	  continue;
715141cc406Sopenharmony_ci	}
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci      if ((numbytes = recv (sockfd, response, resp_len, 0)) == -1)
718141cc406Sopenharmony_ci	{
719141cc406Sopenharmony_ci	  PDBG (bjnp_dbg
720141cc406Sopenharmony_ci		(LOG_NOTICE, "udp_command: ERROR - recv failed: %s",
721141cc406Sopenharmony_ci		 strerror (errno)));
722141cc406Sopenharmony_ci	  continue;
723141cc406Sopenharmony_ci	}
724141cc406Sopenharmony_ci      close(sockfd);
725141cc406Sopenharmony_ci      return numbytes;
726141cc406Sopenharmony_ci    }
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci  /* no response even after retry */
729141cc406Sopenharmony_ci
730141cc406Sopenharmony_ci  close(sockfd);
731141cc406Sopenharmony_ci  PDBG (bjnp_dbg
732141cc406Sopenharmony_ci        (LOG_CRIT, "udp_command: ERROR - no data received (timeout = %d)\n", device[dev_no].bjnp_ip_timeout ) );
733141cc406Sopenharmony_ci  return -1;
734141cc406Sopenharmony_ci}
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_cistatic int
737141cc406Sopenharmony_ciget_scanner_id (const int dev_no, char *model)
738141cc406Sopenharmony_ci{
739141cc406Sopenharmony_ci  /*
740141cc406Sopenharmony_ci   * get scanner identity
741141cc406Sopenharmony_ci   * Sets model (make and model)
742141cc406Sopenharmony_ci   * Return 0 on success, -1 in case of errors
743141cc406Sopenharmony_ci   */
744141cc406Sopenharmony_ci
745141cc406Sopenharmony_ci  struct BJNP_command cmd;
746141cc406Sopenharmony_ci  struct IDENTITY *id;
747141cc406Sopenharmony_ci  char scanner_id[BJNP_IEEE1284_MAX];
748141cc406Sopenharmony_ci  int resp_len;
749141cc406Sopenharmony_ci  char resp_buf[BJNP_RESP_MAX];
750141cc406Sopenharmony_ci  int id_len;
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_ci  /* set defaults */
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci  strcpy (model, "Unidentified scanner");
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci  set_cmd_for_dev (dev_no, &cmd, CMD_UDP_GET_ID, 0);
757141cc406Sopenharmony_ci
758141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG2, "get_scanner_id: Get scanner identity\n"));
759141cc406Sopenharmony_ci  PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &cmd,
760141cc406Sopenharmony_ci		       sizeof (struct BJNP_command)));
761141cc406Sopenharmony_ci
762141cc406Sopenharmony_ci  if ( ( resp_len =  udp_command (dev_no, (char *) &cmd, sizeof (struct BJNP_command),
763141cc406Sopenharmony_ci		 resp_buf, BJNP_RESP_MAX) ) < (int)sizeof(struct BJNP_command) )
764141cc406Sopenharmony_ci    {
765141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG, "get_scanner_id: ERROR - Failed to retrieve scanner identity:\n"));
766141cc406Sopenharmony_ci      return -1;
767141cc406Sopenharmony_ci    }
768141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG2, "get_scanner_id: scanner identity:\n"));
769141cc406Sopenharmony_ci  PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len));
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci  id = (struct IDENTITY *) resp_buf;
772141cc406Sopenharmony_ci
773141cc406Sopenharmony_ci  if (device[dev_no].protocol == PROTOCOL_BJNP)
774141cc406Sopenharmony_ci    {
775141cc406Sopenharmony_ci      id_len = MIN(ntohl( id-> cmd.payload_len ) - sizeof(id-> payload.bjnp.id_len), BJNP_IEEE1284_MAX);
776141cc406Sopenharmony_ci      strncpy(scanner_id, id->payload.bjnp.id, id_len);
777141cc406Sopenharmony_ci      scanner_id[id_len] = '\0';
778141cc406Sopenharmony_ci    }
779141cc406Sopenharmony_ci  else
780141cc406Sopenharmony_ci    {
781141cc406Sopenharmony_ci      id_len = MIN(ntohl( id-> cmd.payload_len ), BJNP_IEEE1284_MAX);
782141cc406Sopenharmony_ci      strncpy(scanner_id, id->payload.mfnp.id, id_len);
783141cc406Sopenharmony_ci      scanner_id[id_len] = '\0';
784141cc406Sopenharmony_ci    }
785141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "get_scanner_id: Scanner identity string = %s - length = %d\n", scanner_id, id_len));
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci  /* get make&model from IEEE1284 id  */
788141cc406Sopenharmony_ci
789141cc406Sopenharmony_ci  if (model != NULL)
790141cc406Sopenharmony_ci  {
791141cc406Sopenharmony_ci    parse_IEEE1284_to_model (scanner_id, model);
792141cc406Sopenharmony_ci    PDBG (bjnp_dbg (LOG_INFO, "get_scanner_id: Scanner model = %s\n", model));
793141cc406Sopenharmony_ci  }
794141cc406Sopenharmony_ci  return 0;
795141cc406Sopenharmony_ci}
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_cistatic int
798141cc406Sopenharmony_ciget_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host)
799141cc406Sopenharmony_ci{
800141cc406Sopenharmony_ci  /*
801141cc406Sopenharmony_ci   * Parse identify command responses to ip-address
802141cc406Sopenharmony_ci   * and hostname. Return qulity of the address
803141cc406Sopenharmony_ci   */
804141cc406Sopenharmony_ci
805141cc406Sopenharmony_ci  struct addrinfo *results;
806141cc406Sopenharmony_ci  struct addrinfo *result;
807141cc406Sopenharmony_ci  char ip_address[BJNP_HOST_MAX];
808141cc406Sopenharmony_ci  int port;
809141cc406Sopenharmony_ci  int error;
810141cc406Sopenharmony_ci  int match = 0;
811141cc406Sopenharmony_ci  int level;
812141cc406Sopenharmony_ci  char service[64];
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
815141cc406Sopenharmony_ci  if ( ( scanner_sa -> addr.sa_family == AF_INET6 ) &&
816141cc406Sopenharmony_ci       ( IN6_IS_ADDR_LINKLOCAL( &(scanner_sa -> ipv6.sin6_addr ) ) ) )
817141cc406Sopenharmony_ci    level = BJNP_ADDRESS_IS_LINK_LOCAL;
818141cc406Sopenharmony_ci  else
819141cc406Sopenharmony_ci#endif
820141cc406Sopenharmony_ci    level = BJNP_ADDRESS_IS_GLOBAL;
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci  get_address_info( scanner_sa, ip_address, &port );
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci  /* do reverse name lookup, if hostname can not be found return ip-address */
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_ci  if( (error = getnameinfo( &(scanner_sa -> addr) , sa_size( scanner_sa),
827141cc406Sopenharmony_ci                  host, BJNP_HOST_MAX , NULL, 0, NI_NAMEREQD) ) != 0 )
828141cc406Sopenharmony_ci    {
829141cc406Sopenharmony_ci      PDBG (bjnp_dbg(LOG_INFO, "get_scanner_name: Name for %s not found : %s\n",
830141cc406Sopenharmony_ci                      ip_address, gai_strerror(error) ) );
831141cc406Sopenharmony_ci      strcpy(host, ip_address);
832141cc406Sopenharmony_ci      return level;
833141cc406Sopenharmony_ci    }
834141cc406Sopenharmony_ci  else
835141cc406Sopenharmony_ci    {
836141cc406Sopenharmony_ci      sprintf(service, "%d", port);
837141cc406Sopenharmony_ci      /* some buggy routers return rubbish if reverse lookup fails, so
838141cc406Sopenharmony_ci       * we do a forward lookup on the received name to see if the result matches */
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci      if (getaddrinfo(host , service, NULL, &results) == 0)
841141cc406Sopenharmony_ci        {
842141cc406Sopenharmony_ci          result = results;
843141cc406Sopenharmony_ci
844141cc406Sopenharmony_ci          while (result != NULL)
845141cc406Sopenharmony_ci            {
846141cc406Sopenharmony_ci               if(sa_is_equal( scanner_sa, (bjnp_sockaddr_t *)result-> ai_addr))
847141cc406Sopenharmony_ci                 {
848141cc406Sopenharmony_ci                     /* found match, good */
849141cc406Sopenharmony_ci                     PDBG (bjnp_dbg (LOG_INFO,
850141cc406Sopenharmony_ci                              "get_scanner_name: Forward lookup for %s succeeded, using as hostname\n", host));
851141cc406Sopenharmony_ci                    match = 1;
852141cc406Sopenharmony_ci                    level = BJNP_ADDRESS_HAS_FQDN;
853141cc406Sopenharmony_ci                    break;
854141cc406Sopenharmony_ci                 }
855141cc406Sopenharmony_ci              result = result-> ai_next;
856141cc406Sopenharmony_ci            }
857141cc406Sopenharmony_ci          freeaddrinfo(results);
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ci          if (match != 1)
860141cc406Sopenharmony_ci            {
861141cc406Sopenharmony_ci              PDBG (bjnp_dbg (LOG_INFO,
862141cc406Sopenharmony_ci                 "get_scanner_name: Forward lookup for %s succeeded, IP-address does not match, using IP-address %s instead\n",
863141cc406Sopenharmony_ci                 host, ip_address));
864141cc406Sopenharmony_ci              strcpy (host, ip_address);
865141cc406Sopenharmony_ci            }
866141cc406Sopenharmony_ci         }
867141cc406Sopenharmony_ci       else
868141cc406Sopenharmony_ci         {
869141cc406Sopenharmony_ci           /* forward lookup failed, use ip-address */
870141cc406Sopenharmony_ci           PDBG ( bjnp_dbg (LOG_INFO, "get_scanner_name: Forward lookup of %s failed, using IP-address", ip_address));
871141cc406Sopenharmony_ci           strcpy (host, ip_address);
872141cc406Sopenharmony_ci         }
873141cc406Sopenharmony_ci    }
874141cc406Sopenharmony_ci  return level;
875141cc406Sopenharmony_ci}
876141cc406Sopenharmony_ci
877141cc406Sopenharmony_cistatic int
878141cc406Sopenharmony_ciget_port_from_sa(const bjnp_sockaddr_t scanner_sa)
879141cc406Sopenharmony_ci{
880141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
881141cc406Sopenharmony_ci  if ( scanner_sa.addr.sa_family == AF_INET6 )
882141cc406Sopenharmony_ci    {
883141cc406Sopenharmony_ci      return ntohs(scanner_sa.ipv6.sin6_port);
884141cc406Sopenharmony_ci    }
885141cc406Sopenharmony_ci  else
886141cc406Sopenharmony_ci#endif
887141cc406Sopenharmony_ci  if ( scanner_sa.addr.sa_family == AF_INET )
888141cc406Sopenharmony_ci    {
889141cc406Sopenharmony_ci      return ntohs(scanner_sa.ipv4.sin_port);
890141cc406Sopenharmony_ci    }
891141cc406Sopenharmony_ci  return -1;
892141cc406Sopenharmony_ci}
893141cc406Sopenharmony_ci
894141cc406Sopenharmony_cistatic int create_broadcast_socket( const bjnp_sockaddr_t * local_addr )
895141cc406Sopenharmony_ci{
896141cc406Sopenharmony_ci  int sockfd = -1;
897141cc406Sopenharmony_ci  int broadcast = 1;
898141cc406Sopenharmony_ci  int ipv6_v6only = 1;
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci
901141cc406Sopenharmony_ci if ((sockfd = socket (local_addr-> addr.sa_family, SOCK_DGRAM, 0)) == -1)
902141cc406Sopenharmony_ci    {
903141cc406Sopenharmony_ci      PDBG (bjnp_dbg
904141cc406Sopenharmony_ci            (LOG_CRIT, "create_broadcast_socket: ERROR - can not open socket - %s",
905141cc406Sopenharmony_ci             strerror (errno)));
906141cc406Sopenharmony_ci      return -1;
907141cc406Sopenharmony_ci    }
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci  /* Set broadcast flag on socket */
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci  if (setsockopt
912141cc406Sopenharmony_ci      (sockfd, SOL_SOCKET, SO_BROADCAST, (const char *) &broadcast,
913141cc406Sopenharmony_ci       sizeof (broadcast)) != 0)
914141cc406Sopenharmony_ci    {
915141cc406Sopenharmony_ci      PDBG (bjnp_dbg
916141cc406Sopenharmony_ci            (LOG_CRIT,
917141cc406Sopenharmony_ci             "create_broadcast_socket: ERROR - setting socket option SO_BROADCAST failed - %s",
918141cc406Sopenharmony_ci             strerror (errno)));
919141cc406Sopenharmony_ci      close (sockfd);
920141cc406Sopenharmony_ci      return -1;
921141cc406Sopenharmony_ci    };
922141cc406Sopenharmony_ci
923141cc406Sopenharmony_ci  /* For an IPv6 socket, bind to v6 only so a V6 socket can co-exist with a v4 socket */
924141cc406Sopenharmony_ci  if ( (local_addr -> addr.sa_family == AF_INET6) && ( setsockopt
925141cc406Sopenharmony_ci      (sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &ipv6_v6only,
926141cc406Sopenharmony_ci       sizeof (ipv6_v6only)) != 0) )
927141cc406Sopenharmony_ci    {
928141cc406Sopenharmony_ci      PDBG (bjnp_dbg
929141cc406Sopenharmony_ci            (LOG_CRIT,
930141cc406Sopenharmony_ci             "create_broadcast_socket: ERROR - setting socket option IPV6_V6ONLY failed - %s",
931141cc406Sopenharmony_ci             strerror (errno)));
932141cc406Sopenharmony_ci      close (sockfd);
933141cc406Sopenharmony_ci      return -1;
934141cc406Sopenharmony_ci    };
935141cc406Sopenharmony_ci
936141cc406Sopenharmony_ci  if (bind
937141cc406Sopenharmony_ci      (sockfd, &(local_addr->addr),
938141cc406Sopenharmony_ci       (socklen_t) sa_size( local_addr)) != 0)
939141cc406Sopenharmony_ci    {
940141cc406Sopenharmony_ci      PDBG (bjnp_dbg
941141cc406Sopenharmony_ci            (LOG_CRIT,
942141cc406Sopenharmony_ci             "create_broadcast_socket: ERROR - bind socket to local address failed - %s\n",
943141cc406Sopenharmony_ci             strerror (errno)));
944141cc406Sopenharmony_ci      close (sockfd);
945141cc406Sopenharmony_ci      return -1;
946141cc406Sopenharmony_ci    }
947141cc406Sopenharmony_ci  return sockfd;
948141cc406Sopenharmony_ci}
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_cistatic int
951141cc406Sopenharmony_ciprepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa,
952141cc406Sopenharmony_ci               const bjnp_sockaddr_t *broadcast_sa, bjnp_sockaddr_t * dest_sa)
953141cc406Sopenharmony_ci{
954141cc406Sopenharmony_ci  /*
955141cc406Sopenharmony_ci   * Prepare a socket for broadcast or multicast
956141cc406Sopenharmony_ci   * Input:
957141cc406Sopenharmony_ci   * if_name: the name of the interface
958141cc406Sopenharmony_ci   * local_sa: local address to use
959141cc406Sopenharmony_ci   * broadcast_sa: broadcast address to use, if NULL we use all hosts
960141cc406Sopenharmony_ci   * dest_sa: (write) where to return destination address of broadcast
961141cc406Sopenharmony_ci   * returns: open socket or -1
962141cc406Sopenharmony_ci   */
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci  int socket = -1;
965141cc406Sopenharmony_ci  bjnp_sockaddr_t local_sa_copy;
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci  if ( local_sa == NULL )
968141cc406Sopenharmony_ci    {
969141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG,
970141cc406Sopenharmony_ci                       "prepare_socket: %s is not a valid IPv4 interface, skipping...\n",
971141cc406Sopenharmony_ci                       if_name));
972141cc406Sopenharmony_ci      return -1;
973141cc406Sopenharmony_ci    }
974141cc406Sopenharmony_ci
975141cc406Sopenharmony_ci  memset( &local_sa_copy, 0, sizeof(local_sa_copy) );
976141cc406Sopenharmony_ci  memcpy( &local_sa_copy, local_sa, sa_size(local_sa) );
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci  switch( local_sa_copy.addr.sa_family )
979141cc406Sopenharmony_ci    {
980141cc406Sopenharmony_ci      case AF_INET:
981141cc406Sopenharmony_ci        {
982141cc406Sopenharmony_ci          local_sa_copy.ipv4.sin_port = htons(BJNP_PORT_SCAN);
983141cc406Sopenharmony_ci
984141cc406Sopenharmony_ci          if (local_sa_copy.ipv4.sin_addr.s_addr == htonl (INADDR_LOOPBACK) )
985141cc406Sopenharmony_ci            {
986141cc406Sopenharmony_ci              /* not a valid interface */
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci              PDBG (bjnp_dbg (LOG_DEBUG,
989141cc406Sopenharmony_ci                               "prepare_socket: %s is not a valid IPv4 interface, skipping...\n",
990141cc406Sopenharmony_ci	                       if_name));
991141cc406Sopenharmony_ci              return -1;
992141cc406Sopenharmony_ci            }
993141cc406Sopenharmony_ci
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_ci          /* send broadcasts to the broadcast address of the interface */
996141cc406Sopenharmony_ci
997141cc406Sopenharmony_ci          memcpy(dest_sa, broadcast_sa, sa_size(broadcast_sa) );
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ci	  /* we fill port when we send the broadcast */
1000141cc406Sopenharmony_ci          dest_sa -> ipv4.sin_port = htons(0);
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci          if ( (socket = create_broadcast_socket( &local_sa_copy) ) != -1)
1003141cc406Sopenharmony_ci            {
1004141cc406Sopenharmony_ci               PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv4 capable, sending broadcast, socket = %d\n",
1005141cc406Sopenharmony_ci                      if_name, socket));
1006141cc406Sopenharmony_ci            }
1007141cc406Sopenharmony_ci          else
1008141cc406Sopenharmony_ci            {
1009141cc406Sopenharmony_ci              PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: ERROR - %s is IPv4 capable, but failed to create a socket.\n",
1010141cc406Sopenharmony_ci                    if_name));
1011141cc406Sopenharmony_ci              return -1;
1012141cc406Sopenharmony_ci            }
1013141cc406Sopenharmony_ci        }
1014141cc406Sopenharmony_ci        break;
1015141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
1016141cc406Sopenharmony_ci      case AF_INET6:
1017141cc406Sopenharmony_ci        {
1018141cc406Sopenharmony_ci          local_sa_copy.ipv6.sin6_port = htons(BJNP_PORT_SCAN);
1019141cc406Sopenharmony_ci
1020141cc406Sopenharmony_ci          if (IN6_IS_ADDR_LOOPBACK( &(local_sa_copy.ipv6.sin6_addr) ) )
1021141cc406Sopenharmony_ci            {
1022141cc406Sopenharmony_ci              /* not a valid interface */
1023141cc406Sopenharmony_ci
1024141cc406Sopenharmony_ci              PDBG (bjnp_dbg (LOG_DEBUG,
1025141cc406Sopenharmony_ci                               "prepare_socket: %s is not a valid IPv6 interface, skipping...\n",
1026141cc406Sopenharmony_ci	                       if_name));
1027141cc406Sopenharmony_ci              return -1;
1028141cc406Sopenharmony_ci            }
1029141cc406Sopenharmony_ci          else
1030141cc406Sopenharmony_ci            {
1031141cc406Sopenharmony_ci              dest_sa -> ipv6.sin6_family = AF_INET6;
1032141cc406Sopenharmony_ci
1033141cc406Sopenharmony_ci              /* We fill port when we send the broadcast */
1034141cc406Sopenharmony_ci              dest_sa -> ipv6.sin6_port = htons(0);
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci              inet_pton(AF_INET6, "ff02::1", dest_sa -> ipv6.sin6_addr.s6_addr);
1037141cc406Sopenharmony_ci              if ( (socket = create_broadcast_socket( &local_sa_copy ) ) != -1)
1038141cc406Sopenharmony_ci                {
1039141cc406Sopenharmony_ci                   PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv6 capable, sending broadcast, socket = %d\n",
1040141cc406Sopenharmony_ci                          if_name, socket));
1041141cc406Sopenharmony_ci                }
1042141cc406Sopenharmony_ci              else
1043141cc406Sopenharmony_ci                {
1044141cc406Sopenharmony_ci                  PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: ERROR - %s is IPv6 capable, but failed to create a socket.\n",
1045141cc406Sopenharmony_ci                        if_name));
1046141cc406Sopenharmony_ci                  return -1;
1047141cc406Sopenharmony_ci                }
1048141cc406Sopenharmony_ci            }
1049141cc406Sopenharmony_ci          }
1050141cc406Sopenharmony_ci          break;
1051141cc406Sopenharmony_ci#endif
1052141cc406Sopenharmony_ci
1053141cc406Sopenharmony_ci      default:
1054141cc406Sopenharmony_ci        socket = -1;
1055141cc406Sopenharmony_ci    }
1056141cc406Sopenharmony_ci  return socket;
1057141cc406Sopenharmony_ci}
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_cistatic int
1060141cc406Sopenharmony_cibjnp_send_broadcast (int sockfd, const bjnp_sockaddr_t * broadcast_addr, int port,
1061141cc406Sopenharmony_ci                     struct BJNP_command cmd, int size)
1062141cc406Sopenharmony_ci{
1063141cc406Sopenharmony_ci  int num_bytes;
1064141cc406Sopenharmony_ci  bjnp_sockaddr_t dest_addr;
1065141cc406Sopenharmony_ci
1066141cc406Sopenharmony_ci  /* set address to send packet to broadcast address of interface, */
1067141cc406Sopenharmony_ci  /* with port set to the destination port */
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci  memcpy(&dest_addr,  broadcast_addr, sizeof(dest_addr));
1070141cc406Sopenharmony_ci  if( dest_addr.addr.sa_family == AF_INET)
1071141cc406Sopenharmony_ci    {
1072141cc406Sopenharmony_ci      dest_addr.ipv4.sin_port = htons(port);
1073141cc406Sopenharmony_ci    }
1074141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
1075141cc406Sopenharmony_ci  if( dest_addr.addr.sa_family == AF_INET6)
1076141cc406Sopenharmony_ci    {
1077141cc406Sopenharmony_ci      dest_addr.ipv6.sin6_port = htons(port);
1078141cc406Sopenharmony_ci    }
1079141cc406Sopenharmony_ci#endif
1080141cc406Sopenharmony_ci
1081141cc406Sopenharmony_ci  if ((num_bytes = sendto (sockfd, &cmd, size, 0,
1082141cc406Sopenharmony_ci			  &(dest_addr.addr),
1083141cc406Sopenharmony_ci			  sa_size( broadcast_addr)) ) != size)
1084141cc406Sopenharmony_ci    {
1085141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_INFO,
1086141cc406Sopenharmony_ci		       "bjnp_send_broadcast: Socket: %d: ERROR - sent only %x = %d bytes of packet, error = %s\n",
1087141cc406Sopenharmony_ci		       sockfd, num_bytes, num_bytes, strerror (errno)));
1088141cc406Sopenharmony_ci      /* not allowed, skip this interface */
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci      return -1;
1091141cc406Sopenharmony_ci    }
1092141cc406Sopenharmony_ci  return sockfd;
1093141cc406Sopenharmony_ci}
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_cistatic void
1096141cc406Sopenharmony_cibjnp_finish_job (int devno)
1097141cc406Sopenharmony_ci{
1098141cc406Sopenharmony_ci/*
1099141cc406Sopenharmony_ci * Signal end of scanjob to scanner
1100141cc406Sopenharmony_ci */
1101141cc406Sopenharmony_ci
1102141cc406Sopenharmony_ci  char resp_buf[BJNP_RESP_MAX];
1103141cc406Sopenharmony_ci  int resp_len;
1104141cc406Sopenharmony_ci  struct BJNP_command cmd;
1105141cc406Sopenharmony_ci
1106141cc406Sopenharmony_ci  set_cmd_for_dev (devno, &cmd, CMD_UDP_CLOSE, 0);
1107141cc406Sopenharmony_ci
1108141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_finish_job: Finish scanjob\n"));
1109141cc406Sopenharmony_ci  PDBG (bjnp_hexdump
1110141cc406Sopenharmony_ci	(LOG_DEBUG2, (char *) &cmd, sizeof (struct BJNP_command)));
1111141cc406Sopenharmony_ci  resp_len =
1112141cc406Sopenharmony_ci    udp_command (devno, (char *) &cmd, sizeof (struct BJNP_command), resp_buf,
1113141cc406Sopenharmony_ci		 BJNP_RESP_MAX);
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci  if (resp_len != sizeof (struct BJNP_command))
1116141cc406Sopenharmony_ci    {
1117141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1118141cc406Sopenharmony_ci	    (LOG_INFO,
1119141cc406Sopenharmony_ci	     "bjnp_finish_job: ERROR - Received %d characters on close scanjob command, expected %d\n",
1120141cc406Sopenharmony_ci	     resp_len, (int) sizeof (struct BJNP_command)));
1121141cc406Sopenharmony_ci      return;
1122141cc406Sopenharmony_ci    }
1123141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_finish_job: Finish scanjob response\n"));
1124141cc406Sopenharmony_ci  PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len));
1125141cc406Sopenharmony_ci
1126141cc406Sopenharmony_ci}
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci#ifdef PIXMA_BJNP_USE_STATUS
1129141cc406Sopenharmony_cistatic int
1130141cc406Sopenharmony_cibjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *status, int size)
1131141cc406Sopenharmony_ci{
1132141cc406Sopenharmony_ci/*
1133141cc406Sopenharmony_ci * send details of user to the scanner
1134141cc406Sopenharmony_ci */
1135141cc406Sopenharmony_ci
1136141cc406Sopenharmony_ci  char cmd_buf[BJNP_CMD_MAX];
1137141cc406Sopenharmony_ci  char resp_buf[BJNP_RESP_MAX];
1138141cc406Sopenharmony_ci  int resp_len;
1139141cc406Sopenharmony_ci  int len = 0;			/* payload length */
1140141cc406Sopenharmony_ci  int buf_len;			/* length of the whole command  buffer */
1141141cc406Sopenharmony_ci  struct POLL_DETAILS *poll;
1142141cc406Sopenharmony_ci  struct POLL_RESPONSE *response;
1143141cc406Sopenharmony_ci  char user_host[256];
1144141cc406Sopenharmony_ci  time_t t;
1145141cc406Sopenharmony_ci  int user_host_len;
1146141cc406Sopenharmony_ci
1147141cc406Sopenharmony_ci  poll = (struct POLL_DETAILS *) cmd_buf;
1148141cc406Sopenharmony_ci  memset( poll, 0, sizeof( struct POLL_DETAILS));
1149141cc406Sopenharmony_ci  memset( &resp_buf, 0, sizeof( resp_buf) );
1150141cc406Sopenharmony_ci
1151141cc406Sopenharmony_ci
1152141cc406Sopenharmony_ci  /* create payload */
1153141cc406Sopenharmony_ci  poll->type = htons(type);
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci  user_host_len =  sizeof( poll -> extensions.type2.user_host);
1156141cc406Sopenharmony_ci  snprintf(user_host, (user_host_len /2) ,"%s  %s", user, hostname);
1157141cc406Sopenharmony_ci  user_host[ user_host_len /2 + 1] = '\0';
1158141cc406Sopenharmony_ci
1159141cc406Sopenharmony_ci  switch( type) {
1160141cc406Sopenharmony_ci    case 0:
1161141cc406Sopenharmony_ci      len = 80;
1162141cc406Sopenharmony_ci      break;
1163141cc406Sopenharmony_ci    case 1:
1164141cc406Sopenharmony_ci      charTo2byte(poll->extensions.type1.user_host, user_host, user_host_len);
1165141cc406Sopenharmony_ci      len = 80;
1166141cc406Sopenharmony_ci      break;
1167141cc406Sopenharmony_ci    case 2:
1168141cc406Sopenharmony_ci      poll->extensions.type2.dialog = htonl(device[devno].dialog);
1169141cc406Sopenharmony_ci      charTo2byte(poll->extensions.type2.user_host, user_host, user_host_len);
1170141cc406Sopenharmony_ci      poll->extensions.type2.unknown_1 = htonl(0x14);
1171141cc406Sopenharmony_ci      poll->extensions.type2.unknown_2 = htonl(0x10);
1172141cc406Sopenharmony_ci      t = time (NULL);
1173141cc406Sopenharmony_ci      strftime (poll->extensions.type2.ascii_date,
1174141cc406Sopenharmony_ci                sizeof (poll->extensions.type2.ascii_date),
1175141cc406Sopenharmony_ci               "%Y%m%d%H%M%S", localtime (&t));
1176141cc406Sopenharmony_ci      len = 116;
1177141cc406Sopenharmony_ci      break;
1178141cc406Sopenharmony_ci    case 5:
1179141cc406Sopenharmony_ci      poll->extensions.type5.dialog = htonl(device[devno].dialog);
1180141cc406Sopenharmony_ci      charTo2byte(poll->extensions.type5.user_host, user_host, user_host_len);
1181141cc406Sopenharmony_ci      poll->extensions.type5.unknown_1 = htonl(0x14);
1182141cc406Sopenharmony_ci      poll->extensions.type5.key = htonl(device[devno].status_key);
1183141cc406Sopenharmony_ci      len = 100;
1184141cc406Sopenharmony_ci      break;
1185141cc406Sopenharmony_ci    default:
1186141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_INFO, "bjnp_poll_scanner: unknown packet type: %d\n", type));
1187141cc406Sopenharmony_ci      return -1;
1188141cc406Sopenharmony_ci  };
1189141cc406Sopenharmony_ci  /* we can only now set the header as we now know the length of the payload */
1190141cc406Sopenharmony_ci  set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_POLL,
1191141cc406Sopenharmony_ci	   len);
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci  buf_len = len + sizeof(struct BJNP_command);
1194141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_poll_scanner: Poll details (type %d)\n", type));
1195141cc406Sopenharmony_ci  PDBG (bjnp_hexdump (LOG_DEBUG2, cmd_buf,
1196141cc406Sopenharmony_ci		       buf_len));
1197141cc406Sopenharmony_ci
1198141cc406Sopenharmony_ci  resp_len = udp_command (devno, cmd_buf, buf_len,  resp_buf, BJNP_RESP_MAX);
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ci  if (resp_len > 0)
1201141cc406Sopenharmony_ci    {
1202141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_poll_scanner: Poll details response:\n"));
1203141cc406Sopenharmony_ci      PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len));
1204141cc406Sopenharmony_ci      response = (struct POLL_RESPONSE *) resp_buf;
1205141cc406Sopenharmony_ci
1206141cc406Sopenharmony_ci      device[devno].dialog = ntohl( response -> dialog );
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_ci      if ( response -> result[3] == 1 )
1209141cc406Sopenharmony_ci        {
1210141cc406Sopenharmony_ci          return BJNP_RESTART_POLL;
1211141cc406Sopenharmony_ci        }
1212141cc406Sopenharmony_ci      if ( (response -> result[2] & 0x80) != 0)
1213141cc406Sopenharmony_ci        {
1214141cc406Sopenharmony_ci          memcpy( status, response->status, size);
1215141cc406Sopenharmony_ci          PDBG( bjnp_dbg(LOG_INFO, "bjnp_poll_scanner: received button status!\n"));
1216141cc406Sopenharmony_ci	  PDBG (bjnp_hexdump( LOG_DEBUG2, status, size ));
1217141cc406Sopenharmony_ci	  device[devno].status_key = ntohl( response -> key );
1218141cc406Sopenharmony_ci          return  size;
1219141cc406Sopenharmony_ci        }
1220141cc406Sopenharmony_ci    }
1221141cc406Sopenharmony_ci  return 0;
1222141cc406Sopenharmony_ci}
1223141cc406Sopenharmony_ci#endif
1224141cc406Sopenharmony_ci
1225141cc406Sopenharmony_cistatic void
1226141cc406Sopenharmony_cibjnp_send_job_details (int devno, char *hostname, char *user, char *title)
1227141cc406Sopenharmony_ci{
1228141cc406Sopenharmony_ci/*
1229141cc406Sopenharmony_ci * send details of scanjob to scanner
1230141cc406Sopenharmony_ci */
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_ci  char cmd_buf[BJNP_CMD_MAX];
1233141cc406Sopenharmony_ci  char resp_buf[BJNP_RESP_MAX];
1234141cc406Sopenharmony_ci  int resp_len;
1235141cc406Sopenharmony_ci  struct JOB_DETAILS *job;
1236141cc406Sopenharmony_ci  struct BJNP_command *resp;
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_ci  /* send job details command */
1239141cc406Sopenharmony_ci
1240141cc406Sopenharmony_ci  set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_JOB_DETAILS,
1241141cc406Sopenharmony_ci	   sizeof (*job) - sizeof (struct BJNP_command));
1242141cc406Sopenharmony_ci
1243141cc406Sopenharmony_ci  /* create payload */
1244141cc406Sopenharmony_ci
1245141cc406Sopenharmony_ci  job = (struct JOB_DETAILS *) (cmd_buf);
1246141cc406Sopenharmony_ci  charTo2byte (job->unknown, "", sizeof (job->unknown));
1247141cc406Sopenharmony_ci  charTo2byte (job->hostname, hostname, sizeof (job->hostname));
1248141cc406Sopenharmony_ci  charTo2byte (job->username, user, sizeof (job->username));
1249141cc406Sopenharmony_ci  charTo2byte (job->jobtitle, title, sizeof (job->jobtitle));
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_send_job_details: Job details\n"));
1252141cc406Sopenharmony_ci  PDBG (bjnp_hexdump (LOG_DEBUG2, cmd_buf,
1253141cc406Sopenharmony_ci		       (sizeof (struct BJNP_command) + sizeof (*job))));
1254141cc406Sopenharmony_ci
1255141cc406Sopenharmony_ci  resp_len = udp_command (devno, cmd_buf,
1256141cc406Sopenharmony_ci			  sizeof (struct JOB_DETAILS), resp_buf,
1257141cc406Sopenharmony_ci			  BJNP_RESP_MAX);
1258141cc406Sopenharmony_ci
1259141cc406Sopenharmony_ci  if (resp_len > 0)
1260141cc406Sopenharmony_ci    {
1261141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_send_job_details: Job details response:\n"));
1262141cc406Sopenharmony_ci      PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len));
1263141cc406Sopenharmony_ci      resp = (struct BJNP_command *) resp_buf;
1264141cc406Sopenharmony_ci      device[devno].session_id = ntohs (resp->session_id);
1265141cc406Sopenharmony_ci    }
1266141cc406Sopenharmony_ci}
1267141cc406Sopenharmony_ci
1268141cc406Sopenharmony_cistatic int
1269141cc406Sopenharmony_cibjnp_get_scanner_mac_address ( int devno, char *mac_address )
1270141cc406Sopenharmony_ci{
1271141cc406Sopenharmony_ci/*
1272141cc406Sopenharmony_ci * send discover to scanner
1273141cc406Sopenharmony_ci */
1274141cc406Sopenharmony_ci
1275141cc406Sopenharmony_ci  char cmd_buf[BJNP_CMD_MAX];
1276141cc406Sopenharmony_ci  char resp_buf[BJNP_RESP_MAX];
1277141cc406Sopenharmony_ci  int resp_len;
1278141cc406Sopenharmony_ci  struct DISCOVER_RESPONSE *resp = (struct DISCOVER_RESPONSE * )&resp_buf;;
1279141cc406Sopenharmony_ci
1280141cc406Sopenharmony_ci  /* send job details command */
1281141cc406Sopenharmony_ci
1282141cc406Sopenharmony_ci  set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_DISCOVER, 0);
1283141cc406Sopenharmony_ci  resp_len = udp_command (devno, cmd_buf,
1284141cc406Sopenharmony_ci			  sizeof (struct BJNP_command), resp_buf,
1285141cc406Sopenharmony_ci			  BJNP_RESP_MAX);
1286141cc406Sopenharmony_ci
1287141cc406Sopenharmony_ci  if (resp_len > 0)
1288141cc406Sopenharmony_ci    {
1289141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_get_scanner_mac_address: Discover response:\n"));
1290141cc406Sopenharmony_ci      PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len));
1291141cc406Sopenharmony_ci      u8tohex( mac_address, resp -> mac_addr, sizeof( resp -> mac_addr ) );
1292141cc406Sopenharmony_ci      return 0;
1293141cc406Sopenharmony_ci    }
1294141cc406Sopenharmony_ci  return -1;
1295141cc406Sopenharmony_ci}
1296141cc406Sopenharmony_ci
1297141cc406Sopenharmony_cistatic int
1298141cc406Sopenharmony_cibjnp_write (int devno, const SANE_Byte * buf, size_t count)
1299141cc406Sopenharmony_ci{
1300141cc406Sopenharmony_ci/*
1301141cc406Sopenharmony_ci * This function writes TCP data to the scanner.
1302141cc406Sopenharmony_ci * Returns: number of bytes written to the scanner
1303141cc406Sopenharmony_ci */
1304141cc406Sopenharmony_ci  int sent_bytes;
1305141cc406Sopenharmony_ci  int terrno;
1306141cc406Sopenharmony_ci  struct SCAN_BUF bjnp_buf;
1307141cc406Sopenharmony_ci
1308141cc406Sopenharmony_ci  if (device[devno].scanner_data_left)
1309141cc406Sopenharmony_ci    {
1310141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1311141cc406Sopenharmony_ci	    (LOG_CRIT, "bjnp_write: ERROR - scanner data left = 0x%lx = %ld\n",
1312141cc406Sopenharmony_ci	     (unsigned long) device[devno].scanner_data_left,
1313141cc406Sopenharmony_ci	     (unsigned long) device[devno].scanner_data_left));
1314141cc406Sopenharmony_ci    }
1315141cc406Sopenharmony_ci  /* set BJNP command header */
1316141cc406Sopenharmony_ci
1317141cc406Sopenharmony_ci  set_cmd_for_dev (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_SEND, count);
1318141cc406Sopenharmony_ci  memcpy (bjnp_buf.scan_data, buf, count);
1319141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_write: sending 0x%lx = %ld bytes\n",
1320141cc406Sopenharmony_ci		   (unsigned long) count, (unsigned long) count);
1321141cc406Sopenharmony_ci	PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &bjnp_buf,
1322141cc406Sopenharmony_ci			     sizeof (struct BJNP_command) + count)));
1323141cc406Sopenharmony_ci
1324141cc406Sopenharmony_ci  if ((sent_bytes =
1325141cc406Sopenharmony_ci       send (device[devno].tcp_socket, &bjnp_buf,
1326141cc406Sopenharmony_ci	     sizeof (struct BJNP_command) + count, 0)) <
1327141cc406Sopenharmony_ci      (ssize_t) (sizeof (struct BJNP_command) + count))
1328141cc406Sopenharmony_ci    {
1329141cc406Sopenharmony_ci      /* return result from write */
1330141cc406Sopenharmony_ci      terrno = errno;
1331141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT, "bjnp_write: ERROR - Could not send data!\n"));
1332141cc406Sopenharmony_ci      errno = terrno;
1333141cc406Sopenharmony_ci      return sent_bytes;
1334141cc406Sopenharmony_ci    }
1335141cc406Sopenharmony_ci  /* correct nr of bytes sent for length of command */
1336141cc406Sopenharmony_ci
1337141cc406Sopenharmony_ci  else if (sent_bytes != (int) (sizeof (struct BJNP_command) + count))
1338141cc406Sopenharmony_ci    {
1339141cc406Sopenharmony_ci      errno = EIO;
1340141cc406Sopenharmony_ci      return -1;
1341141cc406Sopenharmony_ci    }
1342141cc406Sopenharmony_ci  return count;
1343141cc406Sopenharmony_ci}
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_cistatic int
1346141cc406Sopenharmony_cibjnp_send_read_request (int devno)
1347141cc406Sopenharmony_ci{
1348141cc406Sopenharmony_ci/*
1349141cc406Sopenharmony_ci * This function reads responses from the scanner.
1350141cc406Sopenharmony_ci * Returns: 0 on success, else -1
1351141cc406Sopenharmony_ci *
1352141cc406Sopenharmony_ci */
1353141cc406Sopenharmony_ci  int sent_bytes;
1354141cc406Sopenharmony_ci  int terrno;
1355141cc406Sopenharmony_ci  struct BJNP_command bjnp_buf;
1356141cc406Sopenharmony_ci
1357141cc406Sopenharmony_ci  if (device[devno].scanner_data_left)
1358141cc406Sopenharmony_ci    PDBG (bjnp_dbg
1359141cc406Sopenharmony_ci	  (LOG_CRIT,
1360141cc406Sopenharmony_ci	   "bjnp_send_read_request: ERROR - scanner data left = 0x%lx = %ld\n",
1361141cc406Sopenharmony_ci	   (unsigned long) device[devno].scanner_data_left,
1362141cc406Sopenharmony_ci	   (unsigned long) device[devno].scanner_data_left));
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ci  /* set BJNP command header */
1365141cc406Sopenharmony_ci
1366141cc406Sopenharmony_ci  set_cmd_for_dev (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_REQ, 0);
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_send_read_req sending command\n"));
1369141cc406Sopenharmony_ci  PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &bjnp_buf,
1370141cc406Sopenharmony_ci		       sizeof (struct BJNP_command)));
1371141cc406Sopenharmony_ci
1372141cc406Sopenharmony_ci  if ((sent_bytes =
1373141cc406Sopenharmony_ci       send (device[devno].tcp_socket, &bjnp_buf, sizeof (struct BJNP_command),
1374141cc406Sopenharmony_ci	     0)) < 0)
1375141cc406Sopenharmony_ci    {
1376141cc406Sopenharmony_ci      /* return result from write */
1377141cc406Sopenharmony_ci      terrno = errno;
1378141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1379141cc406Sopenharmony_ci	    (LOG_CRIT, "bjnp_send_read_request: ERROR - Could not send data!\n"));
1380141cc406Sopenharmony_ci      errno = terrno;
1381141cc406Sopenharmony_ci      return -1;
1382141cc406Sopenharmony_ci    }
1383141cc406Sopenharmony_ci  return 0;
1384141cc406Sopenharmony_ci}
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_cistatic SANE_Status
1387141cc406Sopenharmony_cibjnp_recv_header (int devno, size_t *payload_size )
1388141cc406Sopenharmony_ci{
1389141cc406Sopenharmony_ci/*
1390141cc406Sopenharmony_ci * This function receives the response header to bjnp commands.
1391141cc406Sopenharmony_ci * devno device number
1392141cc406Sopenharmony_ci * size: return value for data size returned by scanner
1393141cc406Sopenharmony_ci * Returns:
1394141cc406Sopenharmony_ci * SANE_STATUS_IO_ERROR when any IO error occurs
1395141cc406Sopenharmony_ci * SANE_STATUS_GOOD in case no errors were encountered
1396141cc406Sopenharmony_ci */
1397141cc406Sopenharmony_ci  struct BJNP_command resp_buf;
1398141cc406Sopenharmony_ci  fd_set input;
1399141cc406Sopenharmony_ci  struct timeval timeout;
1400141cc406Sopenharmony_ci  int recv_bytes;
1401141cc406Sopenharmony_ci  int terrno;
1402141cc406Sopenharmony_ci  int result;
1403141cc406Sopenharmony_ci  int fd;
1404141cc406Sopenharmony_ci  int attempt;
1405141cc406Sopenharmony_ci
1406141cc406Sopenharmony_ci  PDBG (bjnp_dbg
1407141cc406Sopenharmony_ci	(LOG_DEBUG, "bjnp_recv_header: receiving response header\n") );
1408141cc406Sopenharmony_ci  fd = device[devno].tcp_socket;
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci  *payload_size = 0;
1411141cc406Sopenharmony_ci  attempt = 0;
1412141cc406Sopenharmony_ci  do
1413141cc406Sopenharmony_ci    {
1414141cc406Sopenharmony_ci      /* wait for data to be received, ignore signals being received */
1415141cc406Sopenharmony_ci      FD_ZERO (&input);
1416141cc406Sopenharmony_ci      FD_SET (fd, &input);
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci      timeout.tv_sec = device[devno].bjnp_ip_timeout /1000;
1419141cc406Sopenharmony_ci      timeout.tv_usec = device[devno].bjnp_ip_timeout %1000;
1420141cc406Sopenharmony_ci    }
1421141cc406Sopenharmony_ci  while ( ( (result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) &&
1422141cc406Sopenharmony_ci	 (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS));
1423141cc406Sopenharmony_ci
1424141cc406Sopenharmony_ci  if (result < 0)
1425141cc406Sopenharmony_ci    {
1426141cc406Sopenharmony_ci      terrno = errno;
1427141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT,
1428141cc406Sopenharmony_ci		       "bjnp_recv_header: ERROR - could not read response header (select): %s!\n",
1429141cc406Sopenharmony_ci		       strerror (terrno)));
1430141cc406Sopenharmony_ci      errno = terrno;
1431141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1432141cc406Sopenharmony_ci    }
1433141cc406Sopenharmony_ci  else if (result == 0)
1434141cc406Sopenharmony_ci    {
1435141cc406Sopenharmony_ci      terrno = errno;
1436141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT,
1437141cc406Sopenharmony_ci		"bjnp_recv_header: ERROR - could not read response header (select timed out after %d ms)!\n",
1438141cc406Sopenharmony_ci		device[devno].bjnp_ip_timeout ) );
1439141cc406Sopenharmony_ci      errno = terrno;
1440141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1441141cc406Sopenharmony_ci    }
1442141cc406Sopenharmony_ci
1443141cc406Sopenharmony_ci  /* get response header */
1444141cc406Sopenharmony_ci
1445141cc406Sopenharmony_ci  if ((recv_bytes =
1446141cc406Sopenharmony_ci       recv (fd, (char *) &resp_buf,
1447141cc406Sopenharmony_ci	     sizeof (struct BJNP_command),
1448141cc406Sopenharmony_ci	     0)) != sizeof (struct BJNP_command))
1449141cc406Sopenharmony_ci    {
1450141cc406Sopenharmony_ci      terrno = errno;
1451141cc406Sopenharmony_ci      if (recv_bytes == 0)
1452141cc406Sopenharmony_ci        {
1453141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_CRIT,
1454141cc406Sopenharmony_ci          		"bjnp_recv_header: ERROR - (recv) Scanner closed the TCP-connection!\n"));
1455141cc406Sopenharmony_ci        } else {
1456141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_CRIT,
1457141cc406Sopenharmony_ci	      	       "bjnp_recv_header: ERROR - (recv) could not read response header, received %d bytes!\n",
1458141cc406Sopenharmony_ci		       recv_bytes));
1459141cc406Sopenharmony_ci          PDBG (bjnp_dbg
1460141cc406Sopenharmony_ci	  		(LOG_CRIT, "bjnp_recv_header: ERROR - (recv) error: %s!\n",
1461141cc406Sopenharmony_ci	     		strerror (terrno)));
1462141cc406Sopenharmony_ci        }
1463141cc406Sopenharmony_ci      errno = terrno;
1464141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1465141cc406Sopenharmony_ci    }
1466141cc406Sopenharmony_ci
1467141cc406Sopenharmony_ci  if (resp_buf.cmd_code != device[devno].last_cmd)
1468141cc406Sopenharmony_ci    {
1469141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1470141cc406Sopenharmony_ci	    (LOG_CRIT,
1471141cc406Sopenharmony_ci	     "bjnp_recv_header: ERROR - Received response has cmd code %d, expected %d\n",
1472141cc406Sopenharmony_ci	     resp_buf.cmd_code, device[devno].last_cmd));
1473141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1474141cc406Sopenharmony_ci    }
1475141cc406Sopenharmony_ci
1476141cc406Sopenharmony_ci  if (ntohs (resp_buf.seq_no) != (uint16_t) device[devno].serial)
1477141cc406Sopenharmony_ci    {
1478141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1479141cc406Sopenharmony_ci	    (LOG_CRIT,
1480141cc406Sopenharmony_ci	     "bjnp_recv_header: ERROR - Received response has serial %d, expected %d\n",
1481141cc406Sopenharmony_ci	     (int) ntohs (resp_buf.seq_no), (int) device[devno].serial));
1482141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1483141cc406Sopenharmony_ci    }
1484141cc406Sopenharmony_ci
1485141cc406Sopenharmony_ci  /* got response header back, retrieve length of payload */
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci
1488141cc406Sopenharmony_ci  *payload_size = ntohl (resp_buf.payload_len);
1489141cc406Sopenharmony_ci  PDBG (bjnp_dbg
1490141cc406Sopenharmony_ci	(LOG_DEBUG, "bjnp_recv_header: TCP response header(payload data = %ld bytes):\n",
1491141cc406Sopenharmony_ci	 *payload_size) );
1492141cc406Sopenharmony_ci  PDBG (bjnp_hexdump
1493141cc406Sopenharmony_ci	(LOG_DEBUG2, (char *) &resp_buf, sizeof (struct BJNP_command)));
1494141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1495141cc406Sopenharmony_ci}
1496141cc406Sopenharmony_ci
1497141cc406Sopenharmony_cistatic int
1498141cc406Sopenharmony_cibjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *protocol_defs, int ip_timeout)
1499141cc406Sopenharmony_ci{
1500141cc406Sopenharmony_ci  /* initialize device structure */
1501141cc406Sopenharmony_ci
1502141cc406Sopenharmony_ci  char name[BJNP_HOST_MAX];
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci  device[dn].open = 0;
1505141cc406Sopenharmony_ci#ifdef PIXMA_BJNP_USE_STATUS
1506141cc406Sopenharmony_ci  device[dn].polling_status = BJNP_POLL_STOPPED;
1507141cc406Sopenharmony_ci  device[dn].dialog = 0;
1508141cc406Sopenharmony_ci  device[dn].status_key = 0;
1509141cc406Sopenharmony_ci#endif
1510141cc406Sopenharmony_ci  device[dn].protocol = protocol_defs->protocol_version;
1511141cc406Sopenharmony_ci  device[dn].protocol_string = protocol_defs->proto_string;
1512141cc406Sopenharmony_ci  device[dn].single_tcp_session = protocol_defs->single_tcp_session;
1513141cc406Sopenharmony_ci  device[dn].tcp_socket = -1;
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci  device[dn].addr = (bjnp_sockaddr_t *) malloc(sizeof ( bjnp_sockaddr_t) );
1516141cc406Sopenharmony_ci  memset( device[dn].addr, 0, sizeof( bjnp_sockaddr_t ) );
1517141cc406Sopenharmony_ci  memcpy(device[dn].addr, sa, sa_size((bjnp_sockaddr_t *)sa) );
1518141cc406Sopenharmony_ci  device[dn].address_level = get_scanner_name(sa, name);
1519141cc406Sopenharmony_ci  device[dn].session_id = 0;
1520141cc406Sopenharmony_ci  device[dn].serial = -1;
1521141cc406Sopenharmony_ci  device[dn].bjnp_ip_timeout = ip_timeout;
1522141cc406Sopenharmony_ci  device[dn].bjnp_scanner_timeout = 1000;
1523141cc406Sopenharmony_ci  device[dn].scanner_data_left = 0;
1524141cc406Sopenharmony_ci  device[dn].last_cmd = 0;
1525141cc406Sopenharmony_ci  device[dn].blocksize = BJNP_BLOCKSIZE_START;
1526141cc406Sopenharmony_ci  device[dn].last_block = 0;
1527141cc406Sopenharmony_ci  /* fill mac_address */
1528141cc406Sopenharmony_ci
1529141cc406Sopenharmony_ci  if (bjnp_get_scanner_mac_address(dn, device[dn].mac_address) != 0 )
1530141cc406Sopenharmony_ci    {
1531141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1532141cc406Sopenharmony_ci            (LOG_CRIT, "bjnp_init_device_structure: Cannot read mac address, skipping this scanner\n"  ) );
1533141cc406Sopenharmony_ci            device[dn].open = 0;
1534141cc406Sopenharmony_ci      return -1;
1535141cc406Sopenharmony_ci    }
1536141cc406Sopenharmony_ci  device[dn].open = 1;
1537141cc406Sopenharmony_ci  return 0;
1538141cc406Sopenharmony_ci}
1539141cc406Sopenharmony_ci
1540141cc406Sopenharmony_cistatic void
1541141cc406Sopenharmony_cibjnp_free_device_structure( int dn)
1542141cc406Sopenharmony_ci{
1543141cc406Sopenharmony_ci  if (device[dn].addr != NULL)
1544141cc406Sopenharmony_ci    {
1545141cc406Sopenharmony_ci    free (device[dn].addr );
1546141cc406Sopenharmony_ci    device[dn].addr = NULL;
1547141cc406Sopenharmony_ci    }
1548141cc406Sopenharmony_ci  device[dn].open = 0;
1549141cc406Sopenharmony_ci}
1550141cc406Sopenharmony_ci
1551141cc406Sopenharmony_cistatic SANE_Status
1552141cc406Sopenharmony_cibjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len)
1553141cc406Sopenharmony_ci{
1554141cc406Sopenharmony_ci/*
1555141cc406Sopenharmony_ci * This function receives the payload data.
1556141cc406Sopenharmony_ci * NOTE: len may not exceed SSIZE_MAX (as that is max for recv)
1557141cc406Sopenharmony_ci *       len will be restricted to SSIZE_MAX to be sure
1558141cc406Sopenharmony_ci * Returns: number of bytes of payload received from device
1559141cc406Sopenharmony_ci */
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci  fd_set input;
1562141cc406Sopenharmony_ci  struct timeval timeout;
1563141cc406Sopenharmony_ci  ssize_t recv_bytes;
1564141cc406Sopenharmony_ci  int terrno;
1565141cc406Sopenharmony_ci  int result;
1566141cc406Sopenharmony_ci  int fd;
1567141cc406Sopenharmony_ci  int attempt;
1568141cc406Sopenharmony_ci
1569141cc406Sopenharmony_ci  PDBG (bjnp_dbg
1570141cc406Sopenharmony_ci	(LOG_DEBUG, "bjnp_recv_data: read response payload (0x%lx bytes max), buffer: 0x%lx, start_pos: 0x%lx\n",
1571141cc406Sopenharmony_ci	 (long) *len, (long) buffer, (long) start_pos));
1572141cc406Sopenharmony_ci
1573141cc406Sopenharmony_ci
1574141cc406Sopenharmony_ci  if (*len == 0)
1575141cc406Sopenharmony_ci    {
1576141cc406Sopenharmony_ci      /* nothing to do */
1577141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1578141cc406Sopenharmony_ci  	    (LOG_DEBUG, "bjnp_recv_data: Nothing to do (%ld bytes requested)\n",
1579141cc406Sopenharmony_ci	     (long) *len));
1580141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1581141cc406Sopenharmony_ci    }
1582141cc406Sopenharmony_ci  else if ( *len > SSIZE_MAX )
1583141cc406Sopenharmony_ci    {
1584141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1585141cc406Sopenharmony_ci    	    (LOG_DEBUG, "bjnp_recv_data: WARNING - requested block size (%ld) exceeds maximum, setting to maximum %ld\n",
1586141cc406Sopenharmony_ci	     (long)*len, SSIZE_MAX));
1587141cc406Sopenharmony_ci      *len = SSIZE_MAX;
1588141cc406Sopenharmony_ci    }
1589141cc406Sopenharmony_ci
1590141cc406Sopenharmony_ci  fd = device[devno].tcp_socket;
1591141cc406Sopenharmony_ci  attempt = 0;
1592141cc406Sopenharmony_ci  do
1593141cc406Sopenharmony_ci    {
1594141cc406Sopenharmony_ci      /* wait for data to be received, retry on a signal being received */
1595141cc406Sopenharmony_ci      FD_ZERO (&input);
1596141cc406Sopenharmony_ci      FD_SET (fd, &input);
1597141cc406Sopenharmony_ci      timeout.tv_sec = device[devno].bjnp_ip_timeout /1000;
1598141cc406Sopenharmony_ci      timeout.tv_usec = device[devno].bjnp_ip_timeout %1000;
1599141cc406Sopenharmony_ci    }
1600141cc406Sopenharmony_ci  while (((result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) &&
1601141cc406Sopenharmony_ci	 (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS));
1602141cc406Sopenharmony_ci
1603141cc406Sopenharmony_ci  if (result < 0)
1604141cc406Sopenharmony_ci    {
1605141cc406Sopenharmony_ci      terrno = errno;
1606141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT,
1607141cc406Sopenharmony_ci		       "bjnp_recv_data: ERROR - could not read response payload (select failed): %s!\n",
1608141cc406Sopenharmony_ci		       strerror (errno)));
1609141cc406Sopenharmony_ci      errno = terrno;
1610141cc406Sopenharmony_ci      *len = 0;
1611141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1612141cc406Sopenharmony_ci    }
1613141cc406Sopenharmony_ci  else if (result == 0)
1614141cc406Sopenharmony_ci    {
1615141cc406Sopenharmony_ci      terrno = errno;
1616141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT,
1617141cc406Sopenharmony_ci		"bjnp_recv_data: ERROR - could not read response payload (select timed out after %d ms)!\n",
1618141cc406Sopenharmony_ci		device[devno].bjnp_ip_timeout) );
1619141cc406Sopenharmony_ci      errno = terrno;
1620141cc406Sopenharmony_ci      *len = 0;
1621141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1622141cc406Sopenharmony_ci    }
1623141cc406Sopenharmony_ci
1624141cc406Sopenharmony_ci  if ((recv_bytes = recv (fd, buffer + start_pos, *len, 0)) < 0)
1625141cc406Sopenharmony_ci    {
1626141cc406Sopenharmony_ci      terrno = errno;
1627141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT,
1628141cc406Sopenharmony_ci		       "bjnp_recv_data: ERROR - could not read response payload (%ld + %ld = %ld) (recv): %s!\n",
1629141cc406Sopenharmony_ci		       (long) buffer, (long) start_pos, (long) buffer + start_pos, strerror (errno)));
1630141cc406Sopenharmony_ci      errno = terrno;
1631141cc406Sopenharmony_ci      *len = 0;
1632141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1633141cc406Sopenharmony_ci    }
1634141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_recv_data: Received TCP response payload (%ld bytes):\n",
1635141cc406Sopenharmony_ci		   (unsigned long) recv_bytes));
1636141cc406Sopenharmony_ci  PDBG (bjnp_hexdump (LOG_DEBUG2, buffer, recv_bytes));
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci  *len = recv_bytes;
1639141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1640141cc406Sopenharmony_ci}
1641141cc406Sopenharmony_ci
1642141cc406Sopenharmony_cistatic int
1643141cc406Sopenharmony_cibjnp_open_tcp (int devno)
1644141cc406Sopenharmony_ci{
1645141cc406Sopenharmony_ci  int sock;
1646141cc406Sopenharmony_ci  int val;
1647141cc406Sopenharmony_ci  char my_hostname[HOST_NAME_MAX];
1648141cc406Sopenharmony_ci  char pid_str[64];
1649141cc406Sopenharmony_ci  bjnp_sockaddr_t *addr = device[devno].addr;
1650141cc406Sopenharmony_ci  char host[BJNP_HOST_MAX];
1651141cc406Sopenharmony_ci  int port;
1652141cc406Sopenharmony_ci  int connect_timeout = BJNP_TIMEOUT_TCP_CONNECT;
1653141cc406Sopenharmony_ci
1654141cc406Sopenharmony_ci  if (device[devno].tcp_socket != -1)
1655141cc406Sopenharmony_ci    {
1656141cc406Sopenharmony_ci      PDBG (bjnp_dbg( LOG_DEBUG, "bjnp_open_tcp: socket alreeady opened, nothing to do\n"));
1657141cc406Sopenharmony_ci      return 0;
1658141cc406Sopenharmony_ci    }
1659141cc406Sopenharmony_ci  get_address_info( addr, host, &port);
1660141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_open_tcp: Setting up a TCP socket, dest: %s  port %d\n",
1661141cc406Sopenharmony_ci		   host, port ) );
1662141cc406Sopenharmony_ci
1663141cc406Sopenharmony_ci  gethostname (my_hostname, HOST_NAME_MAX);
1664141cc406Sopenharmony_ci  my_hostname[HOST_NAME_MAX - 1] = '\0';
1665141cc406Sopenharmony_ci  sprintf (pid_str, "Process ID = %d", getpid ());
1666141cc406Sopenharmony_ci  bjnp_send_job_details (devno, my_hostname, getusername (), pid_str);
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci  if ((sock = socket (get_protocol_family( addr ) , SOCK_STREAM, 0)) < 0)
1669141cc406Sopenharmony_ci    {
1670141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not create socket: %s\n",
1671141cc406Sopenharmony_ci		       strerror (errno)));
1672141cc406Sopenharmony_ci      return -1;
1673141cc406Sopenharmony_ci    }
1674141cc406Sopenharmony_ci
1675141cc406Sopenharmony_ci  val = 1;
1676141cc406Sopenharmony_ci  setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val));
1677141cc406Sopenharmony_ci
1678141cc406Sopenharmony_ci#if 0
1679141cc406Sopenharmony_ci  val = 1;
1680141cc406Sopenharmony_ci  setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof (val));
1681141cc406Sopenharmony_ci
1682141cc406Sopenharmony_ci  val = 1;
1683141cc406Sopenharmony_ci#endif
1684141cc406Sopenharmony_ci
1685141cc406Sopenharmony_ci  /*
1686141cc406Sopenharmony_ci   * Using TCP_NODELAY improves responsiveness, especially on systems
1687141cc406Sopenharmony_ci   * with a slow loopback interface...
1688141cc406Sopenharmony_ci   */
1689141cc406Sopenharmony_ci
1690141cc406Sopenharmony_ci  val = 1;
1691141cc406Sopenharmony_ci  setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
1692141cc406Sopenharmony_ci
1693141cc406Sopenharmony_ci/*
1694141cc406Sopenharmony_ci * Close this socket when starting another process...
1695141cc406Sopenharmony_ci */
1696141cc406Sopenharmony_ci
1697141cc406Sopenharmony_ci  fcntl (sock, F_SETFD, FD_CLOEXEC);
1698141cc406Sopenharmony_ci
1699141cc406Sopenharmony_ci  while (connect_timeout > 0)
1700141cc406Sopenharmony_ci    {
1701141cc406Sopenharmony_ci      if (connect
1702141cc406Sopenharmony_ci          (sock, &(addr->addr), sa_size(device[devno].addr)) == 0)
1703141cc406Sopenharmony_ci	    {
1704141cc406Sopenharmony_ci              device[devno].tcp_socket = sock;
1705141cc406Sopenharmony_ci              PDBG( bjnp_dbg(LOG_INFO, "bjnp_open_tcp: created socket %d\n", sock));
1706141cc406Sopenharmony_ci              return 0;
1707141cc406Sopenharmony_ci	    }
1708141cc406Sopenharmony_ci      PDBG (bjnp_dbg( LOG_INFO, "bjnp_open_tcp: INFO - Can not yet connect over TCP to scanner: %s, retrying\n",
1709141cc406Sopenharmony_ci                      strerror(errno)));
1710141cc406Sopenharmony_ci      usleep(BJNP_TCP_CONNECT_INTERVAL * BJNP_USLEEP_MS);
1711141cc406Sopenharmony_ci      connect_timeout = connect_timeout - BJNP_TCP_CONNECT_INTERVAL;
1712141cc406Sopenharmony_ci    }
1713141cc406Sopenharmony_ci  PDBG (bjnp_dbg
1714141cc406Sopenharmony_ci        (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not connect to scanner, giving up!"));
1715141cc406Sopenharmony_ci  return -1;
1716141cc406Sopenharmony_ci}
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_cistatic void bjnp_close_tcp(int devno)
1719141cc406Sopenharmony_ci{
1720141cc406Sopenharmony_ci  if ( device[devno].tcp_socket != -1)
1721141cc406Sopenharmony_ci    {
1722141cc406Sopenharmony_ci      PDBG( bjnp_dbg( LOG_INFO, "bjnp_close_tcp - closing tcp-socket %d\n", device[devno].tcp_socket));
1723141cc406Sopenharmony_ci      bjnp_finish_job (devno);
1724141cc406Sopenharmony_ci      close (device[devno].tcp_socket);
1725141cc406Sopenharmony_ci      device[devno].tcp_socket = -1;
1726141cc406Sopenharmony_ci    }
1727141cc406Sopenharmony_ci  else
1728141cc406Sopenharmony_ci    {
1729141cc406Sopenharmony_ci      PDBG( bjnp_dbg( LOG_INFO, "bjnp_close_tcp: socket not open, nothing to do.\n"));
1730141cc406Sopenharmony_ci    }
1731141cc406Sopenharmony_ci  device[devno].open = 0;
1732141cc406Sopenharmony_ci}
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_cistatic BJNP_Status
1735141cc406Sopenharmony_cibjnp_allocate_device (SANE_String_Const devname,
1736141cc406Sopenharmony_ci                      SANE_Int * dn, char *resulting_host)
1737141cc406Sopenharmony_ci{
1738141cc406Sopenharmony_ci  char method[BJNP_METHOD_MAX];
1739141cc406Sopenharmony_ci  char host[BJNP_HOST_MAX];
1740141cc406Sopenharmony_ci  char port[BJNP_PORT_MAX] = "";
1741141cc406Sopenharmony_ci  char args[BJNP_ARGS_MAX];
1742141cc406Sopenharmony_ci  bjnp_protocol_defs_t *protocol_defs;
1743141cc406Sopenharmony_ci  struct addrinfo *res, *cur;
1744141cc406Sopenharmony_ci  struct addrinfo hints;
1745141cc406Sopenharmony_ci  int result;
1746141cc406Sopenharmony_ci  int i;
1747141cc406Sopenharmony_ci  int ip_timeout = BJNP_TIMEOUT_DEFAULT;
1748141cc406Sopenharmony_ci
1749141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_allocate_device(%s) %d\n", devname, bjnp_no_devices));
1750141cc406Sopenharmony_ci
1751141cc406Sopenharmony_ci  if (split_uri (devname, method, host, port, args) != 0)
1752141cc406Sopenharmony_ci    {
1753141cc406Sopenharmony_ci      return BJNP_STATUS_INVAL;
1754141cc406Sopenharmony_ci    }
1755141cc406Sopenharmony_ci
1756141cc406Sopenharmony_ci  if (strlen (args) > 0)
1757141cc406Sopenharmony_ci    {
1758141cc406Sopenharmony_ci      /* get device specific ip timeout if any */
1759141cc406Sopenharmony_ci
1760141cc406Sopenharmony_ci      if (strncmp(args, "timeout=", strlen("timeout=")) == 0)
1761141cc406Sopenharmony_ci        {
1762141cc406Sopenharmony_ci          ip_timeout = atoi(args + strlen("timeout="));
1763141cc406Sopenharmony_ci        } else {
1764141cc406Sopenharmony_ci		PDBG (bjnp_dbg
1765141cc406Sopenharmony_ci	    		(LOG_CRIT,
1766141cc406Sopenharmony_ci				"bjnp_allocate_device: ERROR - Unrecognized argument: %s\n",
1767141cc406Sopenharmony_ci	     			devname));
1768141cc406Sopenharmony_ci
1769141cc406Sopenharmony_ci      return BJNP_STATUS_INVAL;
1770141cc406Sopenharmony_ci        }
1771141cc406Sopenharmony_ci    }
1772141cc406Sopenharmony_ci  if ( (protocol_defs = get_protocol_by_method(method)) == NULL)
1773141cc406Sopenharmony_ci    {
1774141cc406Sopenharmony_ci      PDBG (bjnp_dbg
1775141cc406Sopenharmony_ci		(LOG_CRIT, "bjnp_allocate_device: ERROR - URI %s contains invalid method: %s\n",
1776141cc406Sopenharmony_ci		 devname, method));
1777141cc406Sopenharmony_ci      return BJNP_STATUS_INVAL;
1778141cc406Sopenharmony_ci    }
1779141cc406Sopenharmony_ci
1780141cc406Sopenharmony_ci  if (strlen(port) == 0)
1781141cc406Sopenharmony_ci    {
1782141cc406Sopenharmony_ci      sprintf( port, "%d", protocol_defs->default_port );
1783141cc406Sopenharmony_ci    }
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci  hints.ai_flags = 0;
1786141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
1787141cc406Sopenharmony_ci  hints.ai_family = AF_UNSPEC;
1788141cc406Sopenharmony_ci#else
1789141cc406Sopenharmony_ci  hints.ai_family = AF_INET;
1790141cc406Sopenharmony_ci#endif
1791141cc406Sopenharmony_ci  hints.ai_socktype = SOCK_DGRAM;
1792141cc406Sopenharmony_ci  hints.ai_protocol = 0;
1793141cc406Sopenharmony_ci  hints.ai_addrlen = 0;
1794141cc406Sopenharmony_ci  hints.ai_addr = NULL;
1795141cc406Sopenharmony_ci  hints.ai_canonname = NULL;
1796141cc406Sopenharmony_ci  hints.ai_next = NULL;
1797141cc406Sopenharmony_ci
1798141cc406Sopenharmony_ci  result = getaddrinfo (host, port, &hints, &res );
1799141cc406Sopenharmony_ci  if (result != 0 )
1800141cc406Sopenharmony_ci    {
1801141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT, "bjnp_allocate_device: ERROR - Cannot resolve host: %s port %s\n", host, port));
1802141cc406Sopenharmony_ci      return BJNP_STATUS_INVAL;
1803141cc406Sopenharmony_ci    }
1804141cc406Sopenharmony_ci
1805141cc406Sopenharmony_ci  /* Check if a device number is already allocated to any of the scanner's addresses */
1806141cc406Sopenharmony_ci
1807141cc406Sopenharmony_ci  cur = res;
1808141cc406Sopenharmony_ci  while( cur != NULL)
1809141cc406Sopenharmony_ci    {
1810141cc406Sopenharmony_ci      /* create a new device structure for this address */
1811141cc406Sopenharmony_ci
1812141cc406Sopenharmony_ci      if (bjnp_no_devices == BJNP_NO_DEVICES)
1813141cc406Sopenharmony_ci        {
1814141cc406Sopenharmony_ci          PDBG (bjnp_dbg
1815141cc406Sopenharmony_ci    	    (LOG_CRIT,
1816141cc406Sopenharmony_ci    	     "bjnp_allocate_device: WARNING - Too many devices, ran out of device structures, cannot add %s\n",
1817141cc406Sopenharmony_ci    	     devname));
1818141cc406Sopenharmony_ci          freeaddrinfo(res);
1819141cc406Sopenharmony_ci          return BJNP_STATUS_INVAL;
1820141cc406Sopenharmony_ci        }
1821141cc406Sopenharmony_ci      if (bjnp_init_device_structure( bjnp_no_devices, (bjnp_sockaddr_t *)cur -> ai_addr,
1822141cc406Sopenharmony_ci                                      protocol_defs, ip_timeout) != 0)
1823141cc406Sopenharmony_ci        {
1824141cc406Sopenharmony_ci          /* giving up on this address, try next one if any */
1825141cc406Sopenharmony_ci          cur = cur->ai_next;
1826141cc406Sopenharmony_ci          continue;
1827141cc406Sopenharmony_ci        }
1828141cc406Sopenharmony_ci      for (i = 0; i < bjnp_no_devices; i++)
1829141cc406Sopenharmony_ci        {
1830141cc406Sopenharmony_ci
1831141cc406Sopenharmony_ci          /* Check if found the scanner before, if so we use the best address
1832141cc406Sopenharmony_ci	   * but still make sure the scanner is listed only once.
1833141cc406Sopenharmony_ci	   * We check for matching addresses as wel as matching mac_addresses as
1834141cc406Sopenharmony_ci           * an IPv6 host can have multiple addresses */
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci          if ( strcmp( device[i].mac_address, device[bjnp_no_devices].mac_address ) == 0 )
1837141cc406Sopenharmony_ci            {
1838141cc406Sopenharmony_ci              if ( device[i].address_level < device[bjnp_no_devices].address_level )
1839141cc406Sopenharmony_ci                {
1840141cc406Sopenharmony_ci                  /* use the new address instead as it is better */
1841141cc406Sopenharmony_ci                  free (device[i].addr);
1842141cc406Sopenharmony_ci                  device[i].addr = device[bjnp_no_devices].addr;
1843141cc406Sopenharmony_ci                  device[bjnp_no_devices].addr = NULL;
1844141cc406Sopenharmony_ci                  device[i].address_level = device[bjnp_no_devices].address_level;
1845141cc406Sopenharmony_ci                }
1846141cc406Sopenharmony_ci
1847141cc406Sopenharmony_ci	      /* Leave timeout values unchanged, as they were probably specified by the user */
1848141cc406Sopenharmony_ci
1849141cc406Sopenharmony_ci              freeaddrinfo(res);
1850141cc406Sopenharmony_ci              *dn = i;
1851141cc406Sopenharmony_ci              bjnp_free_device_structure( bjnp_no_devices);
1852141cc406Sopenharmony_ci              return BJNP_STATUS_ALREADY_ALLOCATED;
1853141cc406Sopenharmony_ci            }
1854141cc406Sopenharmony_ci        }
1855141cc406Sopenharmony_ci      cur = cur->ai_next;
1856141cc406Sopenharmony_ci    }
1857141cc406Sopenharmony_ci  freeaddrinfo(res);
1858141cc406Sopenharmony_ci
1859141cc406Sopenharmony_ci  if (device[bjnp_no_devices].open == 0)
1860141cc406Sopenharmony_ci    {
1861141cc406Sopenharmony_ci      PDBG (bjnp_dbg(LOG_NOTICE, "bjnp_allocate_device: Cannot access scanner, skipping!"));
1862141cc406Sopenharmony_ci      return BJNP_STATUS_INVAL;
1863141cc406Sopenharmony_ci    }
1864141cc406Sopenharmony_ci
1865141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "bjnp_allocate_device: Scanner not yet in our list, added it: %s:%s\n", host, port));
1866141cc406Sopenharmony_ci
1867141cc406Sopenharmony_ci  /* Commit new device structure */
1868141cc406Sopenharmony_ci
1869141cc406Sopenharmony_ci  *dn = bjnp_no_devices;
1870141cc406Sopenharmony_ci  bjnp_no_devices++;
1871141cc406Sopenharmony_ci
1872141cc406Sopenharmony_ci  /* return hostname if required */
1873141cc406Sopenharmony_ci
1874141cc406Sopenharmony_ci  if (resulting_host != NULL)
1875141cc406Sopenharmony_ci    {
1876141cc406Sopenharmony_ci      strcpy (resulting_host, host);
1877141cc406Sopenharmony_ci    }
1878141cc406Sopenharmony_ci
1879141cc406Sopenharmony_ci  return BJNP_STATUS_GOOD;
1880141cc406Sopenharmony_ci}
1881141cc406Sopenharmony_ci
1882141cc406Sopenharmony_cistatic void add_scanner(SANE_Int *dev_no,
1883141cc406Sopenharmony_ci                        const char *uri,
1884141cc406Sopenharmony_ci			SANE_Status (*attach_bjnp)
1885141cc406Sopenharmony_ci			              (SANE_String_Const devname,
1886141cc406Sopenharmony_ci			               SANE_String_Const serial,
1887141cc406Sopenharmony_ci			               const struct pixma_config_t *cfg),
1888141cc406Sopenharmony_ci                       const struct pixma_config_t *const pixma_devices[])
1889141cc406Sopenharmony_ci
1890141cc406Sopenharmony_ci{
1891141cc406Sopenharmony_ci  char scanner_host[BJNP_HOST_MAX];
1892141cc406Sopenharmony_ci  char serial[BJNP_SERIAL_MAX];
1893141cc406Sopenharmony_ci  char makemodel[BJNP_MODEL_MAX];
1894141cc406Sopenharmony_ci  const struct pixma_config_t *cfg = NULL;
1895141cc406Sopenharmony_ci
1896141cc406Sopenharmony_ci  /* Allocate device structure for scanner */
1897141cc406Sopenharmony_ci  switch (bjnp_allocate_device (uri, dev_no, scanner_host))
1898141cc406Sopenharmony_ci    {
1899141cc406Sopenharmony_ci      case BJNP_STATUS_GOOD:
1900141cc406Sopenharmony_ci        if (get_scanner_id (*dev_no, makemodel) != 0)
1901141cc406Sopenharmony_ci          {
1902141cc406Sopenharmony_ci            PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: ERROR - Cannot read scanner make & model: %s\n",
1903141cc406Sopenharmony_ci                             uri));
1904141cc406Sopenharmony_ci          }
1905141cc406Sopenharmony_ci        else
1906141cc406Sopenharmony_ci          {
1907141cc406Sopenharmony_ci            /*
1908141cc406Sopenharmony_ci             * fetch scanner configuration
1909141cc406Sopenharmony_ci             */
1910141cc406Sopenharmony_ci            if ((cfg = lookup_scanner(makemodel, pixma_devices)) == (struct pixma_config_t *)NULL)
1911141cc406Sopenharmony_ci              {
1912141cc406Sopenharmony_ci                 PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: Scanner %s is not supported, model is unknown! Please report upstream\n", makemodel));
1913141cc406Sopenharmony_ci                 break;
1914141cc406Sopenharmony_ci              }
1915141cc406Sopenharmony_ci
1916141cc406Sopenharmony_ci            /*
1917141cc406Sopenharmony_ci             * inform caller of found scanner
1918141cc406Sopenharmony_ci             */
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci             determine_scanner_serial (scanner_host, device[*dev_no].mac_address, serial);
1921141cc406Sopenharmony_ci
1922141cc406Sopenharmony_ci             switch (attach_bjnp (uri, serial, cfg))
1923141cc406Sopenharmony_ci             {
1924141cc406Sopenharmony_ci               case SANE_STATUS_GOOD:
1925141cc406Sopenharmony_ci                 PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac address: %s.\n",
1926141cc406Sopenharmony_ci	                         uri, serial, device[*dev_no].mac_address));
1927141cc406Sopenharmony_ci                 break;
1928141cc406Sopenharmony_ci               default:
1929141cc406Sopenharmony_ci                 PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: unexpected error (out of memory?), adding %s\n", makemodel));
1930141cc406Sopenharmony_ci            }
1931141cc406Sopenharmony_ci          }
1932141cc406Sopenharmony_ci
1933141cc406Sopenharmony_ci        break;
1934141cc406Sopenharmony_ci      case BJNP_STATUS_ALREADY_ALLOCATED:
1935141cc406Sopenharmony_ci        PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: Scanner at %s was added before, good!\n",
1936141cc406Sopenharmony_ci	                 uri));
1937141cc406Sopenharmony_ci        break;
1938141cc406Sopenharmony_ci
1939141cc406Sopenharmony_ci      case BJNP_STATUS_INVAL:
1940141cc406Sopenharmony_ci        PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: Scanner at %s can not be added\n",
1941141cc406Sopenharmony_ci	                 uri));
1942141cc406Sopenharmony_ci        break;
1943141cc406Sopenharmony_ci    }
1944141cc406Sopenharmony_ci}
1945141cc406Sopenharmony_ci
1946141cc406Sopenharmony_ciint add_timeout_to_uri(char *uri, int timeout, int max_len)
1947141cc406Sopenharmony_ci{
1948141cc406Sopenharmony_ci  char method[BJNP_METHOD_MAX];
1949141cc406Sopenharmony_ci  char host[BJNP_HOST_MAX];
1950141cc406Sopenharmony_ci  char port_str[BJNP_PORT_MAX];
1951141cc406Sopenharmony_ci  char args[BJNP_HOST_MAX];
1952141cc406Sopenharmony_ci  int port;
1953141cc406Sopenharmony_ci  bjnp_protocol_defs_t *proto_struct;
1954141cc406Sopenharmony_ci
1955141cc406Sopenharmony_ci  if (split_uri(uri, method, host, port_str, args ) != 0)
1956141cc406Sopenharmony_ci    {
1957141cc406Sopenharmony_ci      return -1;
1958141cc406Sopenharmony_ci    }
1959141cc406Sopenharmony_ci
1960141cc406Sopenharmony_ci  port = atoi(port_str);
1961141cc406Sopenharmony_ci
1962141cc406Sopenharmony_ci  if (port == 0)
1963141cc406Sopenharmony_ci    {
1964141cc406Sopenharmony_ci      proto_struct = get_protocol_by_method(method);
1965141cc406Sopenharmony_ci      if (proto_struct == NULL)
1966141cc406Sopenharmony_ci        {
1967141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_NOTICE, "uri: %s: Method %s cannot be recognized\n", uri,  method));
1968141cc406Sopenharmony_ci        }
1969141cc406Sopenharmony_ci      else
1970141cc406Sopenharmony_ci        {
1971141cc406Sopenharmony_ci          port = proto_struct-> default_port;
1972141cc406Sopenharmony_ci        }
1973141cc406Sopenharmony_ci    }
1974141cc406Sopenharmony_ci
1975141cc406Sopenharmony_ci  /* add timeout value only if missing in URI */
1976141cc406Sopenharmony_ci
1977141cc406Sopenharmony_ci  if (strstr(args, "timeout=") == NULL)
1978141cc406Sopenharmony_ci    {
1979141cc406Sopenharmony_ci      sprintf(args, "timeout=%d", timeout);
1980141cc406Sopenharmony_ci    }
1981141cc406Sopenharmony_ci
1982141cc406Sopenharmony_ci  snprintf(uri, max_len -1, "%s://%s:%d/%s", method,host, port, args);
1983141cc406Sopenharmony_ci  uri[max_len - 1] = '\0';
1984141cc406Sopenharmony_ci  return 0;
1985141cc406Sopenharmony_ci}
1986141cc406Sopenharmony_ci
1987141cc406Sopenharmony_ci/** Public functions **/
1988141cc406Sopenharmony_ci
1989141cc406Sopenharmony_ci/** Initialize sanei_bjnp.
1990141cc406Sopenharmony_ci *
1991141cc406Sopenharmony_ci * Call this before any other sanei_bjnp function.
1992141cc406Sopenharmony_ci */
1993141cc406Sopenharmony_ciextern void
1994141cc406Sopenharmony_cisanei_bjnp_init (void)
1995141cc406Sopenharmony_ci{
1996141cc406Sopenharmony_ci  DBG_INIT();
1997141cc406Sopenharmony_ci  bjnp_no_devices = 0;
1998141cc406Sopenharmony_ci}
1999141cc406Sopenharmony_ci
2000141cc406Sopenharmony_ci/**
2001141cc406Sopenharmony_ci * Find devices that implement the bjnp protocol
2002141cc406Sopenharmony_ci *
2003141cc406Sopenharmony_ci * The function attach is called for every device which has been found.
2004141cc406Sopenharmony_ci *
2005141cc406Sopenharmony_ci * @param attach attach function
2006141cc406Sopenharmony_ci *
2007141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD - on success (even if no scanner was found)
2008141cc406Sopenharmony_ci */
2009141cc406Sopenharmony_ciextern SANE_Status
2010141cc406Sopenharmony_cisanei_bjnp_find_devices (const char **conf_devices,
2011141cc406Sopenharmony_ci			 SANE_Status (*attach_bjnp)
2012141cc406Sopenharmony_ci			     (SANE_String_Const devname,
2013141cc406Sopenharmony_ci			      SANE_String_Const serial,
2014141cc406Sopenharmony_ci			      const struct pixma_config_t *cfg),
2015141cc406Sopenharmony_ci			 const struct pixma_config_t *const pixma_devices[])
2016141cc406Sopenharmony_ci{
2017141cc406Sopenharmony_ci  int numbytes = 0;
2018141cc406Sopenharmony_ci  struct BJNP_command cmd;
2019141cc406Sopenharmony_ci  unsigned char resp_buf[2048];
2020141cc406Sopenharmony_ci  struct DISCOVER_RESPONSE *disc_resp = ( struct DISCOVER_RESPONSE *) & resp_buf;
2021141cc406Sopenharmony_ci  int socket_fd[BJNP_SOCK_MAX];
2022141cc406Sopenharmony_ci  int no_sockets;
2023141cc406Sopenharmony_ci  int i;
2024141cc406Sopenharmony_ci  int j;
2025141cc406Sopenharmony_ci  int attempt;
2026141cc406Sopenharmony_ci  int last_socketfd = 0;
2027141cc406Sopenharmony_ci  fd_set fdset;
2028141cc406Sopenharmony_ci  fd_set active_fdset;
2029141cc406Sopenharmony_ci  struct timeval timeout;
2030141cc406Sopenharmony_ci  char scanner_host[HOST_NAME_MAX];
2031141cc406Sopenharmony_ci  char uri[HOST_NAME_MAX + 32];
2032141cc406Sopenharmony_ci  int dev_no;
2033141cc406Sopenharmony_ci  int port;
2034141cc406Sopenharmony_ci  int auto_detect = 1;
2035141cc406Sopenharmony_ci  int timeout_default = BJNP_TIMEOUT_DEFAULT;
2036141cc406Sopenharmony_ci  bjnp_sockaddr_t broadcast_addr[BJNP_SOCK_MAX];
2037141cc406Sopenharmony_ci  bjnp_sockaddr_t scanner_sa;
2038141cc406Sopenharmony_ci  socklen_t socklen;
2039141cc406Sopenharmony_ci  bjnp_protocol_defs_t *protocol_defs;
2040141cc406Sopenharmony_ci
2041141cc406Sopenharmony_ci  memset( broadcast_addr, 0, sizeof( broadcast_addr) );
2042141cc406Sopenharmony_ci  memset( &scanner_sa, 0 ,sizeof( scanner_sa ) );
2043141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_find_devices, pixma backend version: %d.%d.%d\n",
2044141cc406Sopenharmony_ci	PIXMA_VERSION_MAJOR, PIXMA_VERSION_MINOR, PIXMA_VERSION_BUILD));
2045141cc406Sopenharmony_ci  bjnp_no_devices = 0;
2046141cc406Sopenharmony_ci
2047141cc406Sopenharmony_ci  for (i=0; i < BJNP_SOCK_MAX; i++)
2048141cc406Sopenharmony_ci    {
2049141cc406Sopenharmony_ci      socket_fd[i] = -1;
2050141cc406Sopenharmony_ci    }
2051141cc406Sopenharmony_ci
2052141cc406Sopenharmony_ci  /* parse config file */
2053141cc406Sopenharmony_ci
2054141cc406Sopenharmony_ci  if (conf_devices[0] != NULL)
2055141cc406Sopenharmony_ci    {
2056141cc406Sopenharmony_ci      if (strcmp(conf_devices[0], "networking=no") == 0)
2057141cc406Sopenharmony_ci        {
2058141cc406Sopenharmony_ci          /* networking=no may only occur on the first non-commented line */
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci          PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: Networked scanner detection is disabled in configuration file.\n" ) );
2061141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
2062141cc406Sopenharmony_ci        }
2063141cc406Sopenharmony_ci      /* parse configuration file */
2064141cc406Sopenharmony_ci
2065141cc406Sopenharmony_ci      for (i = 0; conf_devices[i] != NULL; i++)
2066141cc406Sopenharmony_ci        {
2067141cc406Sopenharmony_ci          if (strncmp(conf_devices[i], "bjnp-timeout=", strlen("bjnp-timeout="))== 0)
2068141cc406Sopenharmony_ci            {
2069141cc406Sopenharmony_ci	      timeout_default = atoi(conf_devices[i] + strlen("bjnp-timeout=") );
2070141cc406Sopenharmony_ci	      PDBG ( bjnp_dbg (LOG_DEBUG, "Set new default timeout value: %d ms.", timeout_default));
2071141cc406Sopenharmony_ci	      continue;
2072141cc406Sopenharmony_ci	    }
2073141cc406Sopenharmony_ci	  else if (strncmp(conf_devices[i], "auto_detection=no", strlen("auto_detection=no"))== 0)
2074141cc406Sopenharmony_ci            {
2075141cc406Sopenharmony_ci              auto_detect = 0;
2076141cc406Sopenharmony_ci	      PDBG ( bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: auto detection of scanners disabled"));
2077141cc406Sopenharmony_ci	      continue;
2078141cc406Sopenharmony_ci	    }
2079141cc406Sopenharmony_ci	  else
2080141cc406Sopenharmony_ci            {
2081141cc406Sopenharmony_ci              PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Adding scanner from pixma.conf: %s\n", conf_devices[i]));
2082141cc406Sopenharmony_ci              memcpy(uri, conf_devices[i], sizeof(uri));
2083141cc406Sopenharmony_ci              add_timeout_to_uri(uri, timeout_default, sizeof(uri));
2084141cc406Sopenharmony_ci              add_scanner(&dev_no, uri, attach_bjnp, pixma_devices);
2085141cc406Sopenharmony_ci	    }
2086141cc406Sopenharmony_ci        }
2087141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Added all specified scanners.\n"));
2088141cc406Sopenharmony_ci    }
2089141cc406Sopenharmony_ci  else
2090141cc406Sopenharmony_ci    {
2091141cc406Sopenharmony_ci      PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: Configuration file is empty, No devices specified.\n" ) );
2092141cc406Sopenharmony_ci    }
2093141cc406Sopenharmony_ci
2094141cc406Sopenharmony_ci  if (auto_detect == 0)
2095141cc406Sopenharmony_ci    {
2096141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2097141cc406Sopenharmony_ci    }
2098141cc406Sopenharmony_ci  /*
2099141cc406Sopenharmony_ci   * Send UDP DISCOVER to discover scanners and return the list of scanners found
2100141cc406Sopenharmony_ci   */
2101141cc406Sopenharmony_ci
2102141cc406Sopenharmony_ci  PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: Start auto-detection.\n" ) );
2103141cc406Sopenharmony_ci  FD_ZERO (&fdset);
2104141cc406Sopenharmony_ci
2105141cc406Sopenharmony_ci  no_sockets = 0;
2106141cc406Sopenharmony_ci#ifdef HAVE_IFADDRS_H
2107141cc406Sopenharmony_ci  {
2108141cc406Sopenharmony_ci    struct ifaddrs *interfaces = NULL;
2109141cc406Sopenharmony_ci    struct ifaddrs *interface;
2110141cc406Sopenharmony_ci    getifaddrs (&interfaces);
2111141cc406Sopenharmony_ci
2112141cc406Sopenharmony_ci    /* create a socket for each suitable interface */
2113141cc406Sopenharmony_ci
2114141cc406Sopenharmony_ci    interface = interfaces;
2115141cc406Sopenharmony_ci    while ((no_sockets < BJNP_SOCK_MAX) && (interface != NULL))
2116141cc406Sopenharmony_ci      {
2117141cc406Sopenharmony_ci        if ( ! (interface -> ifa_flags & IFF_POINTOPOINT) &&
2118141cc406Sopenharmony_ci            ( (socket_fd[no_sockets] =
2119141cc406Sopenharmony_ci                      prepare_socket( interface -> ifa_name,
2120141cc406Sopenharmony_ci                                      (bjnp_sockaddr_t *) interface -> ifa_addr,
2121141cc406Sopenharmony_ci                                      (bjnp_sockaddr_t *) interface -> ifa_broadaddr,
2122141cc406Sopenharmony_ci                                      &broadcast_addr[no_sockets] ) ) != -1 ) )
2123141cc406Sopenharmony_ci          {
2124141cc406Sopenharmony_ci            /* track highest used socket for later use in select */
2125141cc406Sopenharmony_ci            if (socket_fd[no_sockets] > last_socketfd)
2126141cc406Sopenharmony_ci              {
2127141cc406Sopenharmony_ci                last_socketfd = socket_fd[no_sockets];
2128141cc406Sopenharmony_ci              }
2129141cc406Sopenharmony_ci            FD_SET (socket_fd[no_sockets], &fdset);
2130141cc406Sopenharmony_ci            no_sockets++;
2131141cc406Sopenharmony_ci          }
2132141cc406Sopenharmony_ci        interface = interface->ifa_next;
2133141cc406Sopenharmony_ci      }
2134141cc406Sopenharmony_ci    freeifaddrs (interfaces);
2135141cc406Sopenharmony_ci  }
2136141cc406Sopenharmony_ci#else
2137141cc406Sopenharmony_ci  /* we have no easy way to find interfaces with their broadcast addresses. */
2138141cc406Sopenharmony_ci  /* use global broadcast and all-hosts instead */
2139141cc406Sopenharmony_ci  {
2140141cc406Sopenharmony_ci    bjnp_sockaddr_t local;
2141141cc406Sopenharmony_ci    bjnp_sockaddr_t bc_addr;
2142141cc406Sopenharmony_ci
2143141cc406Sopenharmony_ci    memset( &local, 0, sizeof( local) );
2144141cc406Sopenharmony_ci    local.ipv4.sin_family = AF_INET;
2145141cc406Sopenharmony_ci    local.ipv4.sin_addr.s_addr = htonl (INADDR_ANY);
2146141cc406Sopenharmony_ci
2147141cc406Sopenharmony_ci    bc_addr.ipv4.sin_family = AF_INET;
2148141cc406Sopenharmony_ci    bc_addr.ipv4.sin_port = htons(0);
2149141cc406Sopenharmony_ci    bc_addr.ipv4.sin_addr.s_addr = htonl (INADDR_BROADCAST);
2150141cc406Sopenharmony_ci
2151141cc406Sopenharmony_ci    socket_fd[no_sockets] = prepare_socket( "any_interface",
2152141cc406Sopenharmony_ci                                   &local,
2153141cc406Sopenharmony_ci                                   &bc_addr,
2154141cc406Sopenharmony_ci                                   &broadcast_addr[no_sockets] );
2155141cc406Sopenharmony_ci    if (socket_fd[no_sockets] >= 0)
2156141cc406Sopenharmony_ci      {
2157141cc406Sopenharmony_ci        FD_SET (socket_fd[no_sockets], &fdset);
2158141cc406Sopenharmony_ci        if (socket_fd[no_sockets] > last_socketfd)
2159141cc406Sopenharmony_ci          {
2160141cc406Sopenharmony_ci            last_socketfd = socket_fd[no_sockets];
2161141cc406Sopenharmony_ci          }
2162141cc406Sopenharmony_ci        no_sockets++;
2163141cc406Sopenharmony_ci      }
2164141cc406Sopenharmony_ci#ifdef ENABLE_IPV6
2165141cc406Sopenharmony_ci    local.ipv6.sin6_family = AF_INET6;
2166141cc406Sopenharmony_ci    local.ipv6.sin6_addr = in6addr_any;
2167141cc406Sopenharmony_ci
2168141cc406Sopenharmony_ci    socket_fd[no_sockets] = prepare_socket( "any_interface",
2169141cc406Sopenharmony_ci                                   &local,
2170141cc406Sopenharmony_ci                                   NULL,
2171141cc406Sopenharmony_ci                                   &broadcast_addr[no_sockets] );
2172141cc406Sopenharmony_ci    if (socket_fd[no_sockets] >= 0)
2173141cc406Sopenharmony_ci      {
2174141cc406Sopenharmony_ci        FD_SET (socket_fd[no_sockets], &fdset);
2175141cc406Sopenharmony_ci        if (socket_fd[no_sockets] > last_socketfd)
2176141cc406Sopenharmony_ci          {
2177141cc406Sopenharmony_ci            last_socketfd = socket_fd[no_sockets];
2178141cc406Sopenharmony_ci          }
2179141cc406Sopenharmony_ci        no_sockets++;
2180141cc406Sopenharmony_ci      }
2181141cc406Sopenharmony_ci#endif
2182141cc406Sopenharmony_ci  }
2183141cc406Sopenharmony_ci#endif
2184141cc406Sopenharmony_ci
2185141cc406Sopenharmony_ci  /* send BJNP_MAX_BROADCAST_ATTEMPTS broadcasts on each prepared socket */
2186141cc406Sopenharmony_ci  for (attempt = 0; attempt < BJNP_MAX_BROADCAST_ATTEMPTS; attempt++)
2187141cc406Sopenharmony_ci    {
2188141cc406Sopenharmony_ci      for ( i=0; i < no_sockets; i++)
2189141cc406Sopenharmony_ci        {
2190141cc406Sopenharmony_ci	  j = 0;
2191141cc406Sopenharmony_ci          while(bjnp_protocol_defs[j].protocol_version != PROTOCOL_NONE)
2192141cc406Sopenharmony_ci	    {
2193141cc406Sopenharmony_ci	      set_cmd_from_string (bjnp_protocol_defs[j].proto_string, &cmd, CMD_UDP_DISCOVER, 0);
2194141cc406Sopenharmony_ci              bjnp_send_broadcast ( socket_fd[i], &broadcast_addr[i],
2195141cc406Sopenharmony_ci                                    bjnp_protocol_defs[j].default_port, cmd, sizeof (cmd));
2196141cc406Sopenharmony_ci	      j++;
2197141cc406Sopenharmony_ci	    }
2198141cc406Sopenharmony_ci	}
2199141cc406Sopenharmony_ci      /* wait for some time between broadcast packets */
2200141cc406Sopenharmony_ci      usleep (BJNP_BROADCAST_INTERVAL * BJNP_USLEEP_MS);
2201141cc406Sopenharmony_ci    }
2202141cc406Sopenharmony_ci
2203141cc406Sopenharmony_ci  /* wait for a UDP response */
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci  timeout.tv_sec = 0;
2206141cc406Sopenharmony_ci  timeout.tv_usec = BJNP_BC_RESPONSE_TIMEOUT * BJNP_USLEEP_MS;
2207141cc406Sopenharmony_ci
2208141cc406Sopenharmony_ci
2209141cc406Sopenharmony_ci  active_fdset = fdset;
2210141cc406Sopenharmony_ci
2211141cc406Sopenharmony_ci  while (select (last_socketfd + 1, &active_fdset, NULL, NULL, &timeout) > 0)
2212141cc406Sopenharmony_ci    {
2213141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Select returned, time left %d.%d....\n",
2214141cc406Sopenharmony_ci		       (int) timeout.tv_sec, (int) timeout.tv_usec));
2215141cc406Sopenharmony_ci      for (i = 0; i < no_sockets; i++)
2216141cc406Sopenharmony_ci	{
2217141cc406Sopenharmony_ci	  if (FD_ISSET (socket_fd[i], &active_fdset))
2218141cc406Sopenharmony_ci	    {
2219141cc406Sopenharmony_ci              socklen =  sizeof(scanner_sa);
2220141cc406Sopenharmony_ci	      if ((numbytes =
2221141cc406Sopenharmony_ci		   recvfrom (socket_fd[i], resp_buf, sizeof (resp_buf), 0,
2222141cc406Sopenharmony_ci                             &(scanner_sa.addr), &socklen ) ) == -1)
2223141cc406Sopenharmony_ci		{
2224141cc406Sopenharmony_ci		  PDBG (bjnp_dbg
2225141cc406Sopenharmony_ci			(LOG_INFO, "sanei_find_devices: no data received"));
2226141cc406Sopenharmony_ci		  break;
2227141cc406Sopenharmony_ci		}
2228141cc406Sopenharmony_ci	      else
2229141cc406Sopenharmony_ci		{
2230141cc406Sopenharmony_ci		  PDBG (bjnp_dbg (LOG_DEBUG2, "sanei_find_devices: Discover response:\n"));
2231141cc406Sopenharmony_ci		  PDBG (bjnp_hexdump (LOG_DEBUG2, &resp_buf, numbytes));
2232141cc406Sopenharmony_ci
2233141cc406Sopenharmony_ci		  /* check if something sensible is returned */
2234141cc406Sopenharmony_ci		  protocol_defs = get_protocol_by_proto_string(disc_resp-> response.BJNP_id);
2235141cc406Sopenharmony_ci		  if ( (numbytes < (int)sizeof (struct BJNP_command)) ||
2236141cc406Sopenharmony_ci		       (protocol_defs == NULL))
2237141cc406Sopenharmony_ci		    {
2238141cc406Sopenharmony_ci		      /* not a valid response, assume not a scanner  */
2239141cc406Sopenharmony_ci
2240141cc406Sopenharmony_ci                      char bjnp_id[5];
2241141cc406Sopenharmony_ci                      strncpy(bjnp_id,  disc_resp-> response.BJNP_id, 4);
2242141cc406Sopenharmony_ci                      bjnp_id[4] = '\0';
2243141cc406Sopenharmony_ci                      PDBG (bjnp_dbg (LOG_INFO,
2244141cc406Sopenharmony_ci                        "sanei_find_devices: Invalid discover response! Length = %d, Id = %s\n",
2245141cc406Sopenharmony_ci                        numbytes, bjnp_id ) );
2246141cc406Sopenharmony_ci		      break;
2247141cc406Sopenharmony_ci		    }
2248141cc406Sopenharmony_ci                  if ( !(disc_resp -> response.dev_type & 0x80) )
2249141cc406Sopenharmony_ci                    {
2250141cc406Sopenharmony_ci                      /* not a response, a command from somebody else or */
2251141cc406Sopenharmony_ci                      /* a discover command that we generated */
2252141cc406Sopenharmony_ci                      break;
2253141cc406Sopenharmony_ci                    }
2254141cc406Sopenharmony_ci		};
2255141cc406Sopenharmony_ci
2256141cc406Sopenharmony_ci	      port = get_port_from_sa(scanner_sa);
2257141cc406Sopenharmony_ci	      /* scanner found, get IP-address or hostname */
2258141cc406Sopenharmony_ci              get_scanner_name( &scanner_sa, scanner_host);
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_ci	      /* construct URI */
2261141cc406Sopenharmony_ci	      sprintf (uri, "%s://%s:%d/timeout=%d", protocol_defs->method_string, scanner_host,
2262141cc406Sopenharmony_ci		           port, timeout_default);
2263141cc406Sopenharmony_ci
2264141cc406Sopenharmony_ci              add_scanner( &dev_no, uri, attach_bjnp, pixma_devices);
2265141cc406Sopenharmony_ci
2266141cc406Sopenharmony_ci	    }
2267141cc406Sopenharmony_ci	}
2268141cc406Sopenharmony_ci      active_fdset = fdset;
2269141cc406Sopenharmony_ci      timeout.tv_sec = 0;
2270141cc406Sopenharmony_ci      timeout.tv_usec = BJNP_BC_RESPONSE_TIMEOUT * BJNP_USLEEP_MS;
2271141cc406Sopenharmony_ci    }
2272141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG, "sanei_find_devices: scanner discovery finished...\n"));
2273141cc406Sopenharmony_ci
2274141cc406Sopenharmony_ci  for (i = 0; i < no_sockets; i++)
2275141cc406Sopenharmony_ci    close (socket_fd[i]);
2276141cc406Sopenharmony_ci
2277141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2278141cc406Sopenharmony_ci}
2279141cc406Sopenharmony_ci
2280141cc406Sopenharmony_ci/** Open a BJNP device.
2281141cc406Sopenharmony_ci *
2282141cc406Sopenharmony_ci * The device is opened by its name devname and the device number is
2283141cc406Sopenharmony_ci * returned in dn on success.
2284141cc406Sopenharmony_ci *
2285141cc406Sopenharmony_ci * Device names consist of an URI
2286141cc406Sopenharmony_ci * Where:
2287141cc406Sopenharmony_ci * type = bjnp
2288141cc406Sopenharmony_ci * hostname = resolvable name or IP-address
2289141cc406Sopenharmony_ci * port = 8612 for a scanner
2290141cc406Sopenharmony_ci * An example could look like this: bjnp://host.domain:8612
2291141cc406Sopenharmony_ci *
2292141cc406Sopenharmony_ci * @param devname name of the device to open
2293141cc406Sopenharmony_ci * @param dn device number
2294141cc406Sopenharmony_ci *
2295141cc406Sopenharmony_ci * @return
2296141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - on success
2297141cc406Sopenharmony_ci * - SANE_STATUS_ACCESS_DENIED - if the file couldn't be accessed due to
2298141cc406Sopenharmony_ci *   permissions
2299141cc406Sopenharmony_ci * - SANE_STATUS_INVAL - on every other error
2300141cc406Sopenharmony_ci */
2301141cc406Sopenharmony_ci
2302141cc406Sopenharmony_ciextern SANE_Status
2303141cc406Sopenharmony_cisanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn)
2304141cc406Sopenharmony_ci{
2305141cc406Sopenharmony_ci  int result;
2306141cc406Sopenharmony_ci
2307141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_open(%s, %d):\n", devname, *dn));
2308141cc406Sopenharmony_ci
2309141cc406Sopenharmony_ci  result = bjnp_allocate_device (devname, dn, NULL);
2310141cc406Sopenharmony_ci  if ( (result != BJNP_STATUS_GOOD) && (result != BJNP_STATUS_ALREADY_ALLOCATED ) ) {
2311141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2312141cc406Sopenharmony_ci  }
2313141cc406Sopenharmony_ci
2314141cc406Sopenharmony_ci  if (device[*dn].single_tcp_session && bjnp_open_tcp (*dn) != 0)
2315141cc406Sopenharmony_ci    {
2316141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_opening TCP connection failed.\n\n"));
2317141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2318141cc406Sopenharmony_ci    }
2319141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_open done.\n\n"));
2320141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2321141cc406Sopenharmony_ci}
2322141cc406Sopenharmony_ci
2323141cc406Sopenharmony_ci/** Close a BJNP device.
2324141cc406Sopenharmony_ci *
2325141cc406Sopenharmony_ci * @param dn device number
2326141cc406Sopenharmony_ci */
2327141cc406Sopenharmony_ci
2328141cc406Sopenharmony_civoid
2329141cc406Sopenharmony_cisanei_bjnp_close (SANE_Int dn)
2330141cc406Sopenharmony_ci{
2331141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_close(%d):\n", dn));
2332141cc406Sopenharmony_ci
2333141cc406Sopenharmony_ci  bjnp_close_tcp( dn );
2334141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_close done.\n\n"));
2335141cc406Sopenharmony_ci}
2336141cc406Sopenharmony_ci
2337141cc406Sopenharmony_ci/** Activate BJNP device connection
2338141cc406Sopenharmony_ci *
2339141cc406Sopenharmony_ci * @param dn device number
2340141cc406Sopenharmony_ci */
2341141cc406Sopenharmony_ci
2342141cc406Sopenharmony_ciSANE_Status
2343141cc406Sopenharmony_cisanei_bjnp_activate (SANE_Int dn)
2344141cc406Sopenharmony_ci{
2345141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate (%d)\n", dn));
2346141cc406Sopenharmony_ci  if (!(device[dn].single_tcp_session) && bjnp_open_tcp (dn) != 0)
2347141cc406Sopenharmony_ci    {
2348141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate: open TCP connection failed.\n\n"));
2349141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2350141cc406Sopenharmony_ci    }
2351141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate done.\n\n"));
2352141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2353141cc406Sopenharmony_ci}
2354141cc406Sopenharmony_ci
2355141cc406Sopenharmony_ci/** Deactivate BJNP device connection
2356141cc406Sopenharmony_ci *
2357141cc406Sopenharmony_ci * @paran dn device number
2358141cc406Sopenharmony_ci */
2359141cc406Sopenharmony_ci
2360141cc406Sopenharmony_ciSANE_Status
2361141cc406Sopenharmony_cisanei_bjnp_deactivate (SANE_Int dn)
2362141cc406Sopenharmony_ci{
2363141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_deactivate (%d)\n", dn));
2364141cc406Sopenharmony_ci  if (!device[dn].single_tcp_session)
2365141cc406Sopenharmony_ci  {
2366141cc406Sopenharmony_ci    bjnp_close_tcp(dn);
2367141cc406Sopenharmony_ci  }
2368141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_deactivate done.\n\n"));
2369141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2370141cc406Sopenharmony_ci}
2371141cc406Sopenharmony_ci
2372141cc406Sopenharmony_ci/** Set the timeout for interrupt reads.
2373141cc406Sopenharmony_ci *  we do not use it for bulk reads!
2374141cc406Sopenharmony_ci * @param timeout the new timeout in ms
2375141cc406Sopenharmony_ci */
2376141cc406Sopenharmony_ciextern void
2377141cc406Sopenharmony_cisanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout)
2378141cc406Sopenharmony_ci{
2379141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_INFO, "bjnp_set_timeout to %d\n",
2380141cc406Sopenharmony_ci        timeout));
2381141cc406Sopenharmony_ci
2382141cc406Sopenharmony_ci  device[devno].bjnp_scanner_timeout = timeout;
2383141cc406Sopenharmony_ci}
2384141cc406Sopenharmony_ci
2385141cc406Sopenharmony_ci/** Initiate a bulk transfer read.
2386141cc406Sopenharmony_ci *
2387141cc406Sopenharmony_ci * Read up to size bytes from the device to buffer. After the read, size
2388141cc406Sopenharmony_ci * contains the number of bytes actually read.
2389141cc406Sopenharmony_ci *
2390141cc406Sopenharmony_ci * @param dn device number
2391141cc406Sopenharmony_ci * @param buffer buffer to store read data in
2392141cc406Sopenharmony_ci * @param size size of the data
2393141cc406Sopenharmony_ci *
2394141cc406Sopenharmony_ci * @return
2395141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - on success
2396141cc406Sopenharmony_ci * - SANE_STATUS_EOF - if zero bytes have been read
2397141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - if an error occurred during the read
2398141cc406Sopenharmony_ci * - SANE_STATUS_INVAL - on every other error
2399141cc406Sopenharmony_ci *
2400141cc406Sopenharmony_ci */
2401141cc406Sopenharmony_ci
2402141cc406Sopenharmony_ciextern SANE_Status
2403141cc406Sopenharmony_cisanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size)
2404141cc406Sopenharmony_ci{
2405141cc406Sopenharmony_ci  SANE_Status result;
2406141cc406Sopenharmony_ci  SANE_Status error;
2407141cc406Sopenharmony_ci  size_t recvd;
2408141cc406Sopenharmony_ci  size_t read_size;
2409141cc406Sopenharmony_ci  size_t read_size_max;
2410141cc406Sopenharmony_ci  size_t requested;
2411141cc406Sopenharmony_ci
2412141cc406Sopenharmony_ci  PDBG (bjnp_dbg
2413141cc406Sopenharmony_ci	(LOG_INFO, "bjnp_read_bulk(dn=%d, bufferptr=%lx, 0x%lx = %ld)\n", dn,
2414141cc406Sopenharmony_ci	 (long) buffer, (unsigned long) *size, (unsigned long) *size));
2415141cc406Sopenharmony_ci
2416141cc406Sopenharmony_ci  recvd = 0;
2417141cc406Sopenharmony_ci  requested = *size;
2418141cc406Sopenharmony_ci
2419141cc406Sopenharmony_ci  PDBG (bjnp_dbg
2420141cc406Sopenharmony_ci	(LOG_DEBUG, "bjnp_read_bulk: 0x%lx = %ld bytes available at start\n",
2421141cc406Sopenharmony_ci	 (unsigned long) device[dn].scanner_data_left,
2422141cc406Sopenharmony_ci	 (unsigned long) device[dn].scanner_data_left ) );
2423141cc406Sopenharmony_ci
2424141cc406Sopenharmony_ci  while ( (recvd < requested) && !( device[dn].last_block && (device[dn].scanner_data_left == 0)) )
2425141cc406Sopenharmony_ci    {
2426141cc406Sopenharmony_ci      PDBG (bjnp_dbg
2427141cc406Sopenharmony_ci	    (LOG_DEBUG,
2428141cc406Sopenharmony_ci	     "bjnp_read_bulk: Already received 0x%lx = %ld bytes, backend requested 0x%lx = %ld bytes\n",
2429141cc406Sopenharmony_ci	     (unsigned long) recvd, (unsigned long) recvd,
2430141cc406Sopenharmony_ci	     (unsigned long) requested, (unsigned long)requested ));
2431141cc406Sopenharmony_ci
2432141cc406Sopenharmony_ci      /* Check first if there is data in flight from the scanner */
2433141cc406Sopenharmony_ci
2434141cc406Sopenharmony_ci      if (device[dn].scanner_data_left == 0)
2435141cc406Sopenharmony_ci        {
2436141cc406Sopenharmony_ci	  /* There is no data in flight from the scanner, send new read request */
2437141cc406Sopenharmony_ci
2438141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_DEBUG,
2439141cc406Sopenharmony_ci                          "bjnp_read_bulk: No (more) scanner data available, requesting more( blocksize = %ld = %lx\n",
2440141cc406Sopenharmony_ci                          (long int) device[dn].blocksize, (long int) device[dn].blocksize ));
2441141cc406Sopenharmony_ci
2442141cc406Sopenharmony_ci          if ((error = bjnp_send_read_request (dn)) != SANE_STATUS_GOOD)
2443141cc406Sopenharmony_ci            {
2444141cc406Sopenharmony_ci              *size = recvd;
2445141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
2446141cc406Sopenharmony_ci            }
2447141cc406Sopenharmony_ci          if ( ( error = bjnp_recv_header (dn, &(device[dn].scanner_data_left) )  ) != SANE_STATUS_GOOD)
2448141cc406Sopenharmony_ci            {
2449141cc406Sopenharmony_ci              *size = recvd;
2450141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
2451141cc406Sopenharmony_ci            }
2452141cc406Sopenharmony_ci          /* correct blocksize if applicable */
2453141cc406Sopenharmony_ci
2454141cc406Sopenharmony_ci          device[dn].blocksize = MAX (device[dn].blocksize, device[dn].scanner_data_left);
2455141cc406Sopenharmony_ci
2456141cc406Sopenharmony_ci          if ( device[dn].scanner_data_left < device[dn].blocksize)
2457141cc406Sopenharmony_ci            {
2458141cc406Sopenharmony_ci              /* the scanner will not react at all to a read request, when no more data is available */
2459141cc406Sopenharmony_ci              /* we now determine end of data by comparing the payload size to the maximum blocksize */
2460141cc406Sopenharmony_ci              /* this block is shorter than blocksize, so after this block we are done */
2461141cc406Sopenharmony_ci
2462141cc406Sopenharmony_ci              device[dn].last_block = 1;
2463141cc406Sopenharmony_ci            }
2464141cc406Sopenharmony_ci        }
2465141cc406Sopenharmony_ci
2466141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: In flight: 0x%lx = %ld bytes available\n",
2467141cc406Sopenharmony_ci		 (unsigned long) device[dn].scanner_data_left,
2468141cc406Sopenharmony_ci		 (unsigned long) device[dn].scanner_data_left));
2469141cc406Sopenharmony_ci
2470141cc406Sopenharmony_ci       /* read as many bytes as needed and available */
2471141cc406Sopenharmony_ci
2472141cc406Sopenharmony_ci      read_size_max = MIN( device[dn].scanner_data_left, (requested - recvd) );
2473141cc406Sopenharmony_ci      read_size = read_size_max;
2474141cc406Sopenharmony_ci
2475141cc406Sopenharmony_ci      PDBG (bjnp_dbg
2476141cc406Sopenharmony_ci	    (LOG_DEBUG,
2477141cc406Sopenharmony_ci	     "bjnp_read_bulk: Try to read 0x%lx = %ld (of max 0x%lx = %ld) bytes\n",
2478141cc406Sopenharmony_ci	     (unsigned long) read_size_max,
2479141cc406Sopenharmony_ci	     (unsigned long) read_size_max,
2480141cc406Sopenharmony_ci	     (unsigned long) device[dn].scanner_data_left,
2481141cc406Sopenharmony_ci	     (unsigned long) device[dn].scanner_data_left) );
2482141cc406Sopenharmony_ci
2483141cc406Sopenharmony_ci      result = bjnp_recv_data (dn, buffer , recvd, &read_size);
2484141cc406Sopenharmony_ci      if (result != SANE_STATUS_GOOD)
2485141cc406Sopenharmony_ci	{
2486141cc406Sopenharmony_ci	  *size = recvd;
2487141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
2488141cc406Sopenharmony_ci	}
2489141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: Expected at most %ld bytes, received this time: %ld\n",
2490141cc406Sopenharmony_ci            read_size_max, read_size) );
2491141cc406Sopenharmony_ci
2492141cc406Sopenharmony_ci      device[dn].scanner_data_left = device[dn].scanner_data_left - read_size;
2493141cc406Sopenharmony_ci      recvd = recvd + read_size;
2494141cc406Sopenharmony_ci    }
2495141cc406Sopenharmony_ci
2496141cc406Sopenharmony_ci  PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: %s: Returning %ld bytes, backend expects %ld\n",
2497141cc406Sopenharmony_ci        (recvd == *size)? "OK": "NOTICE",recvd, *size ) );
2498141cc406Sopenharmony_ci  *size = recvd;
2499141cc406Sopenharmony_ci  if ( *size == 0 )
2500141cc406Sopenharmony_ci    return SANE_STATUS_EOF;
2501141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2502141cc406Sopenharmony_ci}
2503141cc406Sopenharmony_ci
2504141cc406Sopenharmony_ci/** Initiate a bulk transfer write.
2505141cc406Sopenharmony_ci *
2506141cc406Sopenharmony_ci * Write up to size bytes from buffer to the device. After the write size
2507141cc406Sopenharmony_ci * contains the number of bytes actually written.
2508141cc406Sopenharmony_ci *
2509141cc406Sopenharmony_ci * @param dn device number
2510141cc406Sopenharmony_ci * @param buffer buffer to write to device
2511141cc406Sopenharmony_ci * @param size size of the data
2512141cc406Sopenharmony_ci *
2513141cc406Sopenharmony_ci * @return
2514141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - on success
2515141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - if an error occurred during the write
2516141cc406Sopenharmony_ci * - SANE_STATUS_INVAL - on every other error
2517141cc406Sopenharmony_ci */
2518141cc406Sopenharmony_ci
2519141cc406Sopenharmony_ciextern SANE_Status
2520141cc406Sopenharmony_cisanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size)
2521141cc406Sopenharmony_ci{
2522141cc406Sopenharmony_ci  ssize_t sent;
2523141cc406Sopenharmony_ci  size_t recvd;
2524141cc406Sopenharmony_ci  uint32_t buf;
2525141cc406Sopenharmony_ci  size_t payload_size;
2526141cc406Sopenharmony_ci
2527141cc406Sopenharmony_ci  /* Write received data to scanner */
2528141cc406Sopenharmony_ci
2529141cc406Sopenharmony_ci  sent = bjnp_write (dn, buffer, *size);
2530141cc406Sopenharmony_ci  if (sent < 0)
2531141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
2532141cc406Sopenharmony_ci  if (sent != (int) *size)
2533141cc406Sopenharmony_ci    {
2534141cc406Sopenharmony_ci      PDBG (bjnp_dbg
2535141cc406Sopenharmony_ci	    (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Sent only %ld bytes to scanner, expected %ld!!\n",
2536141cc406Sopenharmony_ci	     (unsigned long) sent, (unsigned long) *size));
2537141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2538141cc406Sopenharmony_ci    }
2539141cc406Sopenharmony_ci
2540141cc406Sopenharmony_ci  if (bjnp_recv_header (dn, &payload_size) != SANE_STATUS_GOOD)
2541141cc406Sopenharmony_ci    {
2542141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Could not read response to command!\n"));
2543141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2544141cc406Sopenharmony_ci    }
2545141cc406Sopenharmony_ci
2546141cc406Sopenharmony_ci  if (payload_size != 4)
2547141cc406Sopenharmony_ci    {
2548141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT,
2549141cc406Sopenharmony_ci		       "sanei_bjnp_write_bulk: ERROR - Scanner length of write confirmation = 0x%lx bytes = %ld, expected %d!!\n",
2550141cc406Sopenharmony_ci		       (unsigned long) payload_size,
2551141cc406Sopenharmony_ci		       (unsigned long) payload_size, 4));
2552141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2553141cc406Sopenharmony_ci    }
2554141cc406Sopenharmony_ci  recvd = payload_size;
2555141cc406Sopenharmony_ci  if ((bjnp_recv_data (dn, (unsigned char *) &buf, 0, &recvd) !=
2556141cc406Sopenharmony_ci       SANE_STATUS_GOOD) || (recvd != payload_size))
2557141cc406Sopenharmony_ci    {
2558141cc406Sopenharmony_ci      PDBG (bjnp_dbg (LOG_CRIT,
2559141cc406Sopenharmony_ci		       "sanei_bjnp_write_bulk: ERROR - Could not read length of data confirmed by device\n"));
2560141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2561141cc406Sopenharmony_ci    }
2562141cc406Sopenharmony_ci  recvd = ntohl (buf);
2563141cc406Sopenharmony_ci  if (recvd != *size)
2564141cc406Sopenharmony_ci    {
2565141cc406Sopenharmony_ci      PDBG (bjnp_dbg
2566141cc406Sopenharmony_ci	    (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Scanner confirmed %ld bytes, expected %ld!!\n",
2567141cc406Sopenharmony_ci	     (unsigned long) recvd, (unsigned long) *size));
2568141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2569141cc406Sopenharmony_ci    }
2570141cc406Sopenharmony_ci  /* we can expect data from the scanner */
2571141cc406Sopenharmony_ci
2572141cc406Sopenharmony_ci  device[dn].last_block = 0;
2573141cc406Sopenharmony_ci
2574141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2575141cc406Sopenharmony_ci}
2576141cc406Sopenharmony_ci
2577141cc406Sopenharmony_ci/** Initiate a interrupt transfer read.
2578141cc406Sopenharmony_ci *
2579141cc406Sopenharmony_ci * Read up to size bytes from the interrupt endpoint from the device to
2580141cc406Sopenharmony_ci * buffer. After the read, size contains the number of bytes actually read.
2581141cc406Sopenharmony_ci *
2582141cc406Sopenharmony_ci * @param dn device number
2583141cc406Sopenharmony_ci * @param buffer buffer to store read data in
2584141cc406Sopenharmony_ci * @param size size of the data
2585141cc406Sopenharmony_ci *
2586141cc406Sopenharmony_ci * @return
2587141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - on success
2588141cc406Sopenharmony_ci * - SANE_STATUS_EOF - if zero bytes have been read
2589141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - if an error occurred during the read
2590141cc406Sopenharmony_ci * - SANE_STATUS_INVAL - on every other error
2591141cc406Sopenharmony_ci *
2592141cc406Sopenharmony_ci */
2593141cc406Sopenharmony_ci
2594141cc406Sopenharmony_ciextern SANE_Status
2595141cc406Sopenharmony_cisanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size)
2596141cc406Sopenharmony_ci{
2597141cc406Sopenharmony_ci#ifndef PIXMA_BJNP_USE_STATUS
2598141cc406Sopenharmony_ci  PDBG (bjnp_dbg
2599141cc406Sopenharmony_ci	(LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn,
2600141cc406Sopenharmony_ci	 (unsigned long) *size, (unsigned long) *size));
2601141cc406Sopenharmony_ci
2602141cc406Sopenharmony_ci  memset (buffer, 0, *size);
2603141cc406Sopenharmony_ci  sleep (1);
2604141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
2605141cc406Sopenharmony_ci#else
2606141cc406Sopenharmony_ci
2607141cc406Sopenharmony_ci  char hostname[256];
2608141cc406Sopenharmony_ci  int resp_len;
2609141cc406Sopenharmony_ci  int timeout;
2610141cc406Sopenharmony_ci  int interval;
2611141cc406Sopenharmony_ci
2612141cc406Sopenharmony_ci  PDBG (bjnp_dbg
2613141cc406Sopenharmony_ci	(LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn,
2614141cc406Sopenharmony_ci	 (unsigned long) *size, (unsigned long) *size));
2615141cc406Sopenharmony_ci
2616141cc406Sopenharmony_ci  memset (buffer, 0, *size);
2617141cc406Sopenharmony_ci
2618141cc406Sopenharmony_ci  gethostname (hostname, 32);
2619141cc406Sopenharmony_ci  hostname[32] = '\0';
2620141cc406Sopenharmony_ci
2621141cc406Sopenharmony_ci
2622141cc406Sopenharmony_ci  switch (device[dn].polling_status)
2623141cc406Sopenharmony_ci    {
2624141cc406Sopenharmony_ci    case BJNP_POLL_STOPPED:
2625141cc406Sopenharmony_ci
2626141cc406Sopenharmony_ci      /* establish dialog */
2627141cc406Sopenharmony_ci
2628141cc406Sopenharmony_ci      if ( (bjnp_poll_scanner (dn, 0, hostname, getusername (), buffer, *size ) != 0) ||
2629141cc406Sopenharmony_ci           (bjnp_poll_scanner (dn, 1, hostname, getusername (), buffer, *size ) != 0) )
2630141cc406Sopenharmony_ci        {
2631141cc406Sopenharmony_ci	  PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: WARNING - Failed to setup read_intr dialog with device!\n"));
2632141cc406Sopenharmony_ci          device[dn].dialog = 0;
2633141cc406Sopenharmony_ci          device[dn].status_key = 0;
2634141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
2635141cc406Sopenharmony_ci        }
2636141cc406Sopenharmony_ci      device[dn].polling_status = BJNP_POLL_STARTED;
2637141cc406Sopenharmony_ci
2638141cc406Sopenharmony_ci      /* fall through */
2639141cc406Sopenharmony_ci    case BJNP_POLL_STARTED:
2640141cc406Sopenharmony_ci      /* we use only seonds (rounded up) accuracy between poll attempts */
2641141cc406Sopenharmony_ci      timeout = device[dn].bjnp_scanner_timeout /1000 + 1;
2642141cc406Sopenharmony_ci      if (device[dn].bjnp_scanner_timeout %1000 > 0)
2643141cc406Sopenharmony_ci        {
2644141cc406Sopenharmony_ci	  timeout++;
2645141cc406Sopenharmony_ci
2646141cc406Sopenharmony_ci	}
2647141cc406Sopenharmony_ci      interval = 1;
2648141cc406Sopenharmony_ci      do
2649141cc406Sopenharmony_ci        {
2650141cc406Sopenharmony_ci          if ( (resp_len = bjnp_poll_scanner (dn, 2, hostname, getusername (), buffer, *size ) ) < 0 )
2651141cc406Sopenharmony_ci            {
2652141cc406Sopenharmony_ci              PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: Poll failed, Restarting polling dialog!\n"));
2653141cc406Sopenharmony_ci              device[dn].polling_status = BJNP_POLL_STOPPED;
2654141cc406Sopenharmony_ci              *size = 0;
2655141cc406Sopenharmony_ci              return SANE_STATUS_EOF;
2656141cc406Sopenharmony_ci            }
2657141cc406Sopenharmony_ci          *size = (size_t) resp_len;
2658141cc406Sopenharmony_ci          if ( resp_len > 0 )
2659141cc406Sopenharmony_ci            {
2660141cc406Sopenharmony_ci              device[dn].polling_status = BJNP_POLL_STATUS_RECEIVED;
2661141cc406Sopenharmony_ci              return SANE_STATUS_GOOD;
2662141cc406Sopenharmony_ci            }
2663141cc406Sopenharmony_ci          timeout = timeout - interval;
2664141cc406Sopenharmony_ci	  if (timeout <= 0)
2665141cc406Sopenharmony_ci	    return SANE_STATUS_EOF;
2666141cc406Sopenharmony_ci          sleep(interval);
2667141cc406Sopenharmony_ci        } while ( timeout > 0 ) ;
2668141cc406Sopenharmony_ci      break;
2669141cc406Sopenharmony_ci    case BJNP_POLL_STATUS_RECEIVED:
2670141cc406Sopenharmony_ci       if ( (resp_len = bjnp_poll_scanner (dn, 5, hostname, getusername (), buffer, *size ) ) < 0 )
2671141cc406Sopenharmony_ci        {
2672141cc406Sopenharmony_ci          PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: Restarting polling dialog!\n"));
2673141cc406Sopenharmony_ci          device[dn].polling_status = BJNP_POLL_STOPPED;
2674141cc406Sopenharmony_ci          *size = 0;
2675141cc406Sopenharmony_ci          break;
2676141cc406Sopenharmony_ci        }
2677141cc406Sopenharmony_ci    }
2678141cc406Sopenharmony_ci  return SANE_STATUS_EOF;
2679141cc406Sopenharmony_ci#endif
2680141cc406Sopenharmony_ci}
2681