NETMF / netmf-interpreter

.NET Micro Framework Interpreter
http://netmf.github.io/netmf-interpreter/
Other
487 stars 224 forks source link

Closing a socket doesn't close connection in native lwip #422

Open Palomino34 opened 8 years ago

Palomino34 commented 8 years ago

Hi, We have an issue with closing a socket. When a client socket is opened and connecting to a server that is not listening ( server's IP address is exist). If we closed that socket, socket objects are disposed but, in Lwip native side, some objects are still alive for awhile, even we created another socket. If the server is enable to listen at this time, the device is crashed, because some mess up between 2 socket's objects.

At this time, we have modified some in do_delconn() and netconn_delete(), when closed a socket, instead of posting messages to tell that the socket is closed, we call to close all objects relate to that socket directly. Seem to be worked now but it is just a workaround, we really hope a official fixing for this issue in the future.

Thanks a lot

smaillet-ms commented 8 years ago

Can you provide more details (ideally with a small test app that can re-produce the problem)? Can you describe in detail the workaround you have made? Ideally the problem would be solved without modifying the LWIP stack itself (unless it is actually a bug in the stack, of course) but any workarounds available can help in coming up with a proper fix.

Palomino34 commented 8 years ago

To reproduce the issue:

This issue comes from our customers, and we also can reproduce it easily. Code client:

IPEndPoint endpoint = new IPEndPoint(new IPAddress(new byte[] { 192, 168, 1, 89 }), 21000);
            while (true)
            {
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                try
                {
                    // You can use thread instead of ExecutionConstraint to connect and kill that thread but same result.
                    ExecutionConstraint.Install(10000, 0);
                    socket.Connect(endpoint);
                    ExecutionConstraint.Install(-1, 0);

                }
                catch
                {

                }
                // Without closing the socket, the application still alive untill we run out of socket.
                socket.Close();
            }

Code server:

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Net;
using System.Net.Sockets;

namespace ConnectHangResetPCServer
{
    static class Testing
    {
        private static Socket _serverSocket;
        private static ConcurrentQueue<ClientSocket> _clientSockets = new ConcurrentQueue<ClientSocket>();
        private static Thread _managementThread;
        //private const bool DEBUG = false;
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args)
        {
            _managementThread = new Thread(SocketManagement);
            _managementThread.Start();

            _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _serverSocket.ReceiveTimeout = 1000;
            _serverSocket.SendTimeout = 1000;
            _serverSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
            _serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);

            _serverSocket.Bind(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 1, 89 }), 21000));
            _serverSocket.Listen(5);

            _serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

            Thread.Sleep(-1);
        }

        private static void OnAccept(IAsyncResult ar)
        {
            try
            {
                Socket socket = _serverSocket.EndAccept(ar);

                ClientSocket clientSocket = new ClientSocket(socket);

                _clientSockets.Enqueue(clientSocket);

                //Start listening for more clients
                _serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
            }
            catch
            {
            }
        }

        private static void SocketManagement()
        {
            ClientSocket clientSocket;

            while (true)
            {
                if (_clientSockets.TryPeek(out clientSocket))
                {
                    if (DateTime.Now - clientSocket.ConnectTime > TimeSpan.FromSeconds(60))
                    {
                        if (_clientSockets.TryDequeue(out clientSocket))
                        {
                            //clientSocket.Socket.Disconnect(false);
                            clientSocket.Socket.Close();
                            clientSocket.Socket.Dispose();
                        }
                    }
                }

                Thread.Sleep(500);
            }
        }
    }

    internal class ClientSocket
    {
        public Socket Socket { get; set; }
        public DateTime ConnectTime { get; set; }

        public ClientSocket(Socket clientSocket)
        {
            Socket = clientSocket;
            ConnectTime = DateTime.Now;
        }
    }
}
Palomino34 commented 8 years ago

Our workaround is:

By that way, we tested and seem all working fine. But we are worry another problems can be happened by that change. Thansk a lot for your help.