aboutsummaryrefslogtreecommitdiff
path: root/SocketHttpListener/Net/SocketAcceptor.cs
blob: 36332f52b648e09c924195a6482f42133fb34c35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;
using System.Net.Sockets;
using MediaBrowser.Model.Logging;

namespace SocketHttpListener.Net
{
    public class SocketAcceptor
    {
        private readonly ILogger _logger;
        private readonly Socket _originalSocket;
        private readonly Func<bool> _isClosed;
        private readonly Action<Socket> _onAccept;

        public SocketAcceptor(ILogger logger, Socket originalSocket, Action<Socket> onAccept, Func<bool> isClosed)
        {
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }
            if (originalSocket == null)
            {
                throw new ArgumentNullException("originalSocket");
            }
            if (onAccept == null)
            {
                throw new ArgumentNullException("onAccept");
            }
            if (isClosed == null)
            {
                throw new ArgumentNullException("isClosed");
            }

            _logger = logger;
            _originalSocket = originalSocket;
            _isClosed = isClosed;
            _onAccept = onAccept;
        }

        public void StartAccept()
        {
            Socket dummy = null;
            StartAccept(null, ref dummy);
        }

        public void StartAccept(SocketAsyncEventArgs acceptEventArg, ref Socket accepted)
        {
            if (acceptEventArg == null)
            {
                acceptEventArg = new SocketAsyncEventArgs();
                acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
            }
            else
            {
                // acceptSocket must be cleared since the context object is being reused
                acceptEventArg.AcceptSocket = null;
            }

            try
            {
                bool willRaiseEvent = _originalSocket.AcceptAsync(acceptEventArg);

                if (!willRaiseEvent)
                {
                    ProcessAccept(acceptEventArg);
                }
            }
            catch (Exception ex)
            {
                if (accepted != null)
                {
                    try
                    {
#if NET46
                        accepted.Close();
#else
                        accepted.Dispose();
#endif
                    }
                    catch
                    {
                    }
                    accepted = null;
                }
            }
        }

        // This method is the callback method associated with Socket.AcceptAsync  
        // operations and is invoked when an accept operation is complete 
        // 
        void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
        {
            ProcessAccept(e);
        }

        private void ProcessAccept(SocketAsyncEventArgs e)
        {
            if (_isClosed())
            {
                return;
            }

            // http://msdn.microsoft.com/en-us/library/system.net.sockets.acceptSocket.acceptasync%28v=vs.110%29.aspx
            // Under certain conditions ConnectionReset can occur
            // Need to attept to re-accept
            if (e.SocketError == SocketError.ConnectionReset)
            {
                _logger.Error("SocketError.ConnectionReset reported. Attempting to re-accept.");
                Socket dummy = null;
                StartAccept(e, ref dummy);
                return;
            }

            var acceptSocket = e.AcceptSocket;
            if (acceptSocket != null)
            {
                //ProcessAccept(acceptSocket);
                _onAccept(acceptSocket);
            }

            // Accept the next connection request
            StartAccept(e, ref acceptSocket);
        }
    }
}