diff options
Diffstat (limited to 'frontend/saned.c')
-rw-r--r-- | frontend/saned.c | 361 |
1 files changed, 200 insertions, 161 deletions
diff --git a/frontend/saned.c b/frontend/saned.c index e31758a..d71d428 100644 --- a/frontend/saned.c +++ b/frontend/saned.c @@ -53,6 +53,7 @@ #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <string.h> #include <syslog.h> #include <time.h> @@ -257,6 +258,7 @@ static int data_connect_timeout = 4000; static Handle *handle; static char *bind_addr; static short bind_port = -1; +static size_t buffer_size = (1 * 1024 * 1024); static union { int w; @@ -1651,168 +1653,186 @@ store_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen) static void do_scan (Wire * w, int h, int data_fd) { - int num_fds, be_fd = -1, reader, writer, bytes_in_buf, status_dirty = 0; + int num_fds, be_fd = -1, reader, bytes_in_buf, status_dirty = 0; + size_t writer; SANE_Handle be_handle = handle[h].handle; struct timeval tv, *timeout = 0; fd_set rd_set, rd_mask, wr_set, wr_mask; - SANE_Byte buf[8192]; + SANE_Byte *buf = NULL; SANE_Status status; - long int nwritten; + ssize_t nwritten; SANE_Int length; size_t nbytes; DBG (3, "do_scan: start\n"); - FD_ZERO (&rd_mask); - FD_SET (w->io.fd, &rd_mask); - num_fds = w->io.fd + 1; - - FD_ZERO (&wr_mask); - FD_SET (data_fd, &wr_mask); - if (data_fd >= num_fds) - num_fds = data_fd + 1; - - sane_set_io_mode (be_handle, SANE_TRUE); - if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD) + /* + * Allocate the read buffer. + * + */ + buf = malloc (buffer_size); + if (!buf) { - FD_SET (be_fd, &rd_mask); - if (be_fd >= num_fds) - num_fds = be_fd + 1; + status = SANE_STATUS_NO_MEM; + DBG (DBG_ERR, "do_scan: failed to allocate read buffer (%zu bytes)\n", + buffer_size); } else { - memset (&tv, 0, sizeof (tv)); - timeout = &tv; - } + FD_ZERO(&rd_mask); + FD_SET(w->io.fd, &rd_mask); + num_fds = w->io.fd + 1; - status = SANE_STATUS_GOOD; - reader = writer = bytes_in_buf = 0; - do - { - rd_set = rd_mask; - wr_set = wr_mask; - if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0) - { - if (be_fd >= 0 && errno == EBADF) - { - /* This normally happens when a backend closes a select - filedescriptor when reaching the end of file. So - pass back this status to the client: */ - FD_CLR (be_fd, &rd_mask); - be_fd = -1; - /* only set status_dirty if EOF hasn't been already detected */ - if (status == SANE_STATUS_GOOD) - status_dirty = 1; - status = SANE_STATUS_EOF; - DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n"); - continue; - } - else - { - status = SANE_STATUS_IO_ERROR; - DBG (DBG_ERR, "do_scan: select failed (%s)\n", strerror (errno)); - break; - } - } + FD_ZERO(&wr_mask); + FD_SET(data_fd, &wr_mask); + if (data_fd >= num_fds) + num_fds = data_fd + 1; - if (bytes_in_buf) - { - if (FD_ISSET (data_fd, &wr_set)) - { - if (bytes_in_buf > 0) - { - /* write more input data */ - nbytes = bytes_in_buf; - if (writer + nbytes > sizeof (buf)) - nbytes = sizeof (buf) - writer; - DBG (DBG_INFO, - "do_scan: trying to write %d bytes to client\n", - nbytes); - nwritten = write (data_fd, buf + writer, nbytes); - DBG (DBG_INFO, - "do_scan: wrote %ld bytes to client\n", nwritten); - if (nwritten < 0) - { - DBG (DBG_ERR, "do_scan: write failed (%s)\n", - strerror (errno)); - status = SANE_STATUS_CANCELLED; - handle[h].docancel = 1; - break; - } - bytes_in_buf -= nwritten; - writer += nwritten; - if (writer == sizeof (buf)) - writer = 0; - } - } - } - else if (status == SANE_STATUS_GOOD - && (timeout || FD_ISSET (be_fd, &rd_set))) - { - int i; + sane_set_io_mode (be_handle, SANE_TRUE); + if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD) + { + FD_SET(be_fd, &rd_mask); + if (be_fd >= num_fds) + num_fds = be_fd + 1; + } + else + { + memset (&tv, 0, sizeof(tv)); + timeout = &tv; + } - /* get more input data */ + status = SANE_STATUS_GOOD; + reader = writer = bytes_in_buf = 0; + do + { + rd_set = rd_mask; + wr_set = wr_mask; + if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0) + { + if (be_fd >= 0 && errno == EBADF) + { + /* This normally happens when a backend closes a select + filedescriptor when reaching the end of file. So + pass back this status to the client: */ + FD_CLR(be_fd, &rd_mask); + be_fd = -1; + /* only set status_dirty if EOF hasn't been already detected */ + if (status == SANE_STATUS_GOOD) + status_dirty = 1; + status = SANE_STATUS_EOF; + DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n"); + continue; + } + else + { + status = SANE_STATUS_IO_ERROR; + DBG (DBG_ERR, "do_scan: select failed (%s)\n", + strerror (errno)); + break; + } + } - /* reserve 4 bytes to store the length of the data record: */ - i = reader; - reader += 4; - if (reader >= (int) sizeof (buf)) - reader -= sizeof(buf); + if (bytes_in_buf) + { + if (FD_ISSET(data_fd, &wr_set)) + { + if (bytes_in_buf > 0) + { + /* write more input data */ + nbytes = bytes_in_buf; + if (writer + nbytes > buffer_size) + nbytes = buffer_size - writer; + DBG (DBG_INFO, + "do_scan: trying to write %d bytes to client\n", + nbytes); + nwritten = write (data_fd, buf + writer, nbytes); + DBG (DBG_INFO, "do_scan: wrote %ld bytes to client\n", + nwritten); + if (nwritten < 0) + { + DBG (DBG_ERR, "do_scan: write failed (%s)\n", + strerror (errno)); + status = SANE_STATUS_CANCELLED; + handle[h].docancel = 1; + break; + } + bytes_in_buf -= (size_t) nwritten; + writer += (size_t) nwritten; + if (writer == buffer_size) + writer = 0; + } + } + } + else if (status == SANE_STATUS_GOOD + && (timeout || FD_ISSET(be_fd, &rd_set))) + { + int i; - assert (bytes_in_buf == 0); - nbytes = sizeof (buf) - 4; - if (reader + nbytes > sizeof (buf)) - nbytes = sizeof (buf) - reader; + /* get more input data */ - DBG (DBG_INFO, - "do_scan: trying to read %d bytes from scanner\n", nbytes); - status = sane_read (be_handle, buf + reader, nbytes, &length); - DBG (DBG_INFO, - "do_scan: read %d bytes from scanner\n", length); + /* reserve 4 bytes to store the length of the data record: */ + i = reader; + reader += 4; + if (reader >= (int) buffer_size) + reader -= buffer_size; - reset_watchdog (); + assert(bytes_in_buf == 0); + nbytes = buffer_size - 4; + if (reader + nbytes > buffer_size) + nbytes = buffer_size - reader; - reader += length; - if (reader >= (int) sizeof (buf)) - reader = 0; - bytes_in_buf += length + 4; + DBG (DBG_INFO, "do_scan: trying to read %d bytes from scanner\n", + nbytes); + status = sane_read (be_handle, buf + reader, nbytes, &length); + DBG (DBG_INFO, "do_scan: read %d bytes from scanner\n", length); - if (status != SANE_STATUS_GOOD) - { - reader = i; /* restore reader index */ - status_dirty = 1; - DBG (DBG_MSG, - "do_scan: status = `%s'\n", sane_strstatus(status)); - } - else - store_reclen (buf, sizeof (buf), i, length); - } + reset_watchdog (); - if (status_dirty && sizeof (buf) - bytes_in_buf >= 5) - { - status_dirty = 0; - reader = store_reclen (buf, sizeof (buf), reader, 0xffffffff); - buf[reader] = status; - bytes_in_buf += 5; - DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n", - sane_strstatus(status)); - } + reader += length; + if (reader >= (int) buffer_size) + reader = 0; + bytes_in_buf += length + 4; - if (FD_ISSET (w->io.fd, &rd_set)) - { - DBG (DBG_MSG, - "do_scan: processing RPC request on fd %d\n", w->io.fd); - if(process_request (w) < 0) - handle[h].docancel = 1; + if (status != SANE_STATUS_GOOD) + { + reader = i; /* restore reader index */ + status_dirty = 1; + DBG (DBG_MSG, "do_scan: status = `%s'\n", + sane_strstatus (status)); + } + else + store_reclen (buf, buffer_size, i, length); + } - if (handle[h].docancel) - break; - } + if (status_dirty && buffer_size - bytes_in_buf >= 5) + { + status_dirty = 0; + reader = store_reclen (buf, buffer_size, reader, 0xffffffff); + buf[reader] = status; + bytes_in_buf += 5; + DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n", + sane_strstatus (status)); + } + + if (FD_ISSET(w->io.fd, &rd_set)) + { + DBG (DBG_MSG, "do_scan: processing RPC request on fd %d\n", + w->io.fd); + if (process_request (w) < 0) + handle[h].docancel = 1; + + if (handle[h].docancel) + break; + } + } + while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty); + DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status)); + + free (buf); + buf = NULL; } - while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty); - DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status)); - if(handle[h].docancel) + if (handle[h].docancel) sane_cancel (handle[h].handle); handle[h].docancel = 0; @@ -2236,8 +2256,8 @@ process_request (Wire * w) strerror (errno)); return 1; } - fcntl (data_fd, F_SETFL, 1); /* set non-blocking */ - shutdown (data_fd, 0); + fcntl (data_fd, F_SETFL, O_NONBLOCK); /* set non-blocking */ + shutdown (data_fd, SHUT_RD); do_scan (w, h, data_fd); close (data_fd); } @@ -3413,16 +3433,17 @@ static void usage(char *me, int err) fprintf (stderr, "Usage: %s [OPTIONS]\n\n" " Options:\n\n" - " -a, --alone[=user] equal to `-l -D -u user'\n" - " -l, --listen run in standalone mode (listen for connection)\n" - " -u, --user=user run as `user'\n" - " -D, --daemonize run in background\n" - " -o, --once exit after first client disconnects\n" - " -d, --debug=level set debug level `level' (default is 2)\n" - " -e, --stderr output to stderr\n" - " -b, --bind=addr bind address `addr' (default all interfaces)\n" - " -p, --port=port bind port `port` (default sane-port or 6566)\n" - " -h, --help show this help message and exit\n", me); + " -a, --alone[=user] equal to `-l -D -u user'\n" + " -l, --listen run in standalone mode (listen for connection)\n" + " -u, --user=user run as `user'\n" + " -D, --daemonize run in background\n" + " -o, --once exit after first client disconnects\n" + " -d, --debug=level set debug level `level' (default is 2)\n" + " -e, --stderr output to stderr\n" + " -b, --bind=addr bind address `addr' (default all interfaces)\n" + " -p, --port=port bind port `port` (default sane-port or 6566)\n" + " -B, --buffer-size=size set size of read buffer in KB (default: 1024)\n" + " -h, --help show this help message and exit\n", me); exit(err); } @@ -3432,17 +3453,18 @@ static int debug; static struct option long_options[] = { /* These options set a flag. */ - {"help", no_argument, 0, 'h'}, - {"alone", optional_argument, 0, 'a'}, - {"listen", no_argument, 0, 'l'}, - {"user", required_argument, 0, 'u'}, - {"daemonize", no_argument, 0, 'D'}, - {"once", no_argument, 0, 'o'}, - {"debug", required_argument, 0, 'd'}, - {"stderr", no_argument, 0, 'e'}, - {"bind", required_argument, 0, 'b'}, - {"port", required_argument, 0, 'p'}, - {0, 0, 0, 0 } + {"help", no_argument, 0, 'h'}, + {"alone", optional_argument, 0, 'a'}, + {"listen", no_argument, 0, 'l'}, + {"user", required_argument, 0, 'u'}, + {"daemonize", no_argument, 0, 'D'}, + {"once", no_argument, 0, 'o'}, + {"debug", required_argument, 0, 'd'}, + {"stderr", no_argument, 0, 'e'}, + {"bind", required_argument, 0, 'b'}, + {"port", required_argument, 0, 'p'}, + {"buffer-size", required_argument, 0, 'B'}, + {0, 0, 0, 0 } }; int @@ -3467,7 +3489,7 @@ main (int argc, char *argv[]) run_foreground = SANE_TRUE; run_once = SANE_FALSE; - while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:", long_options, &long_index )) != -1) + while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:B:", long_options, &long_index )) != -1) { switch(c) { case 'a': @@ -3498,8 +3520,25 @@ main (int argc, char *argv[]) bind_addr = optarg; break; case 'p': - bind_port = atoi(optarg); - break; + bind_port = atoi(optarg); + break; + case 'B': + { + int buffer_arg = atoi(optarg); + + if ((buffer_arg < 0) || ((size_t)buffer_arg > (SIZE_MAX / 1024))) + { + DBG ( + DBG_ERR, + "saned: specified buffer size in KB is invalid. Default of %zuKB will be substituted.\n", + buffer_size / 1024); + } + else + { + buffer_size = 1024 * (size_t)buffer_arg; + } + break; + } case 'h': usage(argv[0], EXIT_SUCCESS); break; |