aboutsummaryrefslogtreecommitdiff
path: root/Emby.Common.Implementations/Net/NetAcceptSocket.cs
blob: 5e831ac7aba08c04f08df28ee9c20369e9ba19fe (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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Emby.Common.Implementations.Networking;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Logging;

namespace Emby.Common.Implementations.Net
{
    public class NetAcceptSocket : IAcceptSocket
    {
        public Socket Socket { get; private set; }
        private readonly ILogger _logger;

        public bool DualMode { get; private set; }

        public NetAcceptSocket(Socket socket, ILogger logger, bool isDualMode)
        {
            if (socket == null)
            {
                throw new ArgumentNullException("socket");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }

            Socket = socket;
            _logger = logger;
            DualMode = isDualMode;
        }

        public IpEndPointInfo LocalEndPoint
        {
            get
            {
                return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.LocalEndPoint);
            }
        }

        public IpEndPointInfo RemoteEndPoint
        {
            get
            {
                return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.RemoteEndPoint);
            }
        }

        public void Connect(IpEndPointInfo endPoint)
        {
            var nativeEndpoint = NetworkManager.ToIPEndPoint(endPoint);

            Socket.Connect(nativeEndpoint);
        }

        public void Close()
        {
#if NET46
            Socket.Close();
#else
            Socket.Dispose();
#endif
        }

        public void Shutdown(bool both)
        {
            if (both)
            {
                Socket.Shutdown(SocketShutdown.Both);
            }
            else
            {
                // Change interface if ever needed
                throw new NotImplementedException();
            }
        }

        public void Listen(int backlog)
        {
            Socket.Listen(backlog);
        }

        public void Bind(IpEndPointInfo endpoint)
        {
            var nativeEndpoint = NetworkManager.ToIPEndPoint(endpoint);

            Socket.Bind(nativeEndpoint);
        }

        private SocketAcceptor _acceptor;
        public void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed)
        {
            _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);

            _acceptor.StartAccept();
        }

        public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
        {
            var options = TransmitFileOptions.UseDefaultWorkerThread;

            var completionSource = new TaskCompletionSource<bool>();

            var result = Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), new Tuple<Socket, string, TaskCompletionSource<bool>>(Socket, path, completionSource));

            return completionSource.Task;
        }

        public IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state)
        {
            var options = TransmitFileOptions.UseDefaultWorkerThread;

            return Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), state);
        }

        public void EndSendFile(IAsyncResult result)
        {
            Socket.EndSendFile(result);
        }

        private void FileSendCallback(IAsyncResult ar)
        {
            // Retrieve the socket from the state object.
            Tuple<Socket, string, TaskCompletionSource<bool>> data = (Tuple<Socket, string, TaskCompletionSource<bool>>)ar.AsyncState;

            var client = data.Item1;
            var path = data.Item2;
            var taskCompletion = data.Item3;

            // Complete sending the data to the remote device.
            try
            {
                client.EndSendFile(ar);
                taskCompletion.TrySetResult(true);
            }
            catch (SocketException ex)
            {
                _logger.Info("Socket.SendFile failed for {0}. error code {1}", path, ex.SocketErrorCode);
                taskCompletion.TrySetException(ex);
            }
            catch (Exception ex)
            {
                taskCompletion.TrySetException(ex);
            }
        }

        public void Dispose()
        {
            Socket.Dispose();
        }
    }
}