2016-11-08 18:44:23 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Threading;
|
2017-03-12 19:27:26 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2016-11-08 18:44:23 +00:00
|
|
|
|
using Emby.Common.Implementations.Networking;
|
|
|
|
|
using MediaBrowser.Model.Net;
|
|
|
|
|
using MediaBrowser.Model.Logging;
|
|
|
|
|
|
|
|
|
|
namespace Emby.Common.Implementations.Net
|
|
|
|
|
{
|
2017-03-02 20:50:09 +00:00
|
|
|
|
public class NetAcceptSocket : IAcceptSocket
|
2016-11-08 18:44:23 +00:00
|
|
|
|
{
|
|
|
|
|
public Socket Socket { get; private set; }
|
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
|
|
2016-12-07 20:02:34 +00:00
|
|
|
|
public bool DualMode { get; private set; }
|
|
|
|
|
|
2017-03-02 20:50:09 +00:00
|
|
|
|
public NetAcceptSocket(Socket socket, ILogger logger, bool isDualMode)
|
2016-11-08 18:44:23 +00:00
|
|
|
|
{
|
2016-11-13 21:04:21 +00:00
|
|
|
|
if (socket == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException("socket");
|
|
|
|
|
}
|
|
|
|
|
if (logger == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException("logger");
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 18:44:23 +00:00
|
|
|
|
Socket = socket;
|
|
|
|
|
_logger = logger;
|
2016-12-07 20:02:34 +00:00
|
|
|
|
DualMode = isDualMode;
|
2016-11-08 18:44:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IpEndPointInfo LocalEndPoint
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-11-11 07:24:36 +00:00
|
|
|
|
return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.LocalEndPoint);
|
2016-11-08 18:44:23 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IpEndPointInfo RemoteEndPoint
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-11-11 07:24:36 +00:00
|
|
|
|
return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.RemoteEndPoint);
|
2016-11-08 18:44:23 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-03 05:53:21 +00:00
|
|
|
|
public void Connect(IpEndPointInfo endPoint)
|
|
|
|
|
{
|
|
|
|
|
var nativeEndpoint = NetworkManager.ToIPEndPoint(endPoint);
|
|
|
|
|
|
|
|
|
|
Socket.Connect(nativeEndpoint);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 18:44:23 +00:00
|
|
|
|
public void Close()
|
|
|
|
|
{
|
|
|
|
|
#if NET46
|
|
|
|
|
Socket.Close();
|
|
|
|
|
#else
|
2017-03-12 19:27:26 +00:00
|
|
|
|
Socket.Dispose();
|
2016-11-08 18:44:23 +00:00
|
|
|
|
#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)
|
|
|
|
|
{
|
2016-11-11 07:24:36 +00:00
|
|
|
|
var nativeEndpoint = NetworkManager.ToIPEndPoint(endpoint);
|
2016-11-08 18:44:23 +00:00
|
|
|
|
|
|
|
|
|
Socket.Bind(nativeEndpoint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private SocketAcceptor _acceptor;
|
2017-03-02 20:50:09 +00:00
|
|
|
|
public void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed)
|
2016-11-08 18:44:23 +00:00
|
|
|
|
{
|
2016-12-07 20:02:34 +00:00
|
|
|
|
_acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
|
2016-11-08 18:44:23 +00:00
|
|
|
|
|
|
|
|
|
_acceptor.StartAccept();
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-12 19:27:26 +00:00
|
|
|
|
#if NET46
|
|
|
|
|
public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var options = TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket | TransmitFileOptions.UseKernelApc;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-11-08 18:44:23 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Socket.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|