After executing Shutdown or Close service receives 31 empty bytes

0 votes
asked Mar 10 by Frostea (160 points)

Hello,

After I execute .Shutdown(SocketShutdown.Receive) on client, my service receives byte[] of a size 31 full of 0. It acts like that no matter if I've sent any data before the socket closure or not. Maybe it is intended behavior?

commented Mar 10 by Lukas Pokorny (124,570 points)
Hello, could you please let us know which Rebex API (and which version) you use? Is it the ProxySocket class, TlsSocket class, or other instance of the ISocket interface? A snippet of code that shows what you are doing might also be helpful. Thanks!
commented Mar 10 by Frostea (160 points)
I'm using Rebex.Net.TlsClientSocket

After creating TlsClientSocket and configuring it with parameters all I do is connect
_tlsClientSocket.Connect(new IPEndPoint(address, port));
_tlsClientSocket.Negotiate();
And then disconect:
_tlsClientSocket.Shutdown(SocketShutdown.Receive); //That's where 31 bytes get sent

Service side:
has created  Rebex.Net.TlsServerSocket class and configured with parameters
And then it has listener running.
while (Ssl.Socket.Connected)
{
    if (ssl.Socket.Poll(new Timeout(120_000).Microseconds, SelectMode.SelectRead))
    {
        int available = ssl.Socket.Available;
        byte[] data = new byte[available];
        await ssl.ReceiveAsync(data);
    }
}

 byte[] data is where I receive that byte[] with a length of 31.

Both client and service is running Regex.Tls version 5.0.7579

1 Answer

+1 vote
answered Mar 10 by Lukas Pokorny (124,570 points)
selected Mar 10 by Frostea
 
Best answer

In your while loop, you are mixing calls to a TCP layer API with calls to TLS layer API that runs over it. This won't work properly.

The ssl.Socket property is actually an instance of .NET socket (System.Net.Sockets.Socket class), which represents the TCP socket that underlies the TlsServerSocket instance. That underlying socket does not "know" anything about TLS/SSL or about the TlsServerSocket, and in almost all scenarios involving TlsServerSocket or TlsClientSocket, it's best to leave it alone.

The ssl.Socket.Poll call at the TCP layer implies that you would miss any data that has already been received by the TlsServerSocket and is waiting in its internal buffer, and the ssl.Socket.Available property returns the number of bytes available at the TCP level, which also includes the length of TLS packets that don't represent actual data, but are instead part of the TLS protocol itself.

For example, the value of 31 you get when the socket is closed at the client side represents the length of TLS Alert packet that informs the server that the TLS channel has been closed.

A typical server-side while loop using asynchronous ReceiveAsync might look like this:

byte[] data = new byte[4096]; // allocate a buffer for incoming data
while (true)
{
    // receive data over the TLS socket
    int receivedBytes = await ssl.ReceiveAsync(data);
    if (receivedBytes == 0)
    {
        // when ReceiveAsync returns zero, it indicates
        // that the connection has been closed and that
        // it is time to close it from the server-side
        // and exit the 'while' loop
        await ssl.DisposeAsync();
        break;
    }

    // otherwise, do something with the data
    DoSomething(new ArraySegment<byte>(data, 0, receivedBytes));
}

There is actually no need to call ssl.Socket.Poll or ssl.Socket.Available at all.

commented Mar 10 by Frostea (160 points)
Seems to have worked. Thanks for help and explanation
...