2009-03-06 Louis Lagendijk <llagendijk-guest at users.alioth.debian.org>

* backend/pixma_bjnp.c backend/pixma_bjnp.h
        backend/pixma_bjnp_private.h backend/pixma_io_sanei.c:
        Make bjnp protocol more resilient against packet loss and corruption
        Changed timeout for all responses to be at least 10 seconds
        Send all broadcasts for scanner detection 5 times
        Made sure scanners are added to device list only once
        Changed device-id for bjnp so it uses scanner hostname/ip-address
        instead of mac address as this is more human friendly.
        To make room, use scanner model instead of USB-id (which is bogus
        for network scanners
merge-requests/1/head
Louis Lagendijk 2009-03-17 19:29:39 +00:00
rodzic dd3db8d510
commit 0086173dd3
5 zmienionych plików z 348 dodań i 175 usunięć

Wyświetl plik

@ -1,3 +1,15 @@
2009-03-06 Louis Lagendijk <llagendijk-guest at users.alioth.debian.org>
* backend/pixma_bjnp.c backend/pixma_bjnp.h
backend/pixma_bjnp_private.h backend/pixma_io_sanei.c:
Make bjnp protocol more resilient against packet loss and corruption
Changed timeout for all responses to be at least 10 seconds
Send all broadcasts for scanner detection 5 times
Made sure scanners are added to device list only once
Changed device-id for bjnp so it uses scanner hostname/ip-address
instead of mac address as this is more human friendly.
To make room, use scanner model instead of USB-id (which is bogus
for network scanners
2009-03-17 m. allan noah <kitno455 a t gmail d o t com>
* doc/desc/gt68xx.desc, backend/gt68xx.conf.in: add NeatReceipts
Mobile Scanner (from Kelly Price)

Wyświetl plik

@ -181,6 +181,26 @@ static char *getusername(void)
return noname;
}
static char *truncate_hostname(char *hostname, char *short_hostname)
{
char *dot;
/* determine a short hostname (max HOSTNAME_SHORT_MAX chars */
strncpy(short_hostname, hostname, SHORT_HOSTNAME_MAX);
short_hostname[SHORT_HOSTNAME_MAX -1] = '\0';
if (strlen(hostname) > SHORT_HOSTNAME_MAX)
{
/* this is a hostname, not an ip-address, so remove domain part of the name */
if ((dot = index(short_hostname, '.')) != NULL )
*dot = '\0';
}
return short_hostname;
}
static int
bjnp_open_tcp (int devno)
{
@ -290,7 +310,7 @@ split_uri (const char *devname, char *method, char *hostname, int *port,
*/
if (next != ':')
port = 0;
*port = 0;
else
{
i = 0;
@ -334,15 +354,16 @@ set_cmd (int devno, struct BJNP_command *cmd, char cmd_code, int payload_len)
strncpy (cmd->BJNP_id, BJNP_STRING, sizeof (cmd->BJNP_id));
cmd->dev_type = BJNP_CMD_SCAN;
cmd->cmd_code = cmd_code;
cmd->unknown1 = htons(0);
if (devno == -1)
{
/* device not opened, use 0 for serial and session) */
cmd->seq_no = 0;
cmd->session_id = 0;
cmd->seq_no = htons(0);
cmd->session_id = htons(0);
}
else
{
cmd->seq_no = htonl (device[devno].serial++);
cmd->seq_no = htons (++(device[devno].serial));
cmd->session_id = htons (device[devno].session_id);
}
cmd->payload_len = htonl (payload_len);
@ -367,14 +388,14 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response,
int result;
int try, attempt;
PDBG (pixma_dbg (LOG_DEBUG, "Sending UDP command to %s:%d\n",
PDBG (pixma_dbg (LOG_DEBUG, "udp_command: Sending UDP command to %s:%d\n",
inet_ntoa (device[dev_no].addr.sin_addr),
ntohs (device[dev_no].addr.sin_port)));
if ((sockfd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
PDBG (pixma_dbg
(LOG_CRIT, "udp_command: sockfd - %s\n", strerror (errno)));
(LOG_CRIT, "udp_command: can not open socket - %s\n", strerror (errno)));
return -1;
}
@ -383,7 +404,7 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response,
(socklen_t) sizeof (struct sockaddr_in)) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT, "udp_command: connect - %s\n", strerror (errno)));
(LOG_CRIT, "udp_command: connect failed- %s\n", strerror (errno)));
return -1;
}
@ -392,8 +413,8 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response,
if ((numbytes = send (sockfd, command, cmd_len, 0)) != cmd_len)
{
PDBG (pixma_dbg
(LOG_CRIT, "udp_command: Sent only %d bytes of packet",
numbytes));
(LOG_CRIT, "udp_command: Sent only 0x%x = %d bytes of packet",
numbytes, numbytes));
continue;
}
@ -412,7 +433,7 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response,
if (result <= 0)
{
PDBG (pixma_dbg
(LOG_CRIT, "udpcommand: No data received (select): %s\n",
(LOG_CRIT, "udp_command: No data received (select): %s\n",
result == 0 ? "timed out" : strerror (errno)));
continue;
}
@ -434,11 +455,11 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response,
}
static int
get_scanner_id (const int dev_no, char *model, char *IEEE1284_id)
get_scanner_id (const int dev_no, char *model)
{
/*
* get scanner identity
* Sets model (make and model) and IEEE1284_id
* Sets model (make and model)
* Return 0 on success, -1 in case of errors
*/
@ -452,7 +473,6 @@ get_scanner_id (const int dev_no, char *model, char *IEEE1284_id)
/* set defaults */
strcpy (model, "Unidentified scanner");
strcpy (IEEE1284_id, "");
set_cmd (dev_no, &cmd, CMD_UDP_GET_ID, 0);
@ -472,22 +492,13 @@ get_scanner_id (const int dev_no, char *model, char *IEEE1284_id)
id = (struct IDENTITY *) resp_buf;
/* truncate string to be safe */
id->id[BJNP_IEEE1284_MAX -1] = '\0';
id_len = ntohs (id->id_len) - sizeof (id->id_len);
/* restrict length to size of buffer */
strcpy(scanner_id, id->id);
if (id_len >= BJNP_IEEE1284_MAX)
id_len = BJNP_IEEE1284_MAX - 1;
/* set IEEE1284_id */
strncpy (scanner_id, id->id, id_len);
scanner_id[id_len + 1] = '\0';
PDBG (pixma_dbg (LOG_INFO, "Identity = %s\n", scanner_id));
if (IEEE1284_id != NULL)
strcpy (IEEE1284_id, scanner_id);
PDBG (pixma_dbg (LOG_INFO, "Scanner identity string = %s\n", scanner_id));
/* get make&model from IEEE1284 id */
@ -563,7 +574,7 @@ parse_scanner_address (char *resp_buf, char *address, char *serial)
}
static int
bjnp_send_broadcast (struct in_addr local_addr, struct in_addr broadcast_addr,
bjnp_send_broadcast (struct in_addr local_addr, int local_port, struct in_addr broadcast_addr,
struct BJNP_command cmd, int size)
{
/*
@ -578,7 +589,7 @@ bjnp_send_broadcast (struct in_addr local_addr, struct in_addr broadcast_addr,
if ((sockfd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
PDBG (pixma_dbg
(LOG_CRIT, "discover_scanner: sockfd - %s", strerror (errno)));
(LOG_CRIT, "bjnp_send_broadcast: can not open socket - %s", strerror (errno)));
return -1;
}
@ -589,7 +600,7 @@ bjnp_send_broadcast (struct in_addr local_addr, struct in_addr broadcast_addr,
sizeof (broadcast)) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT, "discover_scanner: setsockopts - %s",
(LOG_CRIT, "bjnp_send_broadcast: setting socket options failed - %s",
strerror (errno)));
close (sockfd);
return -1;
@ -598,7 +609,7 @@ bjnp_send_broadcast (struct in_addr local_addr, struct in_addr broadcast_addr,
/* Bind to local address, use BJNP port */
sendaddr.sin_family = AF_INET;
sendaddr.sin_port = htons (BJNP_PORT_SCAN);
sendaddr.sin_port = htons (local_port);
sendaddr.sin_addr = local_addr;
memset (sendaddr.sin_zero, '\0', sizeof sendaddr.sin_zero);
@ -607,7 +618,7 @@ bjnp_send_broadcast (struct in_addr local_addr, struct in_addr broadcast_addr,
(socklen_t) sizeof (sendaddr)) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT, "discover_scanner: bind - %s\n", strerror (errno)));
(LOG_CRIT, "bjnp_send_broadcast: bind socket to local address failed - %s\n", strerror (errno)));
close (sockfd);
return -1;
}
@ -626,9 +637,9 @@ bjnp_send_broadcast (struct in_addr local_addr, struct in_addr broadcast_addr,
(struct sockaddr *) &sendaddr,
sizeof (sendaddr))) != size)
{
PDBG (pixma_dbg (LOG_NOTICE,
"discover_scanners: Sent only %d bytes of packet, error = %s\n",
numbytes, strerror (errno)));
PDBG (pixma_dbg (LOG_CRIT,
"bjnp_send_broadcasts: Sent only %x = %d bytes of packet, error = %s\n",
numbytes, numbytes, strerror (errno)));
/* not allowed, skip this interface */
close (sockfd);
@ -660,7 +671,7 @@ bjnp_finish_job (int devno)
{
PDBG (pixma_dbg
(LOG_CRIT,
"Received %d characters on close command, expected %d\n",
"Received %d characters on close scanjob command, expected %d\n",
resp_len, (int) sizeof (struct BJNP_command)));
return;
}
@ -819,14 +830,16 @@ bjnp_write (int devno, const SANE_Byte * buf, size_t count)
struct SCAN_BUF bjnp_buf;
if (device[devno].scanner_data_left)
PDBG (pixma_dbg (LOG_CRIT, "bjnp_write: ERROR scanner data left = %lx\n",
(long) device[devno].scanner_data_left));
PDBG (pixma_dbg (LOG_CRIT, "bjnp_write: ERROR scanner data left = 0x%lx = %ld\n",
(long) device[devno].scanner_data_left,
(long) device[devno].scanner_data_left));
/* set BJNP command header */
set_cmd (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_SEND, count);
memcpy (bjnp_buf.scan_data, buf, count);
PDBG (pixma_dbg (LOG_DEBUG, "bjnp_write: sending %d bytes\n", (int) count);
PDBG (pixma_dbg (LOG_DEBUG, "bjnp_write: sending 0x%lx = %ld bytes\n",
(long) count, (long) count);
PDBG( pixma_hexdump (LOG_DEBUG2, (char *) &bjnp_buf,
sizeof (struct BJNP_command) + count)));
@ -865,14 +878,15 @@ bjnp_send_read_request (int devno)
if (device[devno].scanner_data_left)
PDBG (pixma_dbg
(LOG_CRIT, "bjnp_send_request: ERROR scanner data left = %lx\n",
(LOG_CRIT, "bjnp_send_read_request: ERROR scanner data left = 0x%lx = %ld\n",
(long) device[devno].scanner_data_left,
(long) device[devno].scanner_data_left));
/* set BJNP command header */
set_cmd (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_REQ, 0);
PDBG (pixma_dbg (LOG_DEBUG, "bjnp_send_req sending command\n"));
PDBG (pixma_dbg (LOG_DEBUG, "bjnp_send_read_req sending command\n"));
PDBG(pixma_hexdump (LOG_DEBUG2, (char *) &bjnp_buf,
sizeof (struct BJNP_command)));
@ -883,7 +897,7 @@ bjnp_send_read_request (int devno)
/* return result from write */
terrno = errno;
PDBG (pixma_dbg
(LOG_CRIT, "bjnp_send_request: Could not send data!\n"));
(LOG_CRIT, "bjnp_send_read_request: Could not send data!\n"));
errno = terrno;
return -1;
}
@ -915,7 +929,8 @@ bjnp_recv_header (int devno)
if (device[devno].scanner_data_left)
PDBG (pixma_dbg
(LOG_CRIT, "bjnp_send_request: ERROR scanner data left = %lx\n",
(LOG_CRIT, "bjnp_send_request: ERROR scanner data left = 0x%lx = %ld\n",
(long) device[devno].scanner_data_left,
(long) device[devno].scanner_data_left));
attempt = 0;
@ -931,15 +946,24 @@ bjnp_recv_header (int devno)
while (((result = select (fd + 1, &input, NULL, NULL, &timeout)) == -1) &&
(errno == EINTR) && (attempt++ < MAX_SELECT_ATTEMPTS));
if (result <= 0)
if (result < 0)
{
terrno = (result == 0) ? EAGAIN : errno;
terrno = errno;
PDBG (pixma_dbg (LOG_CRIT,
"bjnp_recv_header: could not read response header (select): %s!\n",
strerror (terrno)));
errno = terrno;
return SANE_STATUS_IO_ERROR;
}
else if (result == 0)
{
terrno = errno;
PDBG (pixma_dbg (LOG_CRIT,
"bjnp_recv_header: could not read response header (select timed out): %s!\n",
strerror (terrno)));
errno = terrno;
return SANE_STATUS_IO_ERROR;
}
/* get response header */
@ -963,11 +987,20 @@ bjnp_recv_header (int devno)
{
PDBG (pixma_dbg
(LOG_CRIT,
"ERROR: Received response has cmd code %d, expected %d\n",
"bjnp_recv_header:ERROR, Received response has cmd code %d, expected %d\n",
resp_buf.cmd_code, device[devno].last_cmd));
return SANE_STATUS_IO_ERROR;
}
if (ntohs(resp_buf.seq_no) != (uint16_t) device[devno].serial)
{
PDBG (pixma_dbg
(LOG_CRIT,
"bjnp_recv_header:ERROR, Received response has serial %d, expected %d\n",
(int) ntohs(resp_buf.seq_no), (int)device[devno].serial));
return SANE_STATUS_IO_ERROR;
}
/* got response header back, retrieve length of scanner data */
@ -1000,7 +1033,7 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t * len)
fd = device[devno].fd;
PDBG (pixma_dbg
(LOG_DEBUG, "bjnp_recv_data: read response payload (%ld bytes)\n",
(LOG_DEBUG, "bjnp_recv_data: read response payload (%ld bytes max)\n",
(long) *len));
attempt = 0;
@ -1016,9 +1049,9 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t * len)
while (((result = select (fd + 1, &input, NULL, NULL, &timeout)) == -1) &&
(errno == EINTR) && (attempt++ < MAX_SELECT_ATTEMPTS));
if (result <= 0)
if (result < 0)
{
terrno = (result == 0) ? EAGAIN : errno;
terrno = errno;
PDBG (pixma_dbg (LOG_CRIT,
"bjnp_recv_data: could not read response payload (select): %s!\n",
strerror (errno)));
@ -1026,6 +1059,16 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t * len)
*len = 0;
return SANE_STATUS_IO_ERROR;
}
else if (result == 0)
{
terrno = errno;
PDBG (pixma_dbg (LOG_CRIT,
"bjnp_recv_data: could not read response payload (select timed out): %s!\n",
strerror (terrno)));
errno = terrno;
*len = 0;
return SANE_STATUS_IO_ERROR;
}
if ((recv_bytes = recv (fd, buffer, *len, 0)) < 0)
{
@ -1048,8 +1091,8 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t * len)
return SANE_STATUS_GOOD;
}
static SANE_Status
sanei_bjnp_attach (SANE_String_Const devname, SANE_Int * dn)
static BJNP_Status
bjnp_allocate_device (SANE_String_Const devname, SANE_Int * dn, char *res_hostname)
{
char method[256];
char hostname[256];
@ -1057,34 +1100,30 @@ sanei_bjnp_attach (SANE_String_Const devname, SANE_Int * dn)
char args[256];
struct hostent *result;
struct in_addr *addr_list;
int i;
PDBG (pixma_dbg (LOG_DEBUG, "bjnp_allocate_device(%s)", devname ));
if (split_uri (devname, method, hostname, &port, args) != 0)
{
PDBG (pixma_dbg (LOG_CRIT, "Can not parse scanner URI: %s", devname));
return SANE_STATUS_INVAL;
return BJNP_STATUS_INVAL;
}
if (strlen (args) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT, "URI may not contain userid, password or aguments: %s",
(LOG_CRIT, "URI may not contain userid, password or aguments: %s\n",
devname));
return SANE_STATUS_INVAL;
return BJNP_STATUS_INVAL;
}
if (strcmp (method, BJNP_METHOD) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT, "URI %s contains invalid method: %s", devname,
(LOG_CRIT, "URI %s contains invalid method: %s\n", devname,
method));
return SANE_STATUS_INVAL;
return BJNP_STATUS_INVAL;
}
*dn = first_free_device;
first_free_device++;
/*
* fill device structure
* TODO: implement scanning of ALL returned addressess
*/
result = gethostbyname (hostname);
if ((result == NULL) || result->h_addrtype != AF_INET)
@ -1097,6 +1136,38 @@ sanei_bjnp_attach (SANE_String_Const devname, SANE_Int * dn)
port = BJNP_PORT_SCAN;
}
addr_list = (struct in_addr *) *result->h_addr_list;
/* Check if a device number is already allocated */
for (i = 0; i < first_free_device; i++)
{
/* check address, AF_INET is assumed */
if ((device[i].addr.sin_port == htons (port)) &&
(device[i].addr.sin_addr.s_addr == addr_list[0].s_addr))
{
*dn = i;
return BJNP_STATUS_ALREADY_ALLOCATED;
}
}
/* return hostname if required */
if (res_hostname != NULL)
strcpy(res_hostname, hostname);
/*
* No existing device structure found, fill new device structure
*/
if (first_free_device == BJNP_NO_DEVICES)
{
PDBG (pixma_dbg
(LOG_CRIT, "Too many devices, ran out of device structures, can not add %s\n", devname));
return BJNP_STATUS_INVAL;
}
*dn = first_free_device++;
device[*dn].open = 1;
device[*dn].active = 0;
#ifdef PIXMA_BJNP_STATUS
@ -1104,24 +1175,24 @@ sanei_bjnp_attach (SANE_String_Const devname, SANE_Int * dn)
device[*dn].dialogue = 0;
#endif
device[*dn].fd = -1;
addr_list = (struct in_addr *) *result->h_addr_list;
device[*dn].addr.sin_family = AF_INET;
device[*dn].addr.sin_port = htons (port);
device[*dn].addr.sin_addr = addr_list[0];
device[*dn].session_id = 0;
device[*dn].serial = 0;
device[*dn].serial = -1;
device[*dn].bjnp_timeout_sec = 1;
device[*dn].bjnp_timeout_msec = 0;
device[*dn].scanner_data_left = 0;
device[*dn].last_cmd = 0;
/* we make a worst case guess on blocksize, will be corrected to max size
/* we make a pessimistic guess on blocksize, will be corrected to max size
* of received block when we read data */
device[*dn].blocksize = 1024;
device[*dn].short_read = 0;
return SANE_STATUS_GOOD;
return BJNP_STATUS_GOOD;
}
/*
@ -1159,20 +1230,19 @@ sanei_bjnp_find_devices (const char **conf_devices,
{
int numbytes = 0;
struct BJNP_command cmd;
int num_scanners = 0;
char resp_buf[2048];
int socket_fd[BJNP_SOCK_MAX];
int no_sockets;
int i;
int attempt;
int last_socketfd = 0;
fd_set fdset;
fd_set active_fdset;
struct timeval timeout;
char hostname[256];
char short_hostname[SHORT_HOSTNAME_MAX];
char makemodel[BJNP_IEEE1284_MAX];
char IEEE1284_id[BJNP_IEEE1284_MAX];
char uri[256];
int result;
int dev_no;
char serial[13];
#ifdef HAVE_IFADDRS_H
@ -1184,6 +1254,53 @@ sanei_bjnp_find_devices (const char **conf_devices,
#endif
PDBG (pixma_dbg (LOG_INFO, "sanei_bjnp_find_devices:\n"));
first_free_device = 0;
/* First add devices from config file */
for (i = 0; conf_devices[i] != NULL; i++)
{
PDBG (pixma_dbg
(LOG_DEBUG, "Adding configured scanner: %s\n",
conf_devices[i]));
/* Allocate device structure for scanner and read its model */
switch (bjnp_allocate_device (conf_devices[i], &dev_no, hostname))
{
case BJNP_STATUS_GOOD:
if (get_scanner_id (dev_no, makemodel) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT,
"Cannot read scanner make & model: %s\n", uri));
}
else
{
/*
* inform caller of found scanner
*/
truncate_hostname(hostname, short_hostname);
attach_bjnp (conf_devices[i], makemodel,
short_hostname, pixma_devices);
}
break;
case BJNP_STATUS_ALREADY_ALLOCATED:
PDBG (pixma_dbg
(LOG_NOTICE,
"Scanner at %s defined in configuration file, but it was added before, good!\n",
uri));
break;
case BJNP_STATUS_INVAL:
PDBG (pixma_dbg
(LOG_NOTICE,
"Scanner at %s defined in configuration file, but can not add it\n",
uri));
break;
}
}
PDBG (pixma_dbg (LOG_DEBUG, "Added all configured scanners, now do auto detection...\n"));
/*
* Send UDP broadcast to discover scanners and return the list of scanners found
@ -1194,10 +1311,15 @@ sanei_bjnp_find_devices (const char **conf_devices,
set_cmd (-1, &cmd, CMD_UDP_DISCOVER, 0);
#ifdef HAVE_IFADDRS_H
no_sockets = 0;
getifaddrs (&interfaces);
/* send MAX_SELECT_ATTEMPTS broadcasts on each suitable interface */
for (attempt = 0; attempt < MAX_SELECT_ATTEMPTS; attempt++)
{
interface = interfaces;
for (no_sockets = 0; (no_sockets < BJNP_SOCK_MAX) && (interface != NULL);)
while ((no_sockets < BJNP_SOCK_MAX) && (interface != NULL))
{
/* send broadcast packet to each suitable interface */
@ -1221,7 +1343,8 @@ sanei_bjnp_find_devices (const char **conf_devices,
if ((socket_fd[no_sockets] =
bjnp_send_broadcast (((struct sockaddr_in *) interface->
ifa_addr)->sin_addr,
ifa_addr)->sin_addr,
BJNP_PORT_BROADCAST_BASE + attempt,
((struct sockaddr_in *) interface->
ifa_broadaddr)->sin_addr,
cmd, sizeof (cmd))) != -1)
@ -1238,7 +1361,9 @@ sanei_bjnp_find_devices (const char **conf_devices,
}
interface = interface->ifa_next;
}
/* wait for some time between broadcast packets */
usleep (100 * USLEEP_MS);
}
freeifaddrs (interfaces);
#else
/* we have no easy way to find interfaces with their broadcast addresses, use global broadcast */
@ -1247,24 +1372,29 @@ sanei_bjnp_find_devices (const char **conf_devices,
broadcast.s_addr = htonl(INADDR_BROADCAST);
local.s_addr = htonl(INADDR_ANY);
if ((socket_fd[no_sockets] =
bjnp_send_broadcast (local, broadcast, cmd, sizeof (cmd))) != -1)
for (attempt = 0; attempt < MAX_SELECT_ATTEMPTS; attempt++)
{
if (socket_fd[no_sockets] > last_socketfd)
{
/* track highest used socket for use in select */
if ((socket_fd[no_sockets] =
bjnp_send_broadcast (local, BJNP_PORT_BROADCAST_BASE + attempt, broadcast, cmd, sizeof (cmd))) != -1)
{
if (socket_fd[no_sockets] > last_socketfd)
{
/* track highest used socket for use in select */
last_socketfd = socket_fd[no_sockets];
}
FD_SET (socket_fd[no_sockets], &fdset);
no_sockets++;
last_socketfd = socket_fd[no_sockets];
}
FD_SET (socket_fd[no_sockets], &fdset);
no_sockets++;
}
/* wait for some time between broadcast packets */
usleep (100 * USLEEP_MS);
}
#endif
/* wait for up to 1 second for a UDP response */
/* wait for up to 0.5 second for a UDP response */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
timeout.tv_sec = 0;
timeout.tv_usec = 500 * USLEEP_MS;
active_fdset = fdset;
@ -1281,7 +1411,7 @@ sanei_bjnp_find_devices (const char **conf_devices,
0)) == -1)
{
PDBG (pixma_dbg
(LOG_CRIT, "discover_scanners: no data received"));
(LOG_CRIT, "bjnp_send_broadcasts: no data received"));
break;
}
else
@ -1293,7 +1423,7 @@ sanei_bjnp_find_devices (const char **conf_devices,
if ((numbytes != sizeof (struct DISCOVER_RESPONSE))
|| (strncmp ("BJNP", resp_buf, 4) != 0))
{
/* scanner not found */
/* not a valid response, assume not a scanner */
break;
}
};
@ -1306,28 +1436,42 @@ sanei_bjnp_find_devices (const char **conf_devices,
BJNP_PORT_SCAN);
/* Test scanner connection by attaching it and reading its IEEE1284 id */
if ((result =
sanei_bjnp_attach (uri, &dev_no)) != SANE_STATUS_GOOD)
{
PDBG (pixma_dbg
switch (bjnp_allocate_device (uri, &dev_no, NULL))
{
case BJNP_STATUS_GOOD:
if (get_scanner_id (dev_no, makemodel) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT,
"Scanner not added: Cannot read scanner make & model: %s\n", uri));
}
else
{
/*
* inform caller of found scanner
*/
truncate_hostname(hostname, short_hostname);
attach_bjnp (uri, makemodel, short_hostname,
pixma_devices);
}
break;
case BJNP_STATUS_INVAL:
PDBG (pixma_dbg
(LOG_NOTICE,
"Found scanner at %s, but can not open it\n", uri));
}
else
{
if (get_scanner_id (dev_no, makemodel, IEEE1284_id) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT,
"Cannot read scanner make & model: %s\n", uri));
return SANE_STATUS_INVAL;
}
/*
* inform caller of found scanner
*/
attach_bjnp (uri, makemodel, serial, pixma_devices);
num_scanners++;
}
break;
case BJNP_STATUS_ALREADY_ALLOCATED:
/* already allocated before, no action required */
PDBG (pixma_dbg
(LOG_NOTICE,
"Scanner at %s detected, but it was added before, good!\n",
uri));
break;
}
}
}
active_fdset = fdset;
@ -1339,38 +1483,6 @@ sanei_bjnp_find_devices (const char **conf_devices,
for (i = 0; i < no_sockets; i++)
close (socket_fd[i]);
/* add pre-configured devices */
for (i = 0; conf_devices[i] != NULL; i++)
{
PDBG (pixma_dbg
(LOG_DEBUG, "Adding pre-configured scanner: %s\n",
conf_devices[i]));
/* Test scanner connection by attaching it and reading its IEEE1284 id */
if ((result = sanei_bjnp_attach (conf_devices[i], &dev_no)) != SANE_STATUS_GOOD)
{
PDBG (pixma_dbg
(LOG_NOTICE,
"Scanner at %s defined in configuration file, but can not open it\n",
uri));
}
else
{
if (get_scanner_id (dev_no, makemodel, IEEE1284_id) != 0)
{
PDBG (pixma_dbg
(LOG_CRIT,
"Cannot read scanner make & model: %s\n", uri));
return SANE_STATUS_INVAL;
}
/*
* inform caller of found scanner
*/
attach_bjnp (conf_devices[i], makemodel, serial, pixma_devices);
num_scanners++;
}
}
return SANE_STATUS_GOOD;
}
@ -1400,21 +1512,20 @@ extern SANE_Status
sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn)
{
char pid_str[64];
char hostname[256];
char my_hostname[256];
char *login;
PDBG (pixma_dbg (LOG_INFO, "sanei_bjnp_open(%s, %d):\n", devname, *dn));
/* TODO: check result of sanei_bjnp_attach! */
sanei_bjnp_attach (devname, dn);
if (bjnp_allocate_device (devname, dn, NULL) == BJNP_STATUS_INVAL)
return SANE_STATUS_INVAL;
login = getusername ();
gethostname (hostname, 256);
hostname[255] = '\0';
gethostname (my_hostname, 256);
my_hostname[255] = '\0';
sprintf (pid_str, "Process ID = %d", getpid ());
bjnp_send_job_details (*dn, hostname, login, pid_str);
bjnp_send_job_details (*dn, my_hostname, login, pid_str);
if (bjnp_open_tcp (*dn) != 0)
return SANE_STATUS_INVAL;
@ -1484,12 +1595,17 @@ SANE_Status sanei_bjnp_deactivate(SANE_Int dn)
extern void
sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout)
{
/* timeout must be at least 1 second */
if (timeout < 1000)
timeout = 1000;
PDBG (pixma_dbg (LOG_INFO, "bjnp_set_timeout(%d):\n", timeout));
device[devno].bjnp_timeout_sec = timeout / 1000;
device[devno].bjnp_timeout_msec = timeout % 1000;
int my_timeout = timeout;
/* timeout must be at least 10 second */
if (my_timeout < 10000)
my_timeout = 10000;
PDBG (pixma_dbg (LOG_INFO, "bjnp_set_timeout(requested %d, set %d):\n",
timeout, my_timeout));
device[devno].bjnp_timeout_sec = my_timeout / 1000;
device[devno].bjnp_timeout_msec = my_timeout % 1000;
}
/** Initiate a bulk transfer read.
@ -1509,8 +1625,6 @@ sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout)
*
*/
#define USLEEP_MS 1000
extern SANE_Status
sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size)
{
@ -1521,25 +1635,39 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size)
size_t left;
PDBG (pixma_dbg
(LOG_INFO, "bjnp_read_bulk(%d, bufferptr, %lx)\n", dn, (long) *size));
(LOG_DEBUG, "bjnp_read_bulk(%d, bufferptr, 0x%lx = %ld)\n", dn,
(long) *size, (long) size));
recvd = 0;
left = *size;
if (!device[dn].scanner_data_left)
device[dn].short_read = 0;
if ((device[dn].scanner_data_left == 0) && (device[dn].short_read != 0))
{
/* new read, but we have no data queued from scanner, last read was short, */
/* so scanner needs first a high level read command. This is not an error */
PDBG (pixma_dbg
(LOG_DEBUG, "Scanner has no more data available, return immediately!\n"));
*size = 0;
return SANE_STATUS_EOF;
}
PDBG (pixma_dbg
(LOG_DEBUG, "bjnp_read_bulk: %lx bytes available at start\n",
(long) device[dn].scanner_data_left));
(LOG_DEBUG, "bjnp_read_bulk: 0x%lx = %ld bytes available at start, "
"Short block = %d blocksize = 0x%lx = %ld\n",
(long) device[dn].scanner_data_left,
(long) device[dn].scanner_data_left,
(int) device[dn].short_read,
(long) device[dn].blocksize,
(long) device[dn].blocksize));
while ((recvd < *size)
&& (!device[dn].short_read || device[dn].scanner_data_left))
{
PDBG (pixma_dbg
(LOG_DEBUG,
"So far received %lx bytes, need %lx\n",
(long) recvd, (long) *size));
"So far received 0x%lx bytes = %ld, need 0x%lx = %ld\n",
(long) recvd, (long) recvd, (long) *size, (long) *size));
if (device[dn].scanner_data_left == 0)
{
@ -1552,12 +1680,19 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size)
(LOG_DEBUG, "No (more) scanner data available, requesting more\n"));
if ((error = bjnp_send_read_request (dn)) != SANE_STATUS_GOOD)
return SANE_STATUS_IO_ERROR;
{
*size = recvd;
return SANE_STATUS_IO_ERROR;
}
if ((error = bjnp_recv_header (dn)) != SANE_STATUS_GOOD)
return SANE_STATUS_IO_ERROR;
{
*size = recvd;
return SANE_STATUS_IO_ERROR;
}
PDBG (pixma_dbg
(LOG_DEBUG, "Scanner reports %lx bytes available\n", (long) device[dn].scanner_data_left));
(LOG_DEBUG, "Scanner reports 0x%lx = %ld bytes available\n",
(long) device[dn].scanner_data_left,
(long) device[dn].scanner_data_left));
/* correct blocksize if more data is sent by scanner than current blocksize assumption */
@ -1572,8 +1707,10 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size)
more = left;
PDBG (pixma_dbg (LOG_DEBUG, "reading %lx (of %ld) bytes more\n",
(long) more, device[dn].scanner_data_left));
PDBG (pixma_dbg (LOG_DEBUG, "reading 0x%lx = %ld (of max 0x%lx = %ld) bytes more\n",
device[dn].scanner_data_left,
device[dn].scanner_data_left,
(long) more, (long) more ));
result = bjnp_recv_data (dn, buffer, &more);
if (result != SANE_STATUS_GOOD)
{
@ -1612,7 +1749,8 @@ sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size)
uint32_t buf;
PDBG (pixma_dbg
(LOG_INFO, "bjnp_write_bulk(%d, bufferptr, %d):\n", dn, (int) *size));
(LOG_INFO, "bjnp_write_bulk(%d, bufferptr, 0x%lx = %ld)\n", dn,
(long) *size, (long)*size));
sent = bjnp_write (dn, buffer, *size);
if (sent < 0)
return SANE_STATUS_IO_ERROR;
@ -1632,7 +1770,8 @@ sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size)
if (device[dn].scanner_data_left != 4)
{
PDBG(pixma_dbg (LOG_CRIT,
"Scanner length of write confirmation = %ld bytes, expected %d!!\n",
"Scanner length of write confirmation = 0x%lx bytes = %ld, expected %d!!\n",
(long) device[dn].scanner_data_left,
(long) device[dn].scanner_data_left, 4));
return SANE_STATUS_IO_ERROR;
}
@ -1651,6 +1790,11 @@ sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size)
(long) recvd, (long) *size));
return SANE_STATUS_IO_ERROR;
}
/* we sent a new command, so reset end of block indication */
device[dn].short_read = 0;
return SANE_STATUS_GOOD;
}
@ -1676,7 +1820,9 @@ sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size)
{
#ifndef PIXMA_BJNP_STATUS
PDBG (pixma_dbg
(LOG_INFO, "bjnp_read_int(%d, bufferptr, %d):\n", dn, (int) *size));
(LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn,
(long) *size,
(long) *size));
memset (buffer, 0, *size);
sleep (1);
return SANE_STATUS_IO_ERROR;
@ -1686,7 +1832,8 @@ sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size)
int i;
PDBG (pixma_dbg
(LOG_INFO, "bjnp_read_int(%d, bufferptr, %d):\n", dn, (int) *size));
(LOG_INFO, "bjnp_read_int(%d, bufferptr, %lx = %ld):\n", dn,
(long) *size, (long) *size));
gethostname (hostname, 32);
hostname[32] = '\0';

