Browse Source

Merge pull request #100 from notgiven688/tab2space

Tab2space
pull/123/head
notgiven688 2 years ago
committed by GitHub
parent
commit
18fa48995e
13 changed files with 1495 additions and 1146 deletions
  1. +15
    -28
      server/Server/AlgorithmHelper.cs
  2. +48
    -30
      server/Server/CConsole.cs
  3. +21
    -13
      server/Server/DataStructures.cs
  4. +5
    -3
      server/Server/DevDonation.cs
  5. +195
    -142
      server/Server/EmptyWebsocket.cs
  6. +9
    -6
      server/Server/Extensions.cs
  7. +109
    -85
      server/Server/Firewall.cs
  8. +25
    -20
      server/Server/Helper.cs
  9. +153
    -114
      server/Server/JSONParser.cs
  10. +305
    -256
      server/Server/PoolConnection.cs
  11. +54
    -47
      server/Server/PoolList.cs
  12. +533
    -379
      server/Server/Program.cs
  13. +23
    -23
      server/Server/Random2.cs

+ 15
- 28
server/Server/AlgorithmHelper.cs View File

@ -24,14 +24,16 @@ using System.Collections.Generic;
using JsonData = System.Collections.Generic.Dictionary<string, object>;
namespace Server {
namespace Server
{
public class AlgorithmHelper {
public class AlgorithmHelper
{
// quite a mess
// https://github.com/xmrig/xmrig-proxy/blob/dev/doc/STRATUM_EXT.md#mining-algorithm-negotiation
// quite a mess
// https://github.com/xmrig/xmrig-proxy/blob/dev/doc/STRATUM_EXT.md#mining-algorithm-negotiation
private static Dictionary<string, Tuple<string, int>> lookup = new Dictionary<string, Tuple<string, int>>
private static Dictionary<string, Tuple<string, int>> lookup = new Dictionary<string, Tuple<string, int>>
{
{ "cryptonight/0", new Tuple<string, int>("cn", 0) },
{ "cryptonight/1", new Tuple<string, int>("cn", 1) },
@ -39,17 +41,18 @@ namespace Server {
{ "cryptonight-lite/0", new Tuple<string, int>("cn-lite", 0) },
{ "cryptonight-lite/1", new Tuple<string, int>("cn-lite", 1) },
{ "cryptonight-lite/2", new Tuple<string, int>("cn-lite", 2) },
{ "cn/0", new Tuple<string, int>("cn", 0) },
{ "cn/0", new Tuple<string, int>("cn", 0) },
{ "cn/1", new Tuple<string, int>("cn", 1) },
{ "cn/2", new Tuple<string, int>("cn", 2) },
{ "cn-lite/0", new Tuple<string, int>("cn-lite", 0) },
{ "cn-lite/1", new Tuple<string, int>("cn-lite", 1) },
{ "cn-lite/2", new Tuple<string, int>("cn-lite", 2) }
};
public static bool NormalizeAlgorithmAndVariant (JsonData job) {
string algo = job["algo"].GetString().ToLower();
public static bool NormalizeAlgorithmAndVariant(JsonData job)
{
string algo = job["algo"].GetString().ToLower();
if (algo == "cn" || algo == "cryptonight")
job["algo"] = "cn";
@ -66,24 +69,8 @@ namespace Server {
return false;
}
return true;
}
/*if (lookup.ContainsKey(algo))
{
var tuple = lookup[algo];
job["algo"] = tuple.Item1;
job["variant"] = tuple.Item2;
}
else
{
if (algo == "cn" || algo == "cryptonight")
job["algo"] = "cn";
else if (algo == "cn-lite" || algo == "cryptonight-lite")
job["algo"] = "cn-lite";
else return false;
}*/
return true;
}
}
}
}

+ 48
- 30
server/Server/CConsole.cs View File

@ -24,63 +24,81 @@ using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace Server {
namespace Server
{
public static class CConsole {
public static class CConsole
{
// Info, Alert, Warning
private static object locker = new object ();
private static readonly object locker = new object();
private static readonly bool enabled = true;
private static bool enabled = true;
static CConsole () {
try {
static CConsole()
{
try
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
Console.ResetColor ();
} catch {
// ArgumentException, SecurityException, IOException .
Console.ResetColor();
}
catch
{
// ArgumentException, SecurityException, IOException.
enabled = false;
}
}
private static void ColorConsole (Action consoleAction, ConsoleColor foreground) {
private static void ColorConsole(Action consoleAction, ConsoleColor foreground)
{
if (enabled) {
lock (locker) {
if (enabled)
{
lock (locker)
{
Console.ForegroundColor = foreground;
consoleAction ();
Console.ResetColor ();
consoleAction();
Console.ResetColor();
}
} else {
consoleAction ();
}
else
{
consoleAction();
}
}
private static void ColorConsole (Action consoleAction, ConsoleColor foreground, ConsoleColor background) {
private static void ColorConsole(Action consoleAction, ConsoleColor foreground, ConsoleColor background)
{
if (enabled) {
lock (locker) {
if (enabled)
{
lock (locker)
{
Console.ForegroundColor = foreground;
Console.BackgroundColor = background;
consoleAction ();
Console.ResetColor ();
consoleAction();
Console.ResetColor();
}
} else {
consoleAction ();
}
else
{
consoleAction();
}
}
public static void ColorInfo (Action consoleAction) {
ColorConsole (consoleAction, ConsoleColor.Cyan);
public static void ColorInfo(Action consoleAction)
{
ColorConsole(consoleAction, ConsoleColor.Cyan);
}
public static void ColorWarning (Action consoleAction) {
ColorConsole (consoleAction, ConsoleColor.Yellow);
public static void ColorWarning(Action consoleAction)
{
ColorConsole(consoleAction, ConsoleColor.Yellow);
}
public static void ColorAlert (Action consoleAction) {
ColorConsole (consoleAction, ConsoleColor.Red);
public static void ColorAlert(Action consoleAction)
{
ColorConsole(consoleAction, ConsoleColor.Red);
}
}

+ 21
- 13
server/Server/DataStructures.cs View File

@ -22,38 +22,46 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Server {
namespace Server
{
public class CcDictionary<T, V> : ConcurrentDictionary<T, V> {
public bool TryRemove (T item) {
public class CcDictionary<T, V> : ConcurrentDictionary<T, V>
{
public bool TryRemove(T item)
{
V dummy;
return this.TryRemove (item, out dummy);
return this.TryRemove(item, out dummy);
}
}
public class CcQueue<T> : ConcurrentQueue<T> { }
public class CcHashset<T> {
ConcurrentDictionary<T, byte> dictionary = new ConcurrentDictionary<T, byte> ();
public class CcHashset<T>
{
ConcurrentDictionary<T, byte> dictionary = new ConcurrentDictionary<T, byte>();
public bool TryAdd (T item) {
return dictionary.TryAdd (item, byte.MaxValue);
public bool TryAdd(T item)
{
return dictionary.TryAdd(item, byte.MaxValue);
}
public ICollection<T> Values {
public ICollection<T> Values
{
get { return dictionary.Keys; }
}
public int Count { get { return dictionary.Count; } }
public bool Contains (T item) {
return dictionary.ContainsKey (item);
public bool Contains(T item)
{
return dictionary.ContainsKey(item);
}
public bool TryRemove (T item) {
public bool TryRemove(T item)
{
byte dummy;
return dictionary.TryRemove (item, out dummy);
return dictionary.TryRemove(item, out dummy);
}
}

+ 5
- 3
server/Server/DevDonation.cs View File

@ -19,9 +19,11 @@
// 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.
namespace Server {
public static class DevDonation {
namespace Server
{
public static class DevDonation
{
// by default a 3% dev fee is submitted to the following address.
// thank you for leaving this in.

+ 195
- 142
server/Server/EmptyWebsocket.cs View File

@ -23,151 +23,204 @@ using System;
using System.Collections.Generic;
using Fleck;
namespace Server {
namespace Server
{
public class EmptyConnectionInfo : IWebSocketConnectionInfo {
#region IWebSocketConnectionInfo implementation
public string SubProtocol {
get {
throw new NotImplementedException ();
}
}
public string Origin {
get {
throw new NotImplementedException ();
}
}
public string Host {
get {
throw new NotImplementedException ();
}
}
public string Path {
get {
throw new NotImplementedException ();
}
}
public string ClientIpAddress {
get {
return "127.0.0.1";
}
}
public int ClientPort {
get {
throw new NotImplementedException ();
}
}
public IDictionary<string, string> Cookies {
get {
throw new NotImplementedException ();
}
}
public IDictionary<string, string> Headers {
get {
throw new NotImplementedException ();
}
}
public Guid Id {
get {
return Guid.Empty;
}
}
public string NegotiatedSubProtocol {
get {
throw new NotImplementedException ();
}
}
#endregion
}
public class EmptyConnectionInfo : IWebSocketConnectionInfo
{
#region IWebSocketConnectionInfo implementation
public string SubProtocol
{
get
{
throw new NotImplementedException();
}
}
public string Origin
{
get
{
throw new NotImplementedException();
}
}
public string Host
{
get
{
throw new NotImplementedException();
}
}
public string Path
{
get
{
throw new NotImplementedException();
}
}
public string ClientIpAddress
{
get
{
return "127.0.0.1";
}
}
public int ClientPort
{
get
{
throw new NotImplementedException();
}
}
public IDictionary<string, string> Cookies
{
get
{
throw new NotImplementedException();
}
}
public IDictionary<string, string> Headers
{
get
{
throw new NotImplementedException();
}
}
public Guid Id
{
get
{
return Guid.Empty;
}
}
public string NegotiatedSubProtocol
{
get
{
throw new NotImplementedException();
}
}
#endregion
}
public class EmptyWebsocket : IWebSocketConnection {
private static EmptyConnectionInfo eci =
new EmptyConnectionInfo ();
public class EmptyWebsocket : IWebSocketConnection
{
private static EmptyConnectionInfo eci =
new EmptyConnectionInfo();
#region IWebSocketConnection implementation
public System.Threading.Tasks.Task Send (string message) {
//throw new NotImplementedException ();
return null;
}
public System.Threading.Tasks.Task Send (byte[] message) {
throw new NotImplementedException ();
}
public System.Threading.Tasks.Task SendPing (byte[] message) {
throw new NotImplementedException ();
}
public System.Threading.Tasks.Task SendPong (byte[] message) {
throw new NotImplementedException ();
}
public void Close () {
#region IWebSocketConnection implementation
public System.Threading.Tasks.Task Send(string message)
{
//throw new NotImplementedException ();
return null;
}
public System.Threading.Tasks.Task Send(byte[] message)
{
throw new NotImplementedException();
}
public System.Threading.Tasks.Task SendPing(byte[] message)
{
throw new NotImplementedException();
}
public System.Threading.Tasks.Task SendPong(byte[] message)
{
throw new NotImplementedException();
}
public void Close()
{
}
public Action OnOpen {
get {
throw new NotImplementedException ();
}
set {
throw new NotImplementedException ();
}
}
public Action OnClose {
get {
throw new NotImplementedException ();
}
set {
throw new NotImplementedException ();
}
}
public Action<string> OnMessage {
get {
throw new NotImplementedException ();
}
set {
throw new NotImplementedException ();
}
}
public Action<byte[]> OnBinary {
get {
throw new NotImplementedException ();
}
set {
throw new NotImplementedException ();
}
}
public Action<byte[]> OnPing {
get {
throw new NotImplementedException ();
}
set {
throw new NotImplementedException ();
}
}
public Action<byte[]> OnPong {
get {
throw new NotImplementedException ();
}
set {
throw new NotImplementedException ();
}
}
public Action<Exception> OnError {
get {
throw new NotImplementedException ();
}
set {
throw new NotImplementedException ();
}
}
public IWebSocketConnectionInfo ConnectionInfo {
get {
return EmptyWebsocket.eci;
}
}
public bool IsAvailable {
get {
return false;
}
}
#endregion
}
}
public Action OnOpen
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public Action OnClose
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public Action<string> OnMessage
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public Action<byte[]> OnBinary
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public Action<byte[]> OnPing
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public Action<byte[]> OnPong
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public Action<Exception> OnError
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public IWebSocketConnectionInfo ConnectionInfo
{
get
{
return EmptyWebsocket.eci;
}
}
public bool IsAvailable
{
get
{
return false;
}
}
#endregion
}
}

+ 9
- 6
server/Server/Extensions.cs View File

@ -19,12 +19,15 @@
// 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.
namespace System {
namespace System
{
public static class ObjectExtensionClass {
public static string GetString (this object input) {
return input == null ? string.Empty : input.ToString ();
}
}
public static class ObjectExtensionClass
{
public static string GetString(this object input)
{
return input == null ? string.Empty : input.ToString();
}
}
}

+ 109
- 85
server/Server/Firewall.cs View File

@ -26,89 +26,113 @@ using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace Server {
public static class Firewall {
public enum UpdateEntry {
SolvedJob,
AuthSuccess,
AuthFailure,
WrongHash,
Handshake
}
private class Entry {
public string Address;
public Entry (string adr) {
Address = adr;
}
public int SolvedJobs = 0;
public int WrongHash = 0;
public int AuthSuccess = 0;
public int AuthFailure = 0;
public int Handshake = 0;
public DateTime FirstSeen = DateTime.Now;
}
private static CcDictionary<string, Entry> entries = new CcDictionary<string, Entry> ();
public const int CheckTimeInHeartbeats = 6 * 10; // every 10min
private static void AddToIpTables (Entry entry, int rule) {
Helper.WriteTextAsyncWrapper ("ip_list", entry.Address + Environment.NewLine);
CConsole.ColorWarning(() => Console.WriteLine ("Added {0} to ip_list (rule #{1})", entry.Address, rule.ToString ()));
entries.TryRemove (entry.Address);
}
public static void Update (string ip, UpdateEntry update) {
Entry entry = null;
if (entries.TryGetValue (ip, out entry)) {
if (update == UpdateEntry.SolvedJob)
entry.SolvedJobs++;
else if (update == UpdateEntry.AuthFailure)
entry.AuthFailure++;
else if (update == UpdateEntry.AuthSuccess)
entry.AuthSuccess++;
else if (update == UpdateEntry.WrongHash)
entry.WrongHash++;
else if (update == UpdateEntry.Handshake)
entry.Handshake++;
} else {
entries.TryAdd (ip, new Entry (ip));
}
}
public static void Heartbeat (int heartBeats) {
List<Entry> entrylst = new List<Entry> (entries.Values);
foreach (Entry entry in entrylst) {
// decide here...
if (entry.AuthSuccess == 0 && entry.SolvedJobs == 0 &&
entry.AuthFailure > 20) {
AddToIpTables (entry, 1);
} else if (entry.AuthFailure > 500 && entry.AuthSuccess < 500) {
AddToIpTables (entry, 2);
} else if (entry.AuthSuccess + entry.AuthFailure > 1000 && entry.SolvedJobs < 3) {
AddToIpTables (entry, 3);
} else if (entry.AuthSuccess + entry.AuthFailure > 4000) {
AddToIpTables (entry, 4);
} else if (entry.WrongHash > 0 && entry.AuthSuccess < 5) {
AddToIpTables (entry, 5);
} else if (entry.AuthSuccess + entry.AuthFailure > 2000 && entry.Handshake < 1) {
AddToIpTables (entry, 6);
}
}
if ((heartBeats % CheckTimeInHeartbeats) == 0) {
entries.Clear ();
}
}
}
namespace Server
{
public static class Firewall
{
public enum UpdateEntry
{
SolvedJob,
AuthSuccess,
AuthFailure,
WrongHash,
Handshake
}
private class Entry
{
public string Address;
public Entry(string adr)
{
Address = adr;
}
public int SolvedJobs = 0;
public int WrongHash = 0;
public int AuthSuccess = 0;
public int AuthFailure = 0;
public int Handshake = 0;
public DateTime FirstSeen = DateTime.Now;
}
private static CcDictionary<string, Entry> entries = new CcDictionary<string, Entry>();
public const int CheckTimeInHeartbeats = 6 * 10; // every 10min
private static void AddToIpTables(Entry entry, int rule)
{
Helper.WriteTextAsyncWrapper("ip_list", entry.Address + Environment.NewLine);
CConsole.ColorWarning(() => Console.WriteLine("Added {0} to ip_list (rule #{1})", entry.Address, rule.ToString()));
entries.TryRemove(entry.Address);
}
public static void Update(string ip, UpdateEntry update)
{
Entry entry = null;
if (entries.TryGetValue(ip, out entry))
{
if (update == UpdateEntry.SolvedJob)
entry.SolvedJobs++;
else if (update == UpdateEntry.AuthFailure)
entry.AuthFailure++;
else if (update == UpdateEntry.AuthSuccess)
entry.AuthSuccess++;
else if (update == UpdateEntry.WrongHash)
entry.WrongHash++;
else if (update == UpdateEntry.Handshake)
entry.Handshake++;
}
else
{
entries.TryAdd(ip, new Entry(ip));
}
}
public static void Heartbeat(int heartBeats)
{
List<Entry> entrylst = new List<Entry>(entries.Values);
foreach (Entry entry in entrylst)
{
// decide here...
if (entry.AuthSuccess == 0 && entry.SolvedJobs == 0 &&
entry.AuthFailure > 20)
{
AddToIpTables(entry, 1);
}
else if (entry.AuthFailure > 500 && entry.AuthSuccess < 500)
{
AddToIpTables(entry, 2);
}
else if (entry.AuthSuccess + entry.AuthFailure > 1000 && entry.SolvedJobs < 3)
{
AddToIpTables(entry, 3);
}
else if (entry.AuthSuccess + entry.AuthFailure > 4000)
{
AddToIpTables(entry, 4);
}
else if (entry.WrongHash > 0 && entry.AuthSuccess < 5)
{
AddToIpTables(entry, 5);
}
else if (entry.AuthSuccess + entry.AuthFailure > 2000 && entry.Handshake < 1)
{
AddToIpTables(entry, 6);
}
}
if ((heartBeats % CheckTimeInHeartbeats) == 0)
{
entries.Clear();
}
}
}
}

+ 25
- 20
server/Server/Helper.cs View File

@ -24,24 +24,29 @@ using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace Server {
public class Helper {
public static void WriteTextAsyncWrapper (string filePath, string text, FileMode fileMode = FileMode.Append) {
#pragma warning disable 4014
WriteTextAsync (filePath, text, fileMode);
#pragma warning restore 4014
}
public static async Task WriteTextAsync (string filePath, string text, FileMode fileMode = FileMode.Append) {
byte[] encodedText = Encoding.ASCII.GetBytes (text);
using (FileStream sourceStream = new FileStream (filePath,
fileMode, FileAccess.Write, FileShare.None,
bufferSize : 4096, useAsync : true)) {
await sourceStream.WriteAsync (encodedText, 0, encodedText.Length);
};
}
}
namespace Server
{
public class Helper
{
public static void WriteTextAsyncWrapper(string filePath, string text, FileMode fileMode = FileMode.Append)
{
#pragma warning disable 4014
WriteTextAsync(filePath, text, fileMode);
#pragma warning restore 4014
}
public static async Task WriteTextAsync(string filePath, string text, FileMode fileMode = FileMode.Append)
{
byte[] encodedText = Encoding.ASCII.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath,
fileMode, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
};
}
}
}

+ 153
- 114
server/Server/JSONParser.cs View File

@ -29,9 +29,11 @@ using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
namespace TinyJson {
namespace TinyJson
{
public static class JSONParser {
public static class JSONParser
{
[ThreadStatic]
static Stack<List<string>> splitArrayPool;
@ -48,69 +50,84 @@ namespace TinyJson {
[ThreadStatic]
static bool initialized = false;
public static T FromJson<T> (this string json) {
public static T FromJson<T>(this string json)
{
if (!initialized) {
if (!initialized)
{
/* Do not specify initial values for fields marked with ThreadStaticAttribute, because such initialization
* occurs only once, when the class constructor executes, and therefore affects only one thread. */
splitArrayPool = new Stack<List<string>> ();
stringBuilder = new StringBuilder ();
fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>> ();
propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>> ();
splitArrayPool = new Stack<List<string>>();
stringBuilder = new StringBuilder();
fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>>();
propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
initialized = true;
}
try {
if (string.IsNullOrEmpty (json))
return default (T);
try
{
if (string.IsNullOrEmpty(json))
return default(T);
//Remove all whitespace not within strings to make parsing simpler
stringBuilder.Length = 0;
for (int i = 0; i < json.Length; i++) {
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
if (c == '\"') {
i = AppendUntilStringEnd (true, i, json);
if (c == '\"')
{
i = AppendUntilStringEnd(true, i, json);
continue;
}
if (char.IsWhiteSpace (c))
if (char.IsWhiteSpace(c))
continue;
stringBuilder.Append (c);
stringBuilder.Append(c);
}
//Parse the thing!
return (T) ParseValue (typeof (T), stringBuilder.ToString ());
} catch { return default (T); }
return (T)ParseValue(typeof(T), stringBuilder.ToString());
}
catch { return default(T); }
}
static int AppendUntilStringEnd (bool appendEscapeCharacter, int startIdx, string json) {
stringBuilder.Append (json[startIdx]);
for (int i = startIdx + 1; i < json.Length; i++) {
if (json[i] == '\\') {
static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
{
stringBuilder.Append(json[startIdx]);
for (int i = startIdx + 1; i < json.Length; i++)
{
if (json[i] == '\\')
{
if (appendEscapeCharacter)
stringBuilder.Append (json[i]);
stringBuilder.Append (json[i + 1]);
stringBuilder.Append(json[i]);
stringBuilder.Append(json[i + 1]);
i++; //Skip next character as it is escaped
} else if (json[i] == '\"') {
stringBuilder.Append (json[i]);
}
else if (json[i] == '\"')
{
stringBuilder.Append(json[i]);
return i;
} else
stringBuilder.Append (json[i]);
}
else
stringBuilder.Append(json[i]);
}
return json.Length - 1;
}
//Splits { <value>:<value>, <value>:<value> } and [ <value>, <value> ] into a list of <value> strings
static List<string> Split (string json) {
List<string> splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop () : new List<string> ();
splitArray.Clear ();
static List<string> Split(string json)
{
List<string> splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List<string>();
splitArray.Clear();
int parseDepth = 0;
stringBuilder.Length = 0;
for (int i = 1; i < json.Length - 1; i++) {
switch (json[i]) {
for (int i = 1; i < json.Length - 1; i++)
{
switch (json[i])
{
case '[':
case '{':
parseDepth++;
@ -120,147 +137,165 @@ namespace TinyJson {
parseDepth--;
break;
case '\"':
i = AppendUntilStringEnd (true, i, json);
i = AppendUntilStringEnd(true, i, json);
continue;
case ',':
case ':':
if (parseDepth == 0) {
splitArray.Add (stringBuilder.ToString ());
if (parseDepth == 0)
{
splitArray.Add(stringBuilder.ToString());
stringBuilder.Length = 0;
continue;
}
break;
}
stringBuilder.Append (json[i]);
stringBuilder.Append(json[i]);
}
splitArray.Add (stringBuilder.ToString ());
splitArray.Add(stringBuilder.ToString());
return splitArray;
}
internal static object ParseValue (Type type, string json) {
if (type == typeof (string)) {
internal static object ParseValue(Type type, string json)
{
if (type == typeof(string))
{
if (json.Length <= 2)
return string.Empty;
string str = json.Substring (1, json.Length - 2);
return str.Replace ("\\\\", "\"\"").Replace ("\\", string.Empty).Replace ("\"\"", "\\");
string str = json.Substring(1, json.Length - 2);
return str.Replace("\\\\", "\"\"").Replace("\\", string.Empty).Replace("\"\"", "\\");
}
if (type == typeof (int)) {
int result;
int.TryParse (json, out result);
if (type == typeof(int))
{
int.TryParse(json, out int result);
return result;
}
if (type == typeof (float)) {
float result;
float.TryParse (json, out result);
if (type == typeof(float))
{
float.TryParse(json, out float result);
return result;
}
if (type == typeof (double)) {
double result;
double.TryParse (json, out result);
if (type == typeof(double))
{
double.TryParse(json, out double result);
return result;
}
if (type == typeof (bool)) {
return json.ToLower () == "true";
if (type == typeof(bool))
{
return json.ToLower() == "true";
}
if (json == "null") {
if (json == "null")
{
return null;
}
if (type.IsArray) {
Type arrayType = type.GetElementType ();
if (type.IsArray)
{
Type arrayType = type.GetElementType();
if (json[0] != '[' || json[json.Length - 1] != ']')
return null;
List<string> elems = Split (json);
Array newArray = Array.CreateInstance (arrayType, elems.Count);
List<string> elems = Split(json);
Array newArray = Array.CreateInstance(arrayType, elems.Count);
for (int i = 0; i < elems.Count; i++)
newArray.SetValue (ParseValue (arrayType, elems[i]), i);
splitArrayPool.Push (elems);
newArray.SetValue(ParseValue(arrayType, elems[i]), i);
splitArrayPool.Push(elems);
return newArray;
}
if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (List<>)) {
Type listType = type.GetGenericArguments () [0];
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type listType = type.GetGenericArguments()[0];
if (json[0] != '[' || json[json.Length - 1] != ']')
return null;
List<string> elems = Split (json);
var list = (IList) type.GetConstructor (new Type[] { typeof (int) }).Invoke (new object[] { elems.Count });
List<string> elems = Split(json);
var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count });
for (int i = 0; i < elems.Count; i++)
list.Add (ParseValue (listType, elems[i]));
splitArrayPool.Push (elems);
list.Add(ParseValue(listType, elems[i]));
splitArrayPool.Push(elems);
return list;
}
if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Dictionary<,>)) {
Type keyType, valueType; {
Type[] args = type.GetGenericArguments ();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type keyType, valueType;
{
Type[] args = type.GetGenericArguments();
keyType = args[0];
valueType = args[1];
}
//Refuse to parse dictionary keys that aren't of type string
if (keyType != typeof (string))
if (keyType != typeof(string))
return null;
//Must be a valid dictionary element
if (json[0] != '{' || json[json.Length - 1] != '}')
return null;
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split (json);
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return null;
var dictionary = (IDictionary) type.GetConstructor (new Type[] { typeof (int) }).Invoke (new object[] { elems.Count / 2 });
for (int i = 0; i < elems.Count; i += 2) {
var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 });
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
continue;
string keyValue = elems[i].Substring (1, elems[i].Length - 2);
object val = ParseValue (valueType, elems[i + 1]);
dictionary.Add (keyValue, val);
string keyValue = elems[i].Substring(1, elems[i].Length - 2);
object val = ParseValue(valueType, elems[i + 1]);
dictionary.Add(keyValue, val);
}
return dictionary;
}
if (type == typeof (object)) {
return ParseAnonymousValue (json);
if (type == typeof(object))
{
return ParseAnonymousValue(json);
}
if (json[0] == '{' && json[json.Length - 1] == '}') {
return ParseObject (type, json);
if (json[0] == '{' && json[json.Length - 1] == '}')
{
return ParseObject(type, json);
}
return null;
}
static object ParseAnonymousValue (string json) {
static object ParseAnonymousValue(string json)
{
if (json.Length == 0)
return null;
if (json[0] == '{' && json[json.Length - 1] == '}') {
List<string> elems = Split (json);
if (json[0] == '{' && json[json.Length - 1] == '}')
{
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return null;
var dict = new Dictionary<string, object> (elems.Count / 2);
var dict = new Dictionary<string, object>(elems.Count / 2);
for (int i = 0; i < elems.Count; i += 2)
dict.Add (elems[i].Substring (1, elems[i].Length - 2), ParseAnonymousValue (elems[i + 1]));
dict.Add(elems[i].Substring(1, elems[i].Length - 2), ParseAnonymousValue(elems[i + 1]));
return dict;
}
if (json[0] == '[' && json[json.Length - 1] == ']') {
List<string> items = Split (json);
var finalList = new List<object> (items.Count);
if (json[0] == '[' && json[json.Length - 1] == ']')
{
List<string> items = Split(json);
var finalList = new List<object>(items.Count);
for (int i = 0; i < items.Count; i++)
finalList.Add (ParseAnonymousValue (items[i]));
finalList.Add(ParseAnonymousValue(items[i]));
return finalList;
}
if (json[0] == '\"' && json[json.Length - 1] == '\"') {
string str = json.Substring (1, json.Length - 2);
return str.Replace ("\\", string.Empty);
if (json[0] == '\"' && json[json.Length - 1] == '\"')
{
string str = json.Substring(1, json.Length - 2);
return str.Replace("\\", string.Empty);
}
if (char.IsDigit (json[0]) || json[0] == '-') {
if (json.Contains (".")) {
double result;
double.TryParse (json, out result);
if (char.IsDigit(json[0]) || json[0] == '-')
{
if (json.Contains("."))
{
double.TryParse(json, out double result);
return result;
} else {
int result;
int.TryParse (json, out result);
}
else
{
int.TryParse(json, out int result);
return result;
}
}
@ -272,37 +307,41 @@ namespace TinyJson {
return null;
}
static object ParseObject (Type type, string json) {
object instance = FormatterServices.GetUninitializedObject (type);
static object ParseObject(Type type, string json)
{
object instance = FormatterServices.GetUninitializedObject(type);
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split (json);
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return instance;
Dictionary<string, FieldInfo> nameToField;
Dictionary<string, PropertyInfo> nameToProperty;
if (!fieldInfoCache.TryGetValue (type, out nameToField)) {
nameToField = type.GetFields ().Where (field => field.IsPublic).ToDictionary (field => field.Name);
fieldInfoCache.Add (type, nameToField);
if (!fieldInfoCache.TryGetValue(type, out nameToField))
{
nameToField = type.GetFields().Where(field => field.IsPublic).ToDictionary(field => field.Name);
fieldInfoCache.Add(type, nameToField);
}
if (!propertyInfoCache.TryGetValue (type, out nameToProperty)) {
nameToProperty = type.GetProperties ().ToDictionary (p => p.Name);
propertyInfoCache.Add (type, nameToProperty);
if (!propertyInfoCache.TryGetValue(type, out nameToProperty))
{
nameToProperty = type.GetProperties().ToDictionary(p => p.Name);
propertyInfoCache.Add(type, nameToProperty);
}
for (int i = 0; i < elems.Count; i += 2) {
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
continue;
string key = elems[i].Substring (1, elems[i].Length - 2);
string key = elems[i].Substring(1, elems[i].Length - 2);
string value = elems[i + 1];
FieldInfo fieldInfo;
PropertyInfo propertyInfo;
if (nameToField.TryGetValue (key, out fieldInfo))
fieldInfo.SetValue (instance, ParseValue (fieldInfo.FieldType, value));
else if (nameToProperty.TryGetValue (key, out propertyInfo))
propertyInfo.SetValue (instance, ParseValue (propertyInfo.PropertyType, value), null);
if (nameToField.TryGetValue(key, out fieldInfo))
fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value));
else if (nameToProperty.TryGetValue(key, out propertyInfo))
propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null);
}
return instance;

+ 305
- 256
server/Server/PoolConnection.cs View File

@ -32,386 +32,435 @@ using JsonData = System.Collections.Generic.Dictionary;
using Fleck;
namespace Server {
namespace Server
{
public class PoolConnection {
public TcpClient TcpClient;
public class PoolConnection
{
public TcpClient TcpClient;
public byte[] ReceiveBuffer;
public byte[] ReceiveBuffer;
public string Login;
public string Password;
public int Port;
public string Url;
public bool Closed;
public string Login;
public string Password;
public int Port;
public string Url;
public bool Closed;
public string PoolId;
public string Credentials;
public string PoolId;
public string Credentials;
public long Hashes = 0;
public long Hashes = 0;
public Client LastSender;
public JsonData LastJob;
public DateTime LastInteraction = DateTime.Now;
public CcHashset<string> LastSolved;
public Client LastSender;
public JsonData LastJob;
public DateTime LastInteraction = DateTime.Now;
public CcHashset<string> LastSolved;
public string DefaultAlgorithm = "cn";
public int DefaultVariant = -1;
public string DefaultAlgorithm = "cn";
public int DefaultVariant = -1;
public CcHashset<Client> WebClients = new CcHashset<Client> ();
public CcHashset<Client> WebClients = new CcHashset<Client>();
public void Send (Client client, string msg) {
try {
Byte[] bytesSent = Encoding.ASCII.GetBytes (msg);
TcpClient.GetStream ().BeginWrite (bytesSent, 0, bytesSent.Length, SendCallback, null);
this.LastSender = client;
} catch { }
}
public void Send(Client client, string msg)
{
try
{
Byte[] bytesSent = Encoding.ASCII.GetBytes(msg);
TcpClient.GetStream().BeginWrite(bytesSent, 0, bytesSent.Length, SendCallback, null);
this.LastSender = client;
}
catch { }
}
private void SendCallback (IAsyncResult result) {
if (!TcpClient.Connected) return;
private void SendCallback(IAsyncResult result)
{
if (!TcpClient.Connected) return;
try {
NetworkStream networkStream = TcpClient.GetStream ();
networkStream.EndWrite (result);
} catch { }
}
try
{
NetworkStream networkStream = TcpClient.GetStream();
networkStream.EndWrite(result);
}
catch { }
}
}
public class PoolConnectionFactory {
public delegate void ReceiveJobDelegate (Client client, JsonData json, CcHashset<string> hashset);
public delegate void ReceiveErrorDelegate (Client client, JsonData json);
public delegate void DisconnectedDelegate (Client client, string reason);
}
public class PoolConnectionFactory
{
public delegate void ReceiveJobDelegate(Client client, JsonData json, CcHashset<string> hashset);
public delegate void ReceiveErrorDelegate(Client client, JsonData json);
public delegate void DisconnectedDelegate(Client client, string reason);
private static ReceiveErrorDelegate ReceiveError;
private static ReceiveJobDelegate ReceiveJob;
private static DisconnectedDelegate Disconnect;
private static ReceiveErrorDelegate ReceiveError;
private static ReceiveJobDelegate ReceiveJob;
private static DisconnectedDelegate Disconnect;
public static CcDictionary<string, PoolConnection> Connections = new CcDictionary<string, PoolConnection> ();
public static CcDictionary<string, PoolConnection> Connections = new CcDictionary<string, PoolConnection>();
private static bool VerifyJob (JsonData data) {
if (data == null) return false;
private static bool VerifyJob(JsonData data)
{
if (data == null) return false;
if (!data.ContainsKey ("job_id")) return false;
if (!data.ContainsKey ("blob")) return false;
if (!data.ContainsKey ("target")) return false;
if (!data.ContainsKey("job_id")) return false;
if (!data.ContainsKey("blob")) return false;
if (!data.ContainsKey("target")) return false;
string blob = data["blob"].GetString ();
string target = data["target"].GetString ();
string blob = data["blob"].GetString();
string target = data["target"].GetString();
if (blob.Length < 152 || blob.Length > 180) return false;
if (target.Length != 8) return false;
if (target.Length != 8) return false;
if (!Regex.IsMatch (blob, MainClass.RegexIsHex)) return false;
if (!Regex.IsMatch (target, MainClass.RegexIsHex)) return false;
if (!Regex.IsMatch(blob, MainClass.RegexIsHex)) return false;
if (!Regex.IsMatch(target, MainClass.RegexIsHex)) return false;
return true;
}
return true;
}
private static void ReceiveCallback (IAsyncResult result) {
private static void ReceiveCallback(IAsyncResult result)
{
PoolConnection mypc = result.AsyncState as PoolConnection;
TcpClient client = mypc.TcpClient;
PoolConnection mypc = result.AsyncState as PoolConnection;
TcpClient client = mypc.TcpClient;
if (mypc.Closed || !client.Connected) return;
if (mypc.Closed || !client.Connected) return;
NetworkStream networkStream;
NetworkStream networkStream;
try { networkStream = client.GetStream (); } catch { return; }
try { networkStream = client.GetStream(); } catch { return; }
int bytesread = 0;
int bytesread = 0;
try { bytesread = networkStream.EndRead (result); } catch { return; }
try { bytesread = networkStream.EndRead(result); } catch { return; }
string json = string.Empty;
string json = string.Empty;
try {
if (bytesread == 0) // disconnected
{
try
{
if (bytesread == 0) // disconnected
{
// slow that down a bit to avoid negative feedback loop
// slow that down a bit to avoid negative feedback loop
Task.Run (async delegate {
await Task.Delay (TimeSpan.FromSeconds (4));
Task.Run(async delegate
{
await Task.Delay(TimeSpan.FromSeconds(4));
List<Client> cllist = new List<Client> (mypc.WebClients.Values);
foreach (Client ev in cllist) Disconnect (ev, "lost pool connection.");
});
List<Client> cllist = new List<Client>(mypc.WebClients.Values);
foreach (Client ev in cllist) Disconnect(ev, "lost pool connection.");
});
return;
}
return;
}
json = Encoding.ASCII.GetString (mypc.ReceiveBuffer, 0, bytesread);
json = Encoding.ASCII.GetString(mypc.ReceiveBuffer, 0, bytesread);
networkStream.BeginRead (mypc.ReceiveBuffer, 0, mypc.ReceiveBuffer.Length, new AsyncCallback (ReceiveCallback), mypc);
networkStream.BeginRead(mypc.ReceiveBuffer, 0, mypc.ReceiveBuffer.Length, new AsyncCallback(ReceiveCallback), mypc);
} catch { return; }
}
catch { return; }
if (bytesread == 0 || string.IsNullOrEmpty (json)) return; //?!
if (bytesread == 0 || string.IsNullOrEmpty(json)) return; //?!
var msg = json.FromJson<JsonData> ();
if (msg == null) return;
var msg = json.FromJson<JsonData>();
if (msg == null) return;
if (string.IsNullOrEmpty (mypc.PoolId)) {
if (string.IsNullOrEmpty(mypc.PoolId))
{
// this "protocol" is strange
if (!msg.ContainsKey ("result")) {
// this "protocol" is strange
if (!msg.ContainsKey("result"))
{
string additionalInfo = "none";
string additionalInfo = "none";
// try to get the error
if (msg.ContainsKey ("error")) {
msg = msg["error"] as JsonData;
// try to get the error
if (msg.ContainsKey("error"))
{
msg = msg["error"] as JsonData;
if (msg != null && msg.ContainsKey ("message"))
additionalInfo = msg["message"].GetString ();
}
if (msg != null && msg.ContainsKey("message"))
additionalInfo = msg["message"].GetString();
}
List<Client> cllist = new List<Client> (mypc.WebClients.Values);
foreach (Client ev in cllist)
Disconnect (ev, "can not connect. additional information: " + additionalInfo);
List<Client> cllist = new List<Client>(mypc.WebClients.Values);
foreach (Client ev in cllist)
Disconnect(ev, "can not connect. additional information: " + additionalInfo);
return;
}
return;
}
msg = msg["result"] as JsonData;
msg = msg["result"] as JsonData;