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