Wyświetl plik

@ -66,13 +66,17 @@ extern void sanei_bjnp_init (void);
/** Find scanners responding to a BJNP broadcast.
*
* The function attach is called for every device which has been found.
*
* Serial is the address of the pinter in himan readable form of max
* SHORT_HOSTNAME_MAX characters
* @param conf_devices lsit of pre-configures device URI's to attach
* @param attach attach function
* @param pixma_devices device informatio needed by attach function
*
* @return SANE_STATUS_GOOD - on success (even if no scanner was found)
*/
#define SHORT_HOSTNAME_MAX 16
extern SANE_Status
sanei_bjnp_find_devices (const char **conf_devices,
SANE_Status (*attach_bjnp)

Wyświetl plik

@ -65,6 +65,7 @@
#define BJNP_NO_DEVICES 16 /* max number of open devices */
#define SCAN_BUF_MAX 65536 /* size of scanner data intermediate buffer */
#define MAX_SELECT_ATTEMPTS 5 /* max nr of retries on select (EINTR) */
#define USLEEP_MS 1000 /* sleep for 1 msec */
/* Do not yet use this, it does not work */
/* #define PIXMA_BJNP_STATUS 1 */
@ -85,6 +86,7 @@
/* port numbers */
typedef enum bjnp_port_e
{
BJNP_PORT_BROADCAST_BASE = 8610,
BJNP_PORT_PRINT = 8611,
BJNP_PORT_SCAN = 8612,
BJNP_PORT_3 = 8613,
@ -123,7 +125,8 @@ struct BJNP_command
char BJNP_id[4]; /* string: BJNP */
uint8_t dev_type; /* 1 = printer, 2 = scanner */
uint8_t cmd_code; /* command code/response code */
uint32_t seq_no; /* sequence number */
int16_t unknown1; /* unknown, always 0? */
int16_t seq_no; /* sequence number */
uint16_t session_id; /* session id for printing */
uint32_t payload_len; /* length of command buffer */
} __attribute__ ((__packed__));
@ -199,6 +202,13 @@ typedef enum bjnp_paper_status_e
BJNP_PAPER_OUT = 1
} bjnp_paper_status_t;
typedef enum
{
BJNP_STATUS_GOOD,
BJNP_STATUS_INVAL,
BJNP_STATUS_ALREADY_ALLOCATED
} BJNP_Status;
/*
* Device information for opened devices
*/
@ -210,7 +220,7 @@ typedef struct device_s
int fd; /* file descriptor */
struct sockaddr_in addr;
int session_id; /* session id used in bjnp protocol for TCP packets */
uint32_t serial; /* sequence number of command */
int16_t serial; /* sequence number of command */
int bjnp_timeout_sec; /* timeout (seconds) for next command */
int bjnp_timeout_msec; /* timeout (msec) for next command */
size_t scanner_data_left; /* TCP data left from last read request */

Wyświetl plik

@ -164,7 +164,7 @@ attach_bjnp (SANE_String_Const devname, SANE_String_Const makemodel,
if ((cfg = lookup_scanner(makemodel, pixma_devices)) == (struct pixma_config_t *)NULL)
return SANE_STATUS_INVAL;
si->cfg = cfg;
sprintf(si->serial, "%04x%04x_%s", (unsigned int) cfg->vid, (unsigned int) cfg->pid, serial);
sprintf(si->serial, "%s_%s", cfg->model, serial);
si -> interface = INT_BJNP;
si->next = first_scanner;
first_scanner = si;