Complete sources for a monero webminer.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

296 lines
7.9 KiB

// https://github.com/statianzo/Fleck
// The MIT License
// Copyright (c) 2010-2016 Jason Staten
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Threading.Tasks;
namespace Fleck
{
public class WebSocketConnection : IWebSocketConnection
{
public WebSocketConnection(ISocket socket, Action<IWebSocketConnection> initialize, Func<byte[], WebSocketHttpRequest> parseRequest, Func<WebSocketHttpRequest, IHandler> handlerFactory, Func<IEnumerable<string>, string> negotiateSubProtocol)
{
Socket = socket;
OnOpen = () => { };
OnClose = () => { };
OnMessage = x => { };
OnBinary = x => { };
OnPing = x => SendPong(x);
OnPong = x => { };
OnError = x => { };
_initialize = initialize;
_handlerFactory = handlerFactory;
_parseRequest = parseRequest;
_negotiateSubProtocol = negotiateSubProtocol;
}
public ISocket Socket { get; set; }
private readonly Action<IWebSocketConnection> _initialize;
private readonly Func<WebSocketHttpRequest, IHandler> _handlerFactory;
private readonly Func<IEnumerable<string>, string> _negotiateSubProtocol;
readonly Func<byte[], WebSocketHttpRequest> _parseRequest;
public IHandler Handler { get; set; }
private bool _opened = false;
private bool _closing;
private bool _closed;
private const int ReadSize = 1024 * 4;
public Action OnOpen { get; set; }
public Action OnClose { get; set; }
public Action<string> OnMessage { get; set; }
public Action<byte[]> OnBinary { get; set; }
public Action<byte[]> OnPing { get; set; }
public Action<byte[]> OnPong { get; set; }
public Action<Exception> OnError { get; set; }
public IWebSocketConnectionInfo ConnectionInfo { get; private set; }
public bool IsAvailable {
get { return !_closing && !_closed && Socket.Connected; }
}
public Task Send(string message)
{
return Send(message, Handler.FrameText);
}
public Task Send(byte[] message)
{
return Send(message, Handler.FrameBinary);
}
public Task SendPing(byte[] message)
{
return Send(message, Handler.FramePing);
}
public Task SendPong(byte[] message)
{
return Send(message, Handler.FramePong);
}
private Task Send<T>(T message, Func<T, byte[]> createFrame)
{
if (Handler == null)
throw new InvalidOperationException("Cannot send before handshake");
if (!IsAvailable)
{
const string errorMessage = "Data sent while closing or after close. Ignoring.";
FleckLog.Warn(errorMessage);
var taskForException = new TaskCompletionSource<object>();
taskForException.SetException(new ConnectionNotAvailableException(errorMessage));
return taskForException.Task;
}
var bytes = createFrame(message);
return SendBytes(bytes);
}
byte[] buffer;
public void StartReceiving()
{
List<byte> data = new List<byte>(ReadSize);
buffer = new byte[ReadSize];
Task.Run(async delegate
{
await Task.Delay(TimeSpan.FromSeconds(20));
if (!_closed && !_opened) {
Console.WriteLine("Closing/Disposing WebSocketConnection. Not able to perform handshake within 20s.");
CloseSocket ();
}
});
Read(data, buffer);
}
public void Close()
{
Close(WebSocketStatusCodes.NormalClosure);
}
public void Close(int code)
{
//try{ CloseSocket();} catch{ // added by tl
// }
if (!IsAvailable)
return;
_closing = true;
if (Handler == null) {
CloseSocket();
return;
}
var bytes = Handler.FrameClose(code);
if (bytes.Length == 0)
CloseSocket();
else
SendBytes(bytes, CloseSocket);
}
public void CreateHandler(IEnumerable<byte> data)
{
var request = _parseRequest(data.ToArray());
if (request == null)
return;
Handler = _handlerFactory(request);
if (Handler == null)
return;
var subProtocol = _negotiateSubProtocol(request.SubProtocols);
ConnectionInfo = WebSocketConnectionInfo.Create(request, Socket.RemoteIpAddress, Socket.RemotePort, subProtocol);
_initialize(this);
var handshake = Handler.CreateHandshake(subProtocol);
SendBytes(handshake, () => { OnOpen(); _opened = true; });
}
private void Read(List<byte> data, byte[] buffer)
{
if (!IsAvailable)
return;
Socket.Receive(buffer, r =>
{
if (r <= 0) {
FleckLog.Debug("0 bytes read. Closing.");
CloseSocket();
return;
}
FleckLog.Debug(r + " bytes read");
var readBytes = buffer.Take(r);
if (Handler != null) {
Handler.Receive(readBytes);
} else {
data.AddRange(readBytes);
CreateHandler(data);
}
Read(data, buffer);
},
HandleReadError);
}
private void HandleReadError(Exception e)
{
if (e is AggregateException) {
var agg = e as AggregateException;
HandleReadError(agg.InnerException);
return;
}
if (e is ObjectDisposedException) {
FleckLog.Debug("Swallowing ObjectDisposedException", e);
CloseSocket();
return;
}
OnError(e);
if (e is HandshakeException) {
FleckLog.Debug("Error while reading", e);
// why no close here?? TL
//Close(WebSocketStatusCodes.ProtocolError);
CloseSocket();
} else if (e is WebSocketException) {
FleckLog.Debug("Error while reading", e);
//Close(((WebSocketException)e).StatusCode);
CloseSocket();
} else if (e is SubProtocolNegotiationFailureException) {
FleckLog.Debug(e.Message);
CloseSocket();
//Close(WebSocketStatusCodes.ProtocolError);
} else if (e is IOException) {
FleckLog.Debug("Error while reading", e);
CloseSocket();
//Close(WebSocketStatusCodes.AbnormalClosure);
} else {
FleckLog.Error("Application Error", e);
CloseSocket();
//Close(WebSocketStatusCodes.InternalServerError);
}
}
private Task SendBytes(byte[] bytes, Action callback = null)
{
return Socket.Send(bytes, () =>
{
FleckLog.Debug("Sent " + bytes.Length + " bytes");
if (callback != null)
callback();
},
e =>
{
if (e is IOException)
FleckLog.Debug("Failed to send. Disconnecting.", e);
else
FleckLog.Info("Failed to send. Disconnecting.", e);
CloseSocket();
});
}
public void CloseSocket()
{
_closing = true;
if (!_closed) {
_closed = true;
OnClose ();
}
Socket.Close();
Socket.Dispose();
_closing = false;
buffer = null;
}
}
}