sjamesr / jfreesane

Java API to talk to the SANE scanning daemon
Apache License 2.0
60 stars 25 forks source link

Socket closed while setting SaneOption value #103

Closed jurivrljicak closed 3 years ago

jurivrljicak commented 3 years ago

Hi everyone, sorry to bother.

While setting option values (any type) I get a socket closed exception in SaneOption.writeWordListOption(List value)

java.net.SocketException: Socket closed
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:118)
at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at au.com.southsky.jfreesane.SaneOption.writeWordListOption(SaneOption.java:624)
at au.com.southsky.jfreesane.SaneOption.writeOption(SaneOption.java:657)
at au.com.southsky.jfreesane.SaneOption.setFixedValue(SaneOption.java:492)

SaneOutputStream out = device.getSession().getOutputStream();

returns an open stream however later on the flush fails. Any idea that can help me? thanks in advance


private ControlOptionResult writeWordListOption(List value)
      throws IOException, SaneException {
    Preconditions.checkState(isWriteable(), "option is not writeable");
    Preconditions.checkState(isActive(), "option is not active");

    SaneOutputStream out = device.getSession().getOutputStream();
    out.write(SaneRpcCode.SANE_NET_CONTROL_OPTION);
    out.write(device.getHandle().getHandle());
    out.write(SaneWord.forInt(optionNumber));
    out.write(SaneWord.forInt(OptionAction.SET_VALUE.getWireValue()));
    out.write(getValueType());

    out.write(SaneWord.forInt(value.size() * SaneWord.SIZE_IN_BYTES));

    // Write the pointer to the words
    out.write(SaneWord.forInt(value.size()));

    for (SaneWord element : value) {
      // and the words themselves
      out.write(element);
    }

    out.flush();

    ControlOptionResult result = handleWriteResponse();
    if (result.getInfo().contains(OptionWriteInfo.RELOAD_OPTIONS)
        || result.getInfo().contains(OptionWriteInfo.RELOAD_PARAMETERS)) {
      device.invalidateOptions();
      device.listOptions();
    }

    return result;
  }            
sjamesr commented 3 years ago

Are you able to share the code that is calling into jfreesane?

jurivrljicak commented 3 years ago

hmm, what bit would be relevant?

sjamesr commented 3 years ago

The part that calls "setFixedValue", for example.

I suspect your SANE daemon is somehow misconfigured and is closing the socket shortly after it's opened. You could confirm with server logs.

jurivrljicak commented 3 years ago

Ok, strangely enough if I catch those exceptions and continue I am able to get images back (I am using the test configuration).

jurivrljicak commented 3 years ago

In fact if at this point

SaneOutputStream out = device.getSession().getOutputStream();

I inspect device.isOpen(), that returns true

sjamesr commented 3 years ago

Can you share the code you're using to call into JFreeSane? Where are you catching exceptions? Which socket is closed? If the socket to the SANE server is closed, there's no way you should be able to retrieve images.

Help me understand how you're using SANE/jfreesane.

jurivrljicak commented 3 years ago

Well, there is not much to show. I am going by the manual

SaneDevice device = ...; device.open(); List options = device.listOptions(); then I set a value to a given option (using the setter according to the type) (this step fails with socket closed exception) then I do device.acquireImage() And I get a color test image as set in the configuration file.

I am using Ubuntu16.04 64 on VMWareFusion, and a saned daemon with a virtual device configured.

Tomorrow I'll put my hands on a physical device and I'll see. Up to now I don't understand. I'll get back to you, thanks

sjamesr commented 3 years ago

Do you have any server logs? They should indicate why saned closed the socket.

On Tue, Jan 12, 2021 at 10:45 AM jurivrljicak notifications@github.com wrote:

Well, there is not much to show. I am going by the manual

SaneDevice device = ...; device.open(); List options = device.listOptions(); then I set a value to a given option (using the setter according to the type) (this step fails with socket closed exception) then I do device.acquireImage() And I get a color test image as set in the configuration file.

I am using Ubuntu16.04 64 on VMWareFusion, and a saned daemon with a virtual device configured.

Tomorrow I'll put my hands on a physical device and I'll see. Up to now I don't understand. I'll get back to you, thanks

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/sjamesr/jfreesane/issues/103#issuecomment-758860538, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABDNGA5OG2ZM24CRMURRMJLSZSKEFANCNFSM4V53VTVA .

jurivrljicak commented 3 years ago

Oh, let me see if I can find that one. thanks

jurivrljicak commented 3 years ago

Ok. I am working with a Kodak ScanMate i940 now. I see the same problem this time while acquiring images.

My client code:

@Override
public BufferedImage doScan() throws xxxSaneException {

if (!device.isOpen())
     openDevice();

Logger logger = getLogger();
try {
     logger.info(Messages.getString("akey", getName())); //$NON-NLS-1$
     return device.acquireImage();
} catch (Exception e) {
     Device.getExecutor().submit(()->
    Try.run(()->((SaneDevice)device).close()));

    logger.log(Level.SEVERE, "doScan() " + e.getClass().getName() + ": "+ e.getMessage());
    throw new xxxJSaneException(e);
} finally {
    logger.info(Messages.getString("anotherKey", getName())); //$NON-NLS-1$
    }
}

So here, preconditions are met

public BufferedImage acquireImage(ScanListener listener) throws IOException, SaneException {
    Preconditions.checkState(isOpen(), "device is not open");
    if (listener == null) {
      listener = new ScanListenerAdapter();
    }
    return session.acquireImage(this, listener);
  }

error is thrown in line marked as bold, with a socketClosedException

BufferedImage acquireImage(SaneDevice device, ScanListener listener)
      throws IOException, SaneException {
    SaneImage.Builder builder = new SaneImage.Builder();
    SaneParameters parameters = null;
    listener.scanningStarted(device);
    int currentFrame = 0;

    do {
      SaneDeviceHandle handle = device.getHandle();
      outputStream.write(SaneRpcCode.SANE_NET_START);
      outputStream.write(handle.getHandle());
      outputStream.flush();

      SaneWord startStatus = inputStream.readWord();

      int port = inputStream.readWord().integerValue();
      SaneWord byteOrder = inputStream.readWord();
      String resource = inputStream.readString();
...

Server log reads

07:15:04 osboxes systemd[1]: Started Scanner Service (127.0.0.1:55110).
Jan  9 07:15:04 osboxes saned[35837]: saned (AF-indep+IPv6+systemd) from sane-backends 1.0.25git starting up
Jan  9 07:15:04 osboxes saned[35837]: check_host: access by remote host: ::ffff:127.0.0.1
Jan  9 07:15:04 osboxes saned[35837]: init: access granted to osboxes@::ffff:127.0.0.1
Jan  9 07:15:15 osboxes gnome-session[2384]: Memory pressure relief: Total: res = 7553024/7561216/8192, res+swap = 5726208/5730304/4096
Jan  9 07:15:28 osboxes saned[35837]: saned exiting

thanks!

sjamesr commented 3 years ago

It certainly doesn't look like saned is closing the socket. The only reason that should happen on the client side is because of a call to SaneSession.close.

Do you keep the SaneSession around for the duration of your scanning?

jurivrljicak commented 3 years ago

Oh! I am very sorry you are right.

disclaimer: I am migrating an existing code to use jfreesane (a code that I am not very familiar with)

thanks a lot for your time

sjamesr commented 3 years ago

No problem, glad we got it sorted.