hierynomus / smbj

Server Message Block (SMB2, SMB3) implementation in Java
Other
713 stars 180 forks source link

Does reading from smbfile inputstream keeps the session alive? #702

Closed vjorge closed 2 years ago

vjorge commented 2 years ago

Hi,

I have a large file that I have to read line by line, but I get the following exception after 15 minutes (I guess is the smb server session Idle timeout), I get the error bellow:

com.hierynomus.smbj.transport.tcp.direct.DirectTcpP                                                                                                                     acketReader - PacketReader error, got exception.
com.hierynomus.protocol.transport.TransportException: java.net.SocketException: Connection reset
        at com.hierynomus.smbj.transport.tcp.direct.DirectTcpPacketReader.doRead(DirectTcpPacketReader.java:53) ~[.jar:?]
        at com.hierynomus.smbj.transport.PacketReader.readPacket(PacketReader.java:70) ~[.jar:?]
        at com.hierynomus.smbj.transport.PacketReader.run(PacketReader.java:48) [.jar:?]
        at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: java.net.SocketException: Connection reset
        at java.net.SocketInputStream.read(SocketInputStream.java:186) ~[?:?]
        at java.net.SocketInputStream.read(SocketInputStream.java:140) ~[?:?]
        at com.hierynomus.smbj.transport.tcp.direct.DirectTcpPacketReader.readFully(DirectTcpPacketReader.java:70) ~[.jar:?]
        at com.hierynomus.smbj.transport.tcp.direct.DirectTcpPacketReader.readTcpHeader(DirectTcpPacketReader.java:59) ~[.jar:?]
        at com.hierynomus.smbj.transport.tcp.direct.DirectTcpPacketReader.doRead(DirectTcpPacketReader.java:48) ~[.jar:?]
        ... 3 more
2022-03-25T11:51:45.023Z INFO  thread='Packet Reader for smbserver.domain.test' user='' org='' trace=''] {} com.hierynomus.smbj.session.Session - Logging off s                                                                                                                          ession 1385387872303105 from host smbserver.domain.test
2022-03-25T11:51:45.023Z ERROR  thread='Packet Reader for smbserver.domain.test' user='' org='' trace=''] {} com.hierynomus.smbj.session.Session - Caught excep                                                                                                                          tion while closing TreeConnect with id: 1
com.hierynomus.protocol.transport.TransportException: java.net.SocketException: Broken pipe (Write failed)
        at com.hierynomus.smbj.transport.tcp.direct.DirectTcpTransport.write(DirectTcpTransport.java:78) ~[.jar:?]
        at com.hierynomus.smbj.connection.Connection.send(Connection.java:234) ~[.jar:?]
        at com.hierynomus.smbj.session.Session.send(Session.java:300) ~[.jar:?]
        at com.hierynomus.smbj.share.TreeConnect.close(TreeConnect.java:69) ~[.jar:?]
        at com.hierynomus.smbj.share.Share.close(Share.java:116) ~[.jar:?]
        at com.hierynomus.smbj.session.Session.logoff(Session.java:236) [.jar:?]
        at com.hierynomus.smbj.session.Session.close(Session.java:279) [.jar:?]
        at com.hierynomus.smbj.connection.Connection.close(Connection.java:178) [.jar:?]
        at com.hierynomus.smbj.connection.Connection.close(Connection.java:155) [.jar:?]
        at com.hierynomus.smbj.connection.Connection.handleError(Connection.java:294) [.jar:?]
        at com.hierynomus.smbj.transport.PacketReader.run(PacketReader.java:54) [.jar:?]
        at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: java.net.SocketException: Broken pipe (Write failed)
        at java.net.SocketOutputStream.socketWrite0(Native Method) ~[?:?]
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:110) ~[?:?]
        at java.net.SocketOutputStream.write(SocketOutputStream.java:150) ~[?:?]
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81) ~[?:?]
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142) ~[?:?]
        at com.hierynomus.smbj.transport.tcp.direct.DirectTcpTransport.write(DirectTcpTransport.java:75) ~[.jar:?]
        ... 11 more

Is there a way to keep the session alive while reading from the inputstream? Many thanks for your help.

vjorge commented 2 years ago

Hello, Forget to mention that I am using DFS, I am connected to a Windows 2016, that provides a netapp Share.

I even tried to have a scheduled thread to loop around the sessions and do a SMB2Echo, but as soon as the echo is triggered the session is immediately killed.

snipet of the "keep alive thread"

for (Session session : this.sessions) {
            SMB2Dialect smbver = session.getConnection().getNegotiatedProtocol().getDialect();
            SMB2Echo echo = new SMB2Echo(smbver);
        try {
            Future<SMB2Packet> echoresponse = session.send(echo);
        } catch (TransportException e) {
            log.error(e.getMessage());
            }
        }
    }

Anyone facing this issue, or kindly share a possible solution? Many thanks.

tangxuGoGoGo commented 2 years ago

I also tried keepalive with echo before, but it failed. Later I use the list command to keep alive and it works fine so far

vjorge commented 2 years ago

Hi tangxuGoGoGo, Many thanks for your comment. Yes, in fact it I use the share list it works, but its extremely inefficient, specially if you have : --> hundreds of files in you base share (some work on the SMB server and unecessary bandwith) --> a few dozens of SMB sessions

This will use quite ammount of network and cpu resources just for a keep alive.

I have no idea how to implement the same keep alive as in :

https://www.mankier.com/8/mount.cifs

> echo_interval=n
> sets the interval at which echo requests are sent to the server on an idling connection. This setting also affects the time required for a connection to an unresponsive server to timeout. Here n is the echo interval in seconds. The reconnection happens at twice the value of the echo_interval set for an unresponsive server. If this option is not given then the default value of 60 seconds is used. The minimum tunable value is 1 second and maximum can go up to 600 seconds.
vjorge commented 2 years ago

No need to keep this open as this will not be implemented on the library.

araneolus commented 2 years ago

I have the same Problem. You are not able to send SMB2Echo Messages by session. It works only by sending these Messages by connection (at my example ci). Unfortunately, this does not solve the problem of a session running into a timeout :-(

    @Override
    public void sendNoOp() throws IOException {
        if (this.isConnect() && this.checkConnection() && session!= null) {
            SMB2Dialect dialect = ci.getConnectionContext().getNegotiatedProtocol().getDialect();
            this.session.getSessionId();
            SMB2Echo echo = new SMB2Echo(dialect);
            Future<SMB2Packet> pkg = ci.send(echo);
            try {
                if(!pkg.get(this.getSoTimeout()>0?this.getSoTimeout():30000L, TimeUnit.MILLISECONDS).isSuccess())
                {
                    throw new IOException("[sendNoOp] Can't send noop Package");
                }
            } catch (InterruptedException|ExecutionException|TimeoutException e) {
                throw new IOException(e.getMessage());
            }
        }
    }