2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2026-04-04 12:28:21 +00:00
This commit is contained in:
2026-04-04 04:31:30 +03:00
parent 1339604bc5
commit 5f73cf7af7
298 changed files with 100 additions and 501 deletions

View File

@@ -0,0 +1,57 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using Esiur.Core;
using Esiur.Data;
using Esiur.Net.Packets;
using Esiur.Resource;
namespace Esiur.Net.DataLink;
public abstract class PacketFilter : IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public abstract bool Execute(Packet packet);
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}

View File

@@ -0,0 +1,121 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using Esiur.Core;
using Esiur.Data;
using System.Runtime.InteropServices;
using Esiur.Net.Packets;
using Esiur.Resource;
namespace Esiur.Net.DataLink;
public class PacketServer : IResource
{
List<PacketSource> sources = new List<PacketSource>();
List<PacketFilter> filters = new List<PacketFilter>();
[Storable]
public string Mode
{
get;
set;
}
public Instance Instance
{
get;
set;
}
public List<PacketSource> Sources
{
get
{
return sources;
}
}
public event DestroyedEvent OnDestroy;
public void Destroy()
{
OnDestroy?.Invoke(this);
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
/*
foreach (var resource in Instance.Children<IResource>())
{
if (resource is PacketFilter)
{
filters.Add(resource as PacketFilter);
}
else if (resource is PacketSource)
{
sources.Add(resource as PacketSource);
}
}
*/
foreach (var src in sources)
{
src.OnNewPacket += PacketReceived;
src.Open();
}
}
else if (trigger == ResourceTrigger.Terminate)
{
// foreach (var src in sources)
// src.Close();
}
else if (trigger == ResourceTrigger.SystemReload)
{
foreach (var src in sources)
{
src.Close();
src.Open();
}
}
return new AsyncReply<bool>(true);
}
void PacketReceived(Packet Packet)
{
foreach (var f in filters)
{
if (f.Execute(Packet))
{
break;
}
}
}
}

View File

@@ -0,0 +1,93 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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 Esiur.Net.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.DataLink;
public abstract class PacketSource : IResource
{
public delegate void NewPacket(Packet Packet);
public abstract event NewPacket OnNewPacket;
public event DestroyedEvent OnDestroy;
public Instance Instance
{
get;
set;
}
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public abstract bool RawMode
{
set;
get;
}
//public PacketSource(PacketServer Server, bool RawMode)
//{
// this.RawMode = RawMode;
//}
public abstract bool Open();
public abstract bool Close();
public abstract bool Write(Packet packet);
public void Destroy()
{
OnDestroy?.Invoke(this);
}
/*
public virtual string TypeName
{
get
{
return "Raw";
}
}
*/
public abstract byte[] Address
{
get;
}
public abstract string DeviceId
{
get;
}
}

View File

@@ -0,0 +1,37 @@
using Esiur.Core;
using Esiur.Net.Packets;
using Esiur.Protocol;
using Esiur.Resource;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Http;
public class EpOverHttp : HttpFilter
{
[Attribute]
EntryPoint EntryPoint { get; set; }
public override AsyncReply<bool> Execute(HttpConnection sender)
{
if (sender.Request.URL != "EP")
return new AsyncReply<bool>(false);
EpPacketRequest action = (EpPacketRequest)Convert.ToByte(sender.Request.Query["a"]);
if (action == EpPacketRequest.Query)
{
EntryPoint.Query(sender.Request.Query["l"], null).Then(x =>
{
});
}
return new AsyncReply<bool>(true);
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
}

View File

@@ -0,0 +1,80 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Threading.Tasks;
using Esiur.Resource;
using Esiur.Net.Sockets;
using Esiur.Core;
using Esiur.Protocol;
namespace Esiur.Net.Http;
public class EpOvwerWebsocket : HttpFilter
{
[Attribute]
public EpServer Server
{
get;
set;
}
public override AsyncReply<bool> Execute(HttpConnection sender)
{
if (sender.IsWebsocketRequest())
{
if (Server == null)
return new AsyncReply<bool>(false);
var tcpSocket = sender.Unassign();
if (tcpSocket == null)
return new AsyncReply<bool>(false);
var httpServer = sender.Parent;
var wsSocket = new WSocket(tcpSocket);
httpServer.Remove(sender);
var EPConnection = new EpConnection();
Server.Add(EPConnection);
EPConnection.Assign(wsSocket);
wsSocket.Begin();
return new AsyncReply<bool>(true);
}
return new AsyncReply<bool>(false);
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
}

View File

@@ -0,0 +1,452 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Net.Sockets;
using Esiur.Data;
using Esiur.Misc;
using System.Security.Cryptography;
using Esiur.Core;
using Esiur.Net.Packets.WebSocket;
using Esiur.Net.Packets.Http;
namespace Esiur.Net.Http;
public class HttpConnection : NetworkConnection
{
public bool WSMode { get; internal set; }
public HttpServer Server { get; internal set; }
public WebsocketPacket WSRequest { get; set; }
public HttpRequestPacket Request { get; set; }
public HttpResponsePacket Response { get; } = new HttpResponsePacket();
HttpSession session;
public KeyList<string, object> Variables { get; } = new KeyList<string, object>();
internal long Parse(byte[] data)
{
if (WSMode)
{
// now parse WS protocol
WebsocketPacket ws = new WebsocketPacket();
var pSize = ws.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{
WSRequest = ws;
return 0;
}
else
{
return pSize;
}
}
else
{
var rp = new HttpRequestPacket();
var pSize = rp.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{
Request = rp;
return 0;
}
else
{
return pSize;
}
}
}
public void Flush()
{
// close the connection
if (Request.Headers["connection"].ToLower() != "keep-alive" & IsConnected)
Close();
}
public bool Upgrade()
{
var ok = Upgrade(Request, Response);
if (ok)
{
WSMode = true;
Send();
}
return ok;
}
public static bool Upgrade(HttpRequestPacket request, HttpResponsePacket response)
{
if (IsWebsocketRequest(request))
{
string magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
string ret = request.Headers["Sec-WebSocket-Key"] + magicString;
// Compute the SHA1 hash
SHA1 sha = SHA1.Create();
byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret));
response.Headers["Upgrade"] = request.Headers["Upgrade"];
response.Headers["Connection"] = request.Headers["Connection"];// "Upgrade";
response.Headers["Sec-WebSocket-Accept"] = Convert.ToBase64String(sha1Hash);
if (request.Headers.ContainsKey("Sec-WebSocket-Protocol"))
response.Headers["Sec-WebSocket-Protocol"] = request.Headers["Sec-WebSocket-Protocol"];
response.Number = HttpResponseCode.Switching;
response.Text = "Switching Protocols";
return true;
}
return false;
}
public HttpServer Parent
{
get
{
return Server;
}
}
public void Send(WebsocketPacket packet)
{
if (packet.Data != null)
base.Send(packet.Data);
}
public override void Send(string data)
{
Response.Message = Encoding.UTF8.GetBytes(data);
Send();
}
public override void Send(byte[] msg, int offset, int length)
{
Response.Message = DC.Clip(msg, (uint)offset, (uint)length);
Send();
}
public override void Send(byte[] message)
{
Response.Message = message;
Send();
}
public void Send(HttpComposeOption Options = HttpComposeOption.AllCalculateLength)
{
if (Response.Handled)
return;
try
{
Response.Compose(Options);
base.Send(Response.Data);
// Refresh the current session
if (session != null)
session.Refresh();
}
catch
{
try
{
Close();
}
finally { }
}
finally
{
}
}
public void CreateNewSession()
{
if (session == null)
{
// Create a new one
session = Server.CreateSession(Global.GenerateCode(12), 60 * 20);
HttpCookie cookie = new HttpCookie("SID", session.Id);
cookie.Expires = DateTime.MaxValue;
cookie.Path = "/";
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
}
}
public bool IsWebsocketRequest()
{
return IsWebsocketRequest(this.Request);
}
public static bool IsWebsocketRequest(HttpRequestPacket request)
{
if (request.Headers.ContainsKey("connection")
&& request.Headers["connection"].ToLower().Contains("upgrade")
&& request.Headers.ContainsKey("upgrade")
&& request.Headers["upgrade"].ToLower() == "websocket"
&& request.Headers.ContainsKey("Sec-WebSocket-Version")
&& request.Headers["Sec-WebSocket-Version"] == "13"
&& request.Headers.ContainsKey("Sec-WebSocket-Key"))
//&& Request.Headers.ContainsKey("Sec-WebSocket-Protocol"))
{
return true;
}
else
{
return false;
}
}
protected override void DataReceived(NetworkBuffer data)
{
byte[] msg = data.Read();
var BL = Parse(msg);
if (BL == 0)
{
if (Request.Method == Packets.Http.HttpMethod.UNKNOWN)
{
Close();
return;
}
if (Request.URL == "")
{
Close();
return;
}
}
else if (BL == -1)
{
data.HoldForNextWrite(msg);
return;
}
else if (BL < 0)
{
data.HoldFor(msg, (uint)(msg.Length - BL));
return;
}
else if (BL > 0)
{
if (BL > Server.MaxPost)
{
Send(
"<html><body>POST method content is larger than "
+ Server.MaxPost
+ " bytes.</body></html>");
Close();
}
else
{
data.HoldFor(msg, (uint)(msg.Length + BL));
}
return;
}
else if (BL < 0) // for security
{
Close();
return;
}
if (IsWebsocketRequest(Request) & !WSMode)
{
Upgrade();
//return;
}
//return;
try
{
if (!Server.Execute(this))
{
Response.Number = HttpResponseCode.InternalServerError;
Send("Bad Request");
Close();
}
}
catch (Exception ex)
{
if (ex.Message != "Thread was being aborted.")
{
Global.Log("HTTPServer", LogType.Error, ex.ToString());
//Console.WriteLine(ex.ToString());
//EventLog.WriteEntry("HttpServer", ex.ToString(), EventLogEntryType.Error);
Send(Error500(ex.Message));
}
}
}
private string Error500(string msg)
{
return "<html><head><title>500 Internal Server Error</title></head><br>\r\n"
+ "<body><br>\r\n"
+ "<b>500</b> Internal Server Error<br>" + msg + "\r\n"
+ "</body><br>\r\n"
+ "</html><br>\r\n";
}
public async AsyncReply<bool> SendFile(string filename)
{
if (Response.Handled == true)
return false;
try
{
//HTTP/1.1 200 OK
//Server: Microsoft-IIS/5.0
//Content-Location: http://127.0.0.1/index.html
//Date: Wed, 10 Dec 2003 19:10:25 GMT
//Content-Type: text/html
//Accept-Ranges: bytes
//Last-Modified: Mon, 22 Sep 2003 22:36:56 GMT
//Content-Length: 1957
if (!File.Exists(filename))
{
Response.Number = HttpResponseCode.NotFound;
Send("File Not Found");
return true;
}
var fileEditTime = File.GetLastWriteTime(filename).ToUniversalTime();
if (Request.Headers.ContainsKey("if-modified-since"))
{
try
{
var ims = DateTime.Parse(Request.Headers["if-modified-since"]);
if ((fileEditTime - ims).TotalSeconds < 2)
{
Response.Number = HttpResponseCode.NotModified;
Response.Headers.Clear();
//Response.Text = "Not Modified";
Send(HttpComposeOption.SpecifiedHeadersOnly);
return true;
}
}
catch
{
return false;
}
}
Response.Number = HttpResponseCode.OK;
// Fri, 30 Oct 2007 14:19:41 GMT
Response.Headers["Last-Modified"] = fileEditTime.ToString("ddd, dd MMM yyyy HH:mm:ss");
FileInfo fi = new FileInfo(filename);
Response.Headers["Content-Length"] = fi.Length.ToString();
Send(HttpComposeOption.SpecifiedHeadersOnly);
//var fd = File.ReadAllBytes(filename);
//base.Send(fd);
using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var buffer = new byte[60000];
while (true)
{
var n = fs.Read(buffer, 0, 60000);
if (n <= 0)
break;
//Thread.Sleep(50);
await base.SendAsync(buffer, 0, n);
}
}
return true;
}
catch
{
try
{
Close();
}
finally
{
}
return false;
}
}
protected override void Connected()
{
// do nothing
}
protected override void Disconnected()
{
// do nothing
}
}

View File

@@ -0,0 +1,79 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.Http;
public abstract class HttpFilter : IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
/*
public virtual void SessionModified(HTTPSession session, string key, object oldValue, object newValue)
{
}
public virtual void SessionExpired(HTTPSession session)
{
}
*/
public abstract AsyncReply<bool> Execute(HttpConnection sender);
public virtual void ClientConnected(HttpConnection HTTP)
{
//return false;
}
public virtual void ClientDisconnected(HttpConnection HTTP)
{
//return false;
}
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}

View File

@@ -0,0 +1,394 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Net.Sockets;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
using System.Security.Cryptography.X509Certificates;
using Esiur.Resource;
using System.Text.RegularExpressions;
using System.Linq;
using System.Reflection;
using Esiur.Net.Packets.Http;
namespace Esiur.Net.Http;
public class HttpServer : NetworkServer<HttpConnection>, IResource
{
Dictionary<string, HttpSession> sessions = new Dictionary<string, HttpSession>();
HttpFilter[] filters = new HttpFilter[0];
Dictionary<Packets.Http.HttpMethod, List<RouteInfo>> routes = new()
{
[Packets.Http.HttpMethod.GET] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.POST] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.HEAD] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.OPTIONS] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.UNKNOWN] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.DELETE] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.TRACE] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.CONNECT] = new List<RouteInfo>(),
[Packets.Http.HttpMethod.PUT] = new List<RouteInfo>()
};
//List<RouteInfo> GetRoutes = new List<RouteInfo>();
//List<RouteInfo> PostRoutes = new List<RouteInfo>();
class RouteInfo
{
public Delegate Handler;
public Regex Pattern;
Dictionary<string, ParameterInfo> ParameterIndex = new();
int? SenderIndex;
//bool HasSender;
int ArgumentsCount;
public RouteInfo(Delegate handler, Regex pattern)
{
Pattern = pattern;
Handler = handler;
var ps = handler.Method.GetParameters();
ArgumentsCount = ps.Length;
var last = ps.LastOrDefault();
if (last != null && last.ParameterType == typeof(HttpConnection))
{
SenderIndex = ps.Length - 1;
for (var i = 0; i < ps.Length - 1; i++)
ParameterIndex[ps[i].Name] = ps[i];
}
else
{
for (var i = 0; i < ps.Length; i++)
ParameterIndex[ps[i].Name] = ps[i];
}
}
public bool Invoke(HttpConnection sender)
{
var match = Pattern.Match(sender.Request.URL);
if (!match.Success)
return false;
var args = new object[ArgumentsCount];
foreach (var kv in ParameterIndex)
{
var g = match.Groups[kv.Key];
args[kv.Value.Position] = RuntimeCaster.Cast(g.Value, kv.Value.ParameterType);
}
if (SenderIndex != null)
args[(int)SenderIndex] = sender;
var rt = Handler.DynamicInvoke(args);
if (rt is bool)
return (bool)rt;
return true;
}
}
public Instance Instance
{
get;
set;
}
[Attribute]
public virtual string IP
{
get;
set;
}
[Attribute]
public virtual ushort Port
{
get;
set;
}
[Attribute]
public virtual uint MaxPost
{
get;
set;
}
[Attribute]
public virtual bool SSL
{
get;
set;
}
[Attribute]
public virtual string Certificate
{
get;
set;
}
public HttpSession CreateSession(string id, int timeout)
{
var s = new HttpSession();
s.Set(id, timeout);
sessions.Add(id, s);
return s;
}
public static string MakeCookie(string Item, string Value, DateTime Expires, string Domain, string Path, bool HttpOnly)
{
//Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/
//Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/
string Cookie = Item + "=" + Value;
if (Expires.Ticks != 0)
{
Cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT";
}
if (Domain != null)
{
Cookie += "; domain=" + Domain;
}
if (Path != null)
{
Cookie += "; path=" + Path;
}
if (HttpOnly)
{
Cookie += "; HttpOnly";
}
return Cookie;
}
protected override void ClientDisconnected(HttpConnection connection)
{
foreach (var filter in filters)
filter.ClientDisconnected(connection);
}
internal bool Execute(HttpConnection sender)
{
if (!sender.WSMode)
foreach (var route in routes[sender.Request.Method])
if (route.Invoke(sender))
return true;
foreach (var resource in filters)
if (resource.Execute(sender).Wait(30000))
return true;
return false;
}
public void MapGet(string pattern, Delegate handler)
{
var regex = Global.GetRouteRegex(pattern);
var list = routes[Packets.Http.HttpMethod.GET];
list.Add(new RouteInfo(handler, regex));
}
public void MapPost(string pattern, Delegate handler)
{
var regex = Global.GetRouteRegex(pattern);
var list = routes[Packets.Http.HttpMethod.POST];
list.Add(new RouteInfo(handler, regex));
}
/*
protected override void SessionEnded(NetworkSession session)
{
// verify wether there are no active connections related to the session
foreach (HTTPConnection c in Connections)//.Values)
{
if (c.Session == session)
{
session.Refresh();
return;
}
}
foreach (Instance instance in Instance.Children)
{
var f = (HTTPFilter)instance.Resource;
f.SessionExpired((HTTPSession)session);
}
base.SessionEnded((HTTPSession)session);
//Sessions.Remove(Session.ID);
//Session.Dispose();
}
*/
/*
public int TTL
{
get
{
return Timeout;// mTimeout;
}
}
*/
public async AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
//var ip = (IPAddress)Instance.Attributes["ip"];
//var port = (int)Instance.Attributes["port"];
//var ssl = (bool)Instance.Attributes["ssl"];
//var cert = (string)Instance.Attributes["certificate"];
//if (ip == null) ip = IPAddress.Any;
Sockets.ISocket listener;
IPAddress ipAdd;
if (IP == null)
ipAdd = IPAddress.Any;
else
ipAdd = IPAddress.Parse(IP);
if (SSL)
listener = new SSLSocket(new IPEndPoint(ipAdd, Port), new X509Certificate2(Certificate));
else
listener = new TCPSocket(new IPEndPoint(ipAdd, Port));
Start(listener);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
await Trigger(ResourceTrigger.Terminate);
await Trigger(ResourceTrigger.Initialize);
}
else if (trigger == ResourceTrigger.SystemInitialized)
{
filters = await Instance.Children<HttpFilter>();
}
return true;
}
public override void Add(HttpConnection connection)
{
connection.Server = this;
base.Add(connection);
}
public override void Remove(HttpConnection connection)
{
connection.Server = null;
base.Remove(connection);
}
protected override void ClientConnected(HttpConnection connection)
{
//if (filters.Length == 0 && routes.)
//{
// connection.Close();
// return;
//}
foreach (var resource in filters)
{
resource.ClientConnected(connection);
}
}
/*
public int LocalPort
{
get
{
return cServer.LocalPort;
}
}
*/
/*
public HTTPServer(int Port)
{
cServer = new TServer();
cServer.LocalPort = Port;
cServer.StartServer();
cServer.ClientConnected += new TServer.eClientConnected(ClientConnected);
cServer.ClientDisConnected += new TServer.eClientDisConnected(ClientDisConnected);
cServer.ClientIsSwitching += new TServer.eClientIsSwitching(ClientIsSwitching);
cServer.DataReceived += new TServer.eDataReceived(DataReceived);
}*/
//~HTTPServer()
//{
// cServer.StopServer();
//}
}

View File

@@ -0,0 +1,128 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
namespace Esiur.Net.Http;
public class HttpSession : IDestructible //<T> where T : TClient
{
public delegate void SessionModifiedEvent(HttpSession session, string key, object oldValue, object newValue);
public delegate void SessionEndedEvent(HttpSession session);
private string id;
private Timer timer;
private int timeout;
DateTime creation;
DateTime lastAction;
private KeyList<string, object> variables;
public event SessionEndedEvent OnEnd;
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> Variables
{
get { return variables; }
}
public HttpSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now;
}
internal void Set(string id, int timeout)
{
//modified = sessionModifiedEvent;
//ended = sessionEndEvent;
this.id = id;
if (this.timeout != 0)
{
this.timeout = timeout;
timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
creation = DateTime.Now;
}
}
private void OnSessionEndTimerCallback(object o)
{
OnEnd?.Invoke(this);
}
void VariablesModified(string key, object oldValue, object newValue, KeyList<string, object> sender)
{
OnModify?.Invoke(this, key, oldValue, newValue);
}
public void Destroy()
{
OnDestroy?.Invoke(this);
timer.Dispose();
timer = null;
}
internal void Refresh()
{
lastAction = DateTime.Now;
timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
}
public int Timeout // Seconds
{
get
{
return timeout;
}
set
{
timeout = value;
Refresh();
}
}
public string Id
{
get { return id; }
}
public DateTime LastAction
{
get { return lastAction; }
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net;
public interface INetworkReceiver<T>
{
void NetworkClose(T sender);
void NetworkReceive(T sender, NetworkBuffer buffer);
//void NetworkError(T sender);
void NetworkConnect(T sender);
}

View File

@@ -0,0 +1,206 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using Esiur.Data;
using Esiur.Misc;
namespace Esiur.Net;
public class NetworkBuffer
{
byte[] data;
uint neededDataLength = 0;
//bool trim;
object syncLock = new object();
//public object SyncLock
//{
// get { return syncLock; }
//}
public NetworkBuffer()
{
data = new byte[0];
}
public bool Protected
{
get
{
return neededDataLength > data.Length;
}
}
public uint Available
{
get
{
return (uint)data.Length;
}
}
//public void HoldForAtLeast(byte[] src, uint offset, uint size, uint needed)
//{
// HoldFor(src, offset, size, needed);
// //trim = false;
//}
//public void HoldForAtLeast(byte[] src, uint needed)
//{
// HoldForAtLeast(src, 0, (uint)src.Length, needed);
//}
public void HoldForNextWrite(byte[] src)
{
//HoldForAtLeast(src, (uint)src.Length + 1);
HoldFor(src, (uint)src.Length + 1);
}
public void HoldForNextWrite(byte[] src, uint offset, uint size)
{
//HoldForAtLeast(src, offset, size, size + 1);
HoldFor(src, offset, size, size + 1);
}
public void HoldFor(byte[] src, uint offset, uint size, uint needed)
{
lock (syncLock)
{
if (size >= needed)
throw new Exception("Size >= Needed !");
//trim = true;
data = DC.Combine(src, offset, size, data, 0, (uint)data.Length);
neededDataLength = needed;
// Console.WriteLine("Hold StackTrace: '{0}'", Environment.StackTrace);
//Console.WriteLine("Holded {0} {1} {2} {3} - {4}", offset, size, needed, data.Length, GetHashCode());
}
}
public void HoldFor(byte[] src, uint needed)
{
HoldFor(src, 0, (uint)src.Length, needed);
}
public bool Protect(byte[] data, uint offset, uint needed)//, bool exact = false)
{
uint dataLength = (uint)data.Length - offset;
// protection
if (dataLength < needed)
{
//if (exact)
// HoldFor(data, offset, dataLength, needed);
//else
//HoldForAtLeast(data, offset, dataLength, needed);
HoldFor(data, offset, dataLength, needed);
return true;
}
else
return false;
}
public void Write(byte[] src)
{
Write(src, 0, (uint)src.Length);
}
public void Write(byte[] src, uint offset, uint length)
{
//if (data.Length > 0)
// Console.WriteLine();
lock (syncLock)
DC.Append(ref data, src, offset, length);
}
public bool CanRead
{
get
{
if (data.Length == 0)
return false;
if (data.Length < neededDataLength)
return false;
return true;
}
}
public byte[] Read()
{
lock (syncLock)
{
if (data.Length == 0)
return null;
byte[] rt = null;
if (neededDataLength == 0)
{
rt = data;
data = new byte[0];
return rt;
}
else
{
//Console.WriteLine("P STATE:" + data.Length + " " + neededDataLength);
if (data.Length >= neededDataLength)
{
//Console.WriteLine("data.Length >= neededDataLength " + data.Length + " >= " + neededDataLength + " " + trim);
//if (trim)
//{
// rt = DC.Clip(data, 0, neededDataLength);
// data = DC.Clip(data, neededDataLength, (uint)data.Length - neededDataLength);
//}
//else
//{
// return all data
rt = data;
data = new byte[0];
//}
neededDataLength = 0;
return rt;
}
else
{
return null;
}
}
}
}
}

View File

@@ -0,0 +1,365 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Misc;
using Esiur.Core;
using Esiur.Data;
using Esiur.Net.Sockets;
using Esiur.Resource;
namespace Esiur.Net;
public abstract class NetworkConnection : IDestructible, INetworkReceiver<ISocket>// <TS>: IResource where TS : NetworkSession
{
private Sockets.ISocket sock;
// private bool connected;
private DateTime lastAction;
//public delegate void DataReceivedEvent(NetworkConnection sender, NetworkBuffer data);
//public delegate void ConnectionClosedEvent(NetworkConnection sender);
public delegate void NetworkConnectionEvent(NetworkConnection connection);
public event NetworkConnectionEvent OnConnect;
//public event DataReceivedEvent OnDataReceived;
public event NetworkConnectionEvent OnClose;
public event DestroyedEvent OnDestroy;
//object receivingLock = new object();
//object sendLock = new object();
bool processing = false;
// public INetworkReceiver<NetworkConnection> Receiver { get; set; }
public virtual void Destroy()
{
// remove references
//sock.OnClose -= Socket_OnClose;
//sock.OnConnect -= Socket_OnConnect;
//sock.OnReceive -= Socket_OnReceive;
sock?.Destroy();
//Receiver = null;
Close();
sock = null;
OnClose = null;
OnConnect = null;
//OnDataReceived = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public ISocket Socket
{
get
{
return sock;
}
}
public virtual void Assign(ISocket socket)
{
lastAction = DateTime.Now;
sock = socket;
sock.Receiver = this;
//socket.OnReceive += Socket_OnReceive;
//socket.OnClose += Socket_OnClose;
//socket.OnConnect += Socket_OnConnect;
}
//private void Socket_OnConnect()
//{
// OnConnect?.Invoke(this);
//}
//private void Socket_OnClose()
//{
// ConnectionClosed();
// OnClose?.Invoke(this);
//}
//protected virtual void ConnectionClosed()
//{
//}
//private void Socket_OnReceive(NetworkBuffer buffer)
//{
//}
public ISocket Unassign()
{
if (sock != null)
{
// connected = false;
//sock.OnClose -= Socket_OnClose;
//sock.OnConnect -= Socket_OnConnect;
//sock.OnReceive -= Socket_OnReceive;
sock.Receiver = null;
var rt = sock;
sock = null;
return rt;
}
else
return null;
}
//protected virtual void DataReceived(NetworkBuffer data)
//{
// if (OnDataReceived != null)
// {
// try
// {
// OnDataReceived?.Invoke(this, data);
// }
// catch (Exception ex)
// {
// Global.Log("NetworkConenction:DataReceived", LogType.Error, ex.ToString());
// }
// }
//}
public void Close()
{
//if (!connected)
// return;
try
{
if (sock != null)
sock.Close();
}
catch (Exception ex)
{
Global.Log("NetworkConenction:Close", LogType.Error, ex.ToString());
}
//finally
//{
//connected = false;
//}
}
public DateTime LastAction
{
get { return lastAction; }
}
public IPEndPoint RemoteEndPoint
{
get
{
if (sock != null)
return (IPEndPoint)sock.RemoteEndPoint;
else
return null;
}
}
public IPEndPoint LocalEndPoint
{
get
{
if (sock != null)
return (IPEndPoint)sock.LocalEndPoint;
else
return null;
}
}
public bool IsConnected
{
get
{
return sock == null ? false : sock.State == SocketState.Established;
}
}
/*
public void CloseAndWait()
{
try
{
if (!connected)
return;
if (sock != null)
sock.Close();
while (connected)
{
Thread.Sleep(100);
}
}
finally
{
}
}
*/
public virtual AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
try
{
lastAction = DateTime.Now;
return sock.SendAsync(message, offset, length);
}
catch
{
return new AsyncReply<bool>(false);
}
}
public virtual void Send(byte[] msg)
{
try
{
sock?.Send(msg);
lastAction = DateTime.Now;
}
catch
{
}
}
public virtual void Send(byte[] msg, int offset, int length)
{
try
{
sock.Send(msg, offset, length);
lastAction = DateTime.Now;
}
catch
{
}
}
public virtual void Send(string data)
{
Send(Encoding.UTF8.GetBytes(data));
}
public void NetworkClose(ISocket socket)
{
Disconnected();
OnClose?.Invoke(this);
}
public void NetworkConnect(ISocket socket)
{
Connected();
OnConnect?.Invoke(this);
}
//{
//ConnectionClosed();
//OnClose?.Invoke(this);
//Receiver?.NetworkClose(this);
//}
//public void NetworkConenct(ISocket sender)
//{
// OnConnect?.Invoke(this);
//}
protected abstract void DataReceived(NetworkBuffer buffer);
protected abstract void Connected();
protected abstract void Disconnected();
public void NetworkReceive(ISocket sender, NetworkBuffer buffer)
{
try
{
// Unassigned ?
if (sock == null)
return;
// Closed ?
if (sock.State == SocketState.Closed)// || sock.State == SocketState.Terminated) // || !connected)
return;
lastAction = DateTime.Now;
if (!processing)
{
processing = true;
try
{
//lock(buffer.SyncLock)
while (buffer.Available > 0 && !buffer.Protected)
{
//Receiver?.NetworkReceive(this, buffer);
DataReceived(buffer);
}
}
catch
{
}
processing = false;
}
}
catch (Exception ex)
{
Global.Log("NetworkConnection", LogType.Warning, ex.ToString());
}
}
//{
// Receiver?.NetworkError(this);
//throw new NotImplementedException();
//}
//public void NetworkConnect(ISocket sender)
//{
// Receiver?.NetworkConnect(this);
//throw new NotImplementedException();
//}
}

View File

@@ -0,0 +1,297 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Threading;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
using Esiur.Net.Sockets;
using Esiur.Resource;
using System.Threading.Tasks;
using System.Diagnostics;
namespace Esiur.Net;
public abstract class NetworkServer<TConnection> : IDestructible where TConnection : NetworkConnection, new()
{
//private bool isRunning;
private Sockets.ISocket listener;
public AutoList<TConnection, NetworkServer<TConnection>> Connections { get; internal set; }
private Thread thread;
//protected abstract void DataReceived(TConnection sender, NetworkBuffer data);
//protected abstract void ClientConnected(TConnection sender);
//protected abstract void ClientDisconnected(TConnection sender);
private Timer timer;
//public KeyList<string, TSession> Sessions = new KeyList<string, TSession>();
public event DestroyedEvent OnDestroy;
//public AutoList<TConnection, NetworkServer<TConnection>> Connections => connections;
private void MinuteThread(object state)
{
List<TConnection> ToBeClosed = null;
lock (Connections.SyncRoot)
{
foreach (TConnection c in Connections)
{
if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= Timeout)
{
if (ToBeClosed == null)
ToBeClosed = new List<TConnection>();
ToBeClosed.Add(c);
}
}
}
if (ToBeClosed != null)
{
//Console.WriteLine("Term: " + ToBeClosed.Count + " " + this.listener.LocalEndPoint.ToString());
foreach (TConnection c in ToBeClosed)
c.Close();// CloseAndWait();
ToBeClosed.Clear();
ToBeClosed = null;
}
}
public void Start(Sockets.ISocket socket)//, uint timeout, uint clock)
{
if (listener != null)
return;
Connections = new AutoList<TConnection, NetworkServer<TConnection>>(this);
if (Timeout > 0 & Clock > 0)
{
timer = new Timer(MinuteThread, null, TimeSpan.FromMinutes(0), TimeSpan.FromSeconds(Clock));
}
listener = socket;
// Start accepting
//var r = listener.Accept();
//r.Then(NewConnection);
//r.timeout?.Dispose();
//var rt = listener.Accept().Then()
thread = new Thread(new ThreadStart(() =>
{
while (true)
{
try
{
var s = listener.Accept();
if (s == null)
{
Global.Log("NetworkServer", LogType.Error, "sock == null");
return;
}
//Console.WriteLine("New Socket ... " + DateTime.Now);
var c = new TConnection();
c.Assign(s);
Add(c);
try
{
ClientConnected(c);
}
catch
{
// something wrong with the child.
}
s.Begin();
// Accept more
//listener.Accept().Then(NewConnection);
}
catch (Exception ex)
{
Global.Log(ex);
}
}
}));
thread.Start();
}
[Attribute]
public uint Timeout
{
get;
set;
}
[Attribute]
public uint Clock
{
get;
set;
}
public void Stop()
{
var port = 0;
try
{
if (listener != null)
{
port = listener.LocalEndPoint.Port;
listener.Close();
}
// wait until the listener stops
//while (isRunning)
//{
// Thread.Sleep(100);
//}
//Console.WriteLine("Listener stopped");
var cons = Connections.ToArray();
//lock (connections.SyncRoot)
//{
foreach (TConnection con in cons)
con.Close();
//}
//Console.WriteLine("Sockets Closed");
//while (connections.Count > 0)
//{
// Console.WriteLine("Waiting... " + connections.Count);
// Thread.Sleep(1000);
//}
}
finally
{
Global.Log("NetworkServer", LogType.Warning, $"Server@{port} is down.");
}
}
public virtual void Remove(TConnection connection)
{
connection.OnClose -= ClientDisconnectedEventReceiver;
Connections.Remove(connection);
}
public virtual void Add(TConnection connection)
{
connection.OnClose += ClientDisconnectedEventReceiver;
Connections.Add(connection);
}
public bool IsRunning
{
get
{
return listener.State == SocketState.Listening;
//isRunning;
}
}
//public void OnDataReceived(ISocket sender, NetworkBuffer data)
//{
// DataReceived((TConnection)sender, data);
//}
//public void OnClientConnect(ISocket sender)
//{
// if (sender == null)
// return;
// if (sender.RemoteEndPoint == null || sender.LocalEndPoint == null)
// { }
// //Console.WriteLine("NULL");
// else
// Global.Log("Connections", LogType.Debug, sender.RemoteEndPoint.Address.ToString()
// + "->" + sender.LocalEndPoint.Port + " at " + DateTime.UtcNow.ToString("d")
// + " " + DateTime.UtcNow.ToString("d"), false);
// // Console.WriteLine("Connected " + sender.RemoteEndPoint.ToString());
// ClientConnected((TConnection)sender);
//}
//public void OnClientClose(ISocket sender)
//{
//}
public void Destroy()
{
Stop();
OnDestroy?.Invoke(this);
}
private void ClientDisconnectedEventReceiver(NetworkConnection connection)
{
try
{
var con = connection as TConnection;
con.Destroy();
Remove(con);
ClientDisconnected(con);
}
catch (Exception ex)
{
Global.Log(ex);
}
}
protected abstract void ClientDisconnected(TConnection connection);
protected abstract void ClientConnected(TConnection connection);
~NetworkServer()
{
Stop();
listener = null;
}
}

View File

@@ -0,0 +1,128 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Core;
namespace Esiur.Net;
public class NetworkSession : IDestructible //<T> where T : TClient
{
public delegate void SessionModifiedEvent(NetworkSession session, string key, object oldValue, object newValue);
public delegate void SessionEndedEvent(NetworkSession session);
private string id;
private Timer timer;
private int timeout;
DateTime creation;
DateTime lastAction;
private KeyList<string, object> variables;
public event SessionEndedEvent OnEnd;
public event SessionModifiedEvent OnModify;
public event DestroyedEvent OnDestroy;
public KeyList<string, object> Variables
{
get { return variables; }
}
public NetworkSession()
{
variables = new KeyList<string, object>();
variables.OnModified += new KeyList<string, object>.Modified(VariablesModified);
creation = DateTime.Now;
}
internal void Set(string id, int timeout)
{
//modified = sessionModifiedEvent;
//ended = sessionEndEvent;
this.id = id;
if (this.timeout != 0)
{
this.timeout = timeout;
timer = new Timer(OnSessionEndTimerCallback, null, TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
creation = DateTime.Now;
}
}
private void OnSessionEndTimerCallback(object o)
{
OnEnd?.Invoke(this);
}
void VariablesModified(string key, object oldValue, object newValue, KeyList<string, object> sender)
{
OnModify?.Invoke(this, key, oldValue, newValue);
}
public void Destroy()
{
OnDestroy?.Invoke(this);
timer.Dispose();
timer = null;
}
internal void Refresh()
{
lastAction = DateTime.Now;
timer.Change(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(0));
}
public int Timeout // Seconds
{
get
{
return timeout;
}
set
{
timeout = value;
Refresh();
}
}
public string Id
{
get { return id; }
}
public DateTime LastAction
{
get { return lastAction; }
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public static class EpAuthExtensions
{
public static EpAuthPacketIAuthFormat GetIAuthFormat(this object value)
{
if (value is string)
return EpAuthPacketIAuthFormat.Text;
else if (value is int || value is uint
|| value is byte || value is sbyte
|| value is short || value is ushort
|| value is long || value is ulong)
return EpAuthPacketIAuthFormat.Number;
else if (value.GetType().IsArray)
return EpAuthPacketIAuthFormat.Choice;
throw new Exception("Unknown IAuth format");
}
}
}

View File

@@ -0,0 +1,191 @@
/*
Copyright (c) 2017-2026 Ahmed Kh. Zamil
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 Esiur.Data;
using Esiur.Security.Authority;
using Esiur.Security.Cryptography;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace Esiur.Net.Packets;
public class EpAuthPacket : Packet
{
public EpAuthPacketCommand Command
{
get;
set;
}
public EpAuthPacketAction Action
{
get;
set;
}
public EpAuthPacketEvent Event
{
get;
set;
}
public EpAuthPacketAcknowledgement Acknowledgement
{
get;
set;
}
public AuthenticationMode AuthMode
{
get;
set;
}
public EncryptionMode EncryptionMode
{
get;
set;
}
//public AuthenticationMethod AuthenticationMethod
//{
// get;
// set;
//}
public byte ErrorCode
{
get;
set;
}
public string Message
{
get;
set;
}
public byte[] SessionId
{
get;
set;
}
public ParsedTdu? Tdu
{
get;
set;
}
// IAuth Reference
public uint Reference
{
get;
set;
}
private uint dataLengthNeeded;
bool NotEnough(uint offset, uint ends, uint needed)
{
if (offset + needed > ends)
{
dataLengthNeeded = needed - (ends - offset);
return true;
}
else
return false;
}
public override string ToString()
{
return Command.ToString() + " " + Action.ToString();
}
public override long Parse(byte[] data, uint offset, uint ends)
{
var oOffset = offset;
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
Command = (EpAuthPacketCommand)(data[offset] >> 6);
var hasTdu = (data[offset] & 0x20) != 0;
if (Command == EpAuthPacketCommand.Initialize)
{
AuthMode = (AuthenticationMode)(data[offset] >> 3 & 0x7);
EncryptionMode = (EncryptionMode)(data[offset++] & 0x7);
}
else if (Command == EpAuthPacketCommand.Acknowledge)
{
// remove last two reserved LSBs
Acknowledgement = (EpAuthPacketAcknowledgement)(data[offset++]);// & 0xFC);
}
else if (Command == EpAuthPacketCommand.Action)
{
// remove last two reserved LSBs
Action = (EpAuthPacketAction)(data[offset++]);// & 0xFC);
}
else if (Command == EpAuthPacketCommand.Event)
{
// remove last two reserved LSBs
Event = (EpAuthPacketEvent)(data[offset++]);// & 0xFC);
}
else
{
return -1; // invalid command
}
if (hasTdu)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
Tdu = ParsedTdu.Parse(data, offset, ends);
if (Tdu.Value.Class == TduClass.Invalid)
return -(int)Tdu.Value.TotalLength;
offset += (uint)Tdu.Value.TotalLength;
}
return offset - oOffset;
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketAcknowledgement : byte
{
Denied = 0x40, // no reason, terminate connection
NotSupported = 0x41, // auth not supported, terminate connection
TrySupported = 0x42, // auth not supported, but other auth methods in the reply are supported. connection is still open
Retry = 0x43, // try another auth method, connection is still open
ProceedToHandshake = 0x44, // auth method accepted, proceed to handshake, connection is still open
ProceedToFinalHandshake = 0x45, // auth method accepted, proceed to final handshake, connection is still open
ProceedToEstablishSession = 0x46, // auth method accepted, proceed to establish session, connection is still open
SessionEstablished = 0x47, // session established, session Id provided, switch to session mode, connection is still open
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketAction : byte
{
Handshake = 0x80,
FinalHandshake = 0x81,
//AuthenticateHash = 0x80,
//AuthenticatePublicHash = 0x81,
//AuthenticatePrivateHash = 0x82,
//AuthenticatePublicPrivateHash = 0x83,
//AuthenticatePrivateHashCert = 0x88,
//AuthenticatePublicPrivateHashCert = 0x89,
//IAuthPlain = 0x90,
//IAuthHashed = 0x91,
//IAuthEncrypted = 0x92,
//EstablishNewSession = 0x98,
//EstablishResumeSession = 0x99,
//EncryptKeyExchange = 0xA0,
//RegisterEndToEndKey = 0xA8,
//RegisterHomomorphic = 0xA9,
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketAuthMode : byte
{
NoAuh = 0x0,
InitializerIdentity = 0x1,
ResponderIdentity = 0x2,
DualIdentity = 0x3,
//NoAuthNoAuth = 0x0, //0b00000000,
//NoAuthCredentials = 0x4, //0b00000100,
//NoAuthToken = 0x8, //0b00001000,
//NoAuthCertificate = 0xC, //0b00001100,
//CredentialsNoAuth = 0x10, //0b00010000,
//CredentialsCredentials = 0x14, //0b00010100,
//CredentialsToken = 0x18, //0b00011000,
//CredentialsCertificate = 0x1c, //0b00011100,
//TokenNoAuth = 0x20, //0b00100000,
//TokenCredentials = 0x24, //0b00100100,
//TokenToken = 0x28, //0b00101000,
//TokenCertificate = 0x2c, //0b00101100,
//CertificateNoAuth = 0x30, //0b00110000,
//CertificateCredentials = 0x34,// 0b00110100,
//CertificateToken = 0x38, //0b00111000,
//CertificateCertificate = 0x3c, //0b00111100,
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketCommand : byte
{
Initialize = 0x0,
Acknowledge = 0x1,
Action = 0x2,
Event = 0x3,
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketEncryptionMode
{
NoEncryption,
EncryptWithSessionKey,
EncryptWithSessionKeyAndAddress,
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketEvent : byte
{
ErrorTerminate = 0xC0,
ErrorMustEncrypt = 0xC1,
ErrorRetry = 0xC2,
IndicationEstablished = 0xC8,
IAuthPlain = 0xD0,
IAuthHashed = 0xD1,
IAuthEncrypted = 0xD2
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketHeader
{
Version,
Domain,
SupportedAuthentications ,
SupportedHashAlgorithms,
SupportedCiphers,
SupportedCompression,
SupportedMultiFactorAuthentications,
CipherType,
CipherKey,
SoftwareIdentity,
Referrer,
Time,
IPAddress,
AuthenticationData,
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketIAuthDestination
{
Self = 0,
Device = 1, // logged in device
Email = 2,
SMS = 3,
App = 4, // Authenticator app
ThirdParty = 5, // usually a second person
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketIAuthFormat
{
None = 0,
Number = 1,
Text = 2,
LowercaseText = 3,
Choice = 4,
Photo = 5,
Signature = 6,
Fingerprint = 7,
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpAuthPacketIAuthHeader : byte
{
Reference = 0,
Destination = 1,
Clue = 2,
RequiredFormat = 3,
ContentFormat = 4,
Content = 5,
Trials = 6,
Issue = 7,
Expire = 8,
}
}

View File

@@ -0,0 +1,141 @@
/*
Copyright (c) 2017-2026 Ahmed Kh. Zamil
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 Esiur.Data;
using Esiur.Core;
using Esiur.Misc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Packets;
class EpPacket : Packet
{
public uint CallbackId { get; set; }
public EpPacketMethod Method { get; set; }
public EpPacketRequest Request { get; set; }
public EpPacketReply Reply { get; set; }
public EpPacketNotification Notification { get; set; }
public byte Extension { get; set; }
public ParsedTdu? Tdu { get; set; }
private uint dataLengthNeeded;
private uint originalOffset;
public override bool Compose()
{
return base.Compose();
}
public override string ToString()
{
return Method switch
{
EpPacketMethod.Notification => $"{Method} {Notification}",
EpPacketMethod.Request => $"{Method} {Request}",
EpPacketMethod.Reply => $"{Method} {Reply}",
EpPacketMethod.Extension => $"{Method} {Extension}",
_ => $"{Method}"
};
}
bool NotEnough(uint offset, uint ends, uint needed)
{
if (offset + needed > ends)
{
dataLengthNeeded = needed - (ends - offset);
return true;
}
else
return false;
}
public override long Parse(byte[] data, uint offset, uint ends)
{
originalOffset = offset;
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var hasDTU = (data[offset] & 0x20) == 0x20;
Method = (EpPacketMethod)(data[offset] >> 6);
if (Method == EpPacketMethod.Notification)
{
Notification = (EpPacketNotification)(data[offset++] & 0x1f);
}
else if (Method == EpPacketMethod.Request)
{
Request = (EpPacketRequest)(data[offset++] & 0x1f);
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
CallbackId = data.GetUInt32(offset, Endian.Little);
offset += 4;
}
else if (Method == EpPacketMethod.Reply)
{
Reply = (EpPacketReply)(data[offset++] & 0x1f);
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
CallbackId = data.GetUInt32(offset, Endian.Little);
offset += 4;
}
else if (Method == EpPacketMethod.Extension)
{
Extension = (byte)(data[offset++] & 0x1f);
}
if (hasDTU)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
Tdu = ParsedTdu.Parse(data, offset, ends);
if (Tdu.Value.Class == TduClass.Invalid)
return -(int)Tdu.Value.TotalLength;
offset += (uint)Tdu.Value.TotalLength;
}
else
{
Tdu = null;
}
return offset - originalOffset;
}
}

View File

@@ -0,0 +1,22 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets;
struct EpPacketAttachInfo
{
public string Link;
public ulong Age;
public byte[] Content;
public Uuid TypeId;
public EpPacketAttachInfo(Uuid typeId, ulong age, string link, byte[] content)
{
TypeId = typeId;
Age = age;
Content = content;
Link = link;
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpPacketMethod : byte
{
Notification = 0,
Request,
Reply,
Extension,
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpPacketNotification : byte
{
// Notification Invoke
PropertyModified = 0x0,
EventOccurred = 0x1,
// Notification Manage
ResourceDestroyed = 0x8,
ResourceReassigned = 0x9,
ResourceMoved = 0xA,
SystemFailure = 0xB,
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpPacketReply : byte
{
// Success
Completed = 0x0,
Propagated = 0x1,
Stream = 0x2,
// Error
PermissionError = 0x81,
ExecutionError = 0x82,
// Partial
Progress = 0x10,
Chunk = 0x11,
Warning = 0x12
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpPacketReport : byte
{
ManagementError,
ExecutionError,
ProgressReport = 0x8,
ChunkStream = 0x9
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets
{
public enum EpPacketRequest : byte
{
// Request Invoke
InvokeFunction = 0x0,
SetProperty = 0x1,
Subscribe = 0x2,
Unsubscribe = 0x3,
// Request Inquire
TypeDefByName = 0x8,
TypeDefById = 0x9,
TypeDefByResourceId = 0xA,
Query = 0xB,
LinkTypeDefs = 0xC,
Token = 0xD,
GetResourceIdByLink = 0xE,
// Request Manage
AttachResource = 0x10,
ReattachResource = 0x11,
DetachResource = 0x12,
CreateResource = 0x13,
DeleteResource = 0x14,
MoveResource = 0x15,
// Request Static
KeepAlive = 0x18,
ProcedureCall = 0x19,
StaticCall = 0x1A,
IndirectCall = 0x1B,
PullStream = 0x1C,
TerminateExecution = 0x1D,
HaltExecution = 0x1E,
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets.Http
{
public enum HttpComposeOption : int
{
AllCalculateLength,
AllDontCalculateLength,
SpecifiedHeadersOnly,
DataOnly
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets.Http
{
public struct HttpCookie
{
public string Name;
public string Value;
public DateTime Expires;
public string Path;
public bool HttpOnly;
public string Domain;
public HttpCookie(string name, string value)
{
Name = name;
Value = value;
Path = null;
Expires = DateTime.MinValue;
HttpOnly = false;
Domain = null;
}
public HttpCookie(string name, string value, DateTime expires)
{
Name = name;
Value = value;
Expires = expires;
HttpOnly = false;
Domain = null;
Path = null;
}
public override string ToString()
{
//Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/
//Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/
var cookie = Name + "=" + Value;
if (Expires.Ticks != 0)
cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT";
if (Domain != null)
cookie += "; domain=" + Domain;
if (Path != null)
cookie += "; path=" + Path;
if (HttpOnly)
cookie += "; HttpOnly";
return cookie;
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets.Http
{
public enum HttpMethod : byte
{
GET,
POST,
HEAD,
PUT,
DELETE,
OPTIONS,
TRACE,
CONNECT,
UNKNOWN
}
}

View File

@@ -0,0 +1,303 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using Esiur.Misc;
using Esiur.Data;
using System.Net;
using System.Text.Json.Serialization;
namespace Esiur.Net.Packets.Http;
public class HttpRequestPacket : Packet
{
public StringKeyList Query;
public HttpMethod Method;
public StringKeyList Headers;
public bool WSMode;
public string Version;
public StringKeyList Cookies; // String
public string URL; /// With query
public string Filename; /// Without query
public KeyList<string, object> PostForms;
public byte[] Message;
private HttpMethod GetMethod(string method)
{
switch (method.ToLower())
{
case "get":
return HttpMethod.GET;
case "post":
return HttpMethod.POST;
case "head":
return HttpMethod.HEAD;
case "put":
return HttpMethod.PUT;
case "delete":
return HttpMethod.DELETE;
case "options":
return HttpMethod.OPTIONS;
case "trace":
return HttpMethod.TRACE;
case "connect":
return HttpMethod.CONNECT;
default:
return HttpMethod.UNKNOWN;
}
}
public override string ToString()
{
return "HTTPRequestPacket"
+ "\n\tVersion: " + Version
+ "\n\tMethod: " + Method
+ "\n\tURL: " + URL
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
}
public override long Parse(byte[] data, uint offset, uint ends)
{
string[] sMethod = null;
string[] sLines = null;
uint headerSize = 0;
for (uint i = offset; i < ends - 3; i++)
{
if (data[i] == '\r' && data[i + 1] == '\n'
&& data[i + 2] == '\r' && data[i + 3] == '\n')
{
sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" },
StringSplitOptions.None);
headerSize = i + 4;
break;
}
}
if (headerSize == 0)
return -1;
Cookies = new StringKeyList();
PostForms = new KeyList<string, object>();
Query = new StringKeyList();
Headers = new StringKeyList();
sMethod = sLines[0].Split(' ');
Method = GetMethod(sMethod[0].Trim());
if (sMethod.Length == 3)
{
sMethod[1] = WebUtility.UrlDecode(sMethod[1]);
if (sMethod[1].Length >= 7)
{
if (sMethod[1].StartsWith("http://"))
{
sMethod[1] = sMethod[1].Substring(sMethod[1].IndexOf("/", 7));
}
}
URL = sMethod[1].Trim();
if (URL.IndexOf("?", 0) != -1)
{
Filename = URL.Split(new char[] { '?' }, 2)[0];
}
else
{
Filename = URL;
}
if (Filename.IndexOf("%", 0) != -1)
{
Filename = WebUtility.UrlDecode(Filename);
}
Version = sMethod[2].Trim();
}
// Read all headers
for (int i = 1; i < sLines.Length; i++)
{
if (sLines[i] == string.Empty)
{
// Invalid header
return 0;
}
if (sLines[i].IndexOf(':') == -1)
{
// Invalid header
return 0;
}
string[] header = sLines[i].Split(new char[] { ':' }, 2);
header[0] = header[0].ToLower();
Headers[header[0]] = header[1].Trim();
if (header[0] == "cookie")
{
string[] cookies = header[1].Split(';');
foreach (string cookie in cookies)
{
if (cookie.IndexOf('=') != -1)
{
string[] splitCookie = cookie.Split('=');
splitCookie[0] = splitCookie[0].Trim();
splitCookie[1] = splitCookie[1].Trim();
if (!Cookies.ContainsKey(splitCookie[0].Trim()))
Cookies.Add(splitCookie[0], splitCookie[1]);
}
else
{
if (!Cookies.ContainsKey(cookie.Trim()))
{
Cookies.Add(cookie.Trim(), string.Empty);
}
}
}
}
}
// Query String
if (URL.IndexOf("?", 0) != -1)
{
string[] SQ = URL.Split(new char[] { '?' }, 2)[1].Split('&');
foreach (string S in SQ)
{
if (S.IndexOf("=", 0) != -1)
{
string[] qp = S.Split(new char[] { '=' }, 2);
if (!Query.ContainsKey(WebUtility.UrlDecode(qp[0])))
{
Query.Add(WebUtility.UrlDecode(qp[0]), WebUtility.UrlDecode(qp[1]));
}
}
else
{
if (!Query.ContainsKey(WebUtility.UrlDecode(S)))
{
Query.Add(WebUtility.UrlDecode(S), null);
}
}
}
}
// Post Content-Length
if (Method == HttpMethod.POST)
{
try
{
uint postSize = uint.Parse(Headers["content-length"]);
// check limit
if (postSize > data.Length - headerSize)
return -(postSize - (data.Length - headerSize));
if (
Headers["content-type"] == null
|| Headers["content-type"] == ""
|| Headers["content-type"].StartsWith("application/x-www-form-urlencoded"))
{
string[] PostVars = null;
PostVars = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split('&');
for (int J = 0; J < PostVars.Length; J++)
{
if (PostVars[J].IndexOf("=") != -1)
{
string key = WebUtility.HtmlDecode(
WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[0]));
if (PostForms.Contains(key))
PostForms[key] = WebUtility.HtmlDecode(
WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1]));
else
PostForms.Add(key, WebUtility.HtmlDecode(
WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1])));
}
else
if (PostForms.Contains("unknown"))
PostForms["unknown"] = PostForms["unknown"]
+ "&" + WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J]));
else
PostForms.Add("unknown", WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J])));
}
}
else if (Headers["content-type"].StartsWith("multipart/form-data"))
{
int st = 1;
int ed = 0;
string strBoundry = "--" + Headers["content-type"].Substring(
Headers["content-type"].IndexOf("boundary=", 0) + 9);
string[] sc = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split(
new string[] { strBoundry }, StringSplitOptions.None);
for (int j = 1; j < sc.Length - 1; j++)
{
string[] ps = sc[j].Split(new string[] { "\r\n\r\n" }, 2, StringSplitOptions.None);
ps[1] = ps[1].Substring(0, ps[1].Length - 2); // remove the empty line
st = ps[0].IndexOf("name=", 0) + 6;
ed = ps[0].IndexOf("\"", st);
PostForms.Add(ps[0].Substring(st, ed - st), ps[1]);
}
}
//else if (Headers["content-type"] == "application/json")
//{
// var json = DC.Clip(data, headerSize, postSize);
//}
else
{
//PostForms.Add(Headers["content-type"], Encoding.Default.GetString( ));
Message = data.Clip(headerSize, postSize);
}
return headerSize + postSize;
}
catch
{
return 0;
}
}
return headerSize;
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Packets.Http
{
public enum HttpResponseCode : int
{
Switching = 101,
OK = 200,
Created = 201,
Accepted = 202,
NoContent = 204,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
TemporaryRedirect = 307,
BadRequest = 400,
Unauthorized = 401,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
PreconditionFailed = 412,
UnsupportedMediaType = 415,
InternalServerError = 500,
NotImplemented = 501,
}
}

View File

@@ -0,0 +1,217 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.Packets.Http;
public class HttpResponsePacket : Packet
{
public StringKeyList Headers { get; } = new StringKeyList(true);
public string Version { get; set; } = "HTTP/1.1";
public byte[] Message;
public HttpResponseCode Number { get; set; } = HttpResponseCode.OK;
public string Text;
public List<HttpCookie> Cookies { get; } = new List<HttpCookie>();
public bool Handled;
public override string ToString()
{
return "HTTPResponsePacket"
+ "\n\tVersion: " + Version
//+ "\n\tMethod: " + Method
//+ "\n\tURL: " + URL
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
}
private string MakeHeader(HttpComposeOption options)
{
string header = $"{Version} {(int)Number} {Text}\r\nServer: Esiur {Global.Version}\r\nDate: {DateTime.Now.ToUniversalTime().ToString("r")}\r\n";
if (options == HttpComposeOption.AllCalculateLength)
Headers["Content-Length"] = Message?.Length.ToString() ?? "0";
foreach (var kv in Headers)
header += kv.Key + ": " + kv.Value + "\r\n";
// Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2007 21:00:00 GMT; path=/
// Set-Cookie: ASPSESSIONIDQABBDSQA=IPDPMMMALDGFLMICEJIOCIPM; path=/
foreach (var Cookie in Cookies)
header += "Set-Cookie: " + Cookie.ToString() + "\r\n";
header += "\r\n";
return header;
}
public bool Compose(HttpComposeOption options)
{
List<byte> msg = new List<byte>();
if (options != HttpComposeOption.DataOnly)
{
msg.AddRange(Encoding.UTF8.GetBytes(MakeHeader(options)));
}
if (options != HttpComposeOption.SpecifiedHeadersOnly)
{
if (Message != null)
msg.AddRange(Message);
}
Data = msg.ToArray();
return true;
}
public override bool Compose()
{
return Compose(HttpComposeOption.AllDontCalculateLength);
}
public override long Parse(byte[] data, uint offset, uint ends)
{
string[] sMethod = null;
string[] sLines = null;
uint headerSize = 0;
for (uint i = offset; i < ends - 3; i++)
{
if (data[i] == '\r' && data[i + 1] == '\n'
&& data[i + 2] == '\r' && data[i + 3] == '\n')
{
sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" },
StringSplitOptions.None);
headerSize = i + 4;
break;
}
}
if (headerSize == 0)
return -1;
sMethod = sLines[0].Split(' ');
if (sMethod.Length == 3)
{
Version = sMethod[0].Trim();
Number = (HttpResponseCode)Convert.ToInt32(sMethod[1].Trim());
Text = sMethod[2];
}
// Read all headers
for (int i = 1; i < sLines.Length; i++)
{
if (sLines[i] == string.Empty)
{
// Invalid header
return 0;
}
if (sLines[i].IndexOf(':') == -1)
{
// Invalid header
return 0;
}
string[] header = sLines[i].Split(new char[] { ':' }, 2);
header[0] = header[0].ToLower();
Headers[header[0]] = header[1].Trim();
//Set-Cookie: NAME=VALUE; expires=DATE;
if (header[0] == "set-cookie")
{
string[] cookie = header[1].Split(';');
if (cookie.Length >= 1)
{
string[] splitCookie = cookie[0].Split('=');
HttpCookie c = new HttpCookie(splitCookie[0], splitCookie[1]);
for (int j = 1; j < cookie.Length; j++)
{
splitCookie = cookie[j].Split('=');
switch (splitCookie[0].ToLower())
{
case "domain":
c.Domain = splitCookie[1];
break;
case "path":
c.Path = splitCookie[1];
break;
case "httponly":
c.HttpOnly = true;
break;
case "expires":
// Wed, 13-Jan-2021 22:23:01 GMT
c.Expires = DateTime.Parse(splitCookie[1]);
break;
}
}
}
}
}
// Content-Length
try
{
uint contentLength = uint.Parse(Headers["content-length"]);
// check limit
if (contentLength > data.Length - headerSize)
{
return contentLength - (data.Length - headerSize);
}
Message = data.Clip(offset, contentLength);
return headerSize + contentLength;
}
catch
{
return 0;
}
}
}

View File

@@ -0,0 +1,367 @@
/********************************************************************************\
* Uruky Project *
* *
* Copyright (C) 2006 Ahmed Zamil - ahmed@dijlh.com *
* http://www.dijlh.com *
* *
* 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. *
* *
* File: Packet.cs *
* Description: Ethernet/ARP/IPv4/TCP/UDP Packet Decoding & Encoding Class *
* Compatibility: .Net Framework 2.0 / Mono 1.1.8 *
* *
\********************************************************************************/
using System;
using System.Text;
using Esiur.Misc;
using Esiur.Net.DataLink;
using System.Net.NetworkInformation;
using Esiur.Data;
namespace Esiur.Net.Packets;
internal static class Functions
{
public static void AddData(ref byte[] dest, byte[] src)
{
int I = 0;
if (src == null)
{
return;
}
if (dest != null)
{
I = dest.Length;
Array.Resize(ref dest, dest.Length + src.Length);
//dest = (byte[])Resize(dest, dest.Length + src.Length);
}
else
{
dest = new byte[src.Length];
}
Array.Copy(src, 0, dest, I, src.Length);
}
/*
public static Array Resize(Array array, int newSize)
{
Type myType = Type.GetType(array.GetType().FullName.TrimEnd('[', ']'));
Array nA = Array.CreateInstance(myType, newSize);
Array.Copy(array, nA, (newSize > array.Length ? array.Length : newSize));
return nA;
} */
//Computes the checksum used in IP, ARP..., ie the
// "The 16 bit one's complement of the one 's complement sum
//of all 16 bit words" as seen in RFCs
// Returns a 4 characters hex string
// data's lenght must be multiple of 4, else zero padding
public static ushort IP_CRC16(byte[] data)
{
ulong Sum = 0;
bool Padding = false;
/// * Padding if needed
if (data.Length % 2 != 0)
{
Array.Resize(ref data, data.Length + 1);
//data = (byte[])Resize(data, data.Length + 1);
Padding = true;
}
int count = data.Length;
///* add 16-bit words */
while (count > 0) //1)
{
///* this is the inner loop */
Sum += GetInteger(data[count - 2], data[count - 1]);
///* Fold 32-bit sum to 16-bit */
while (Sum >> 16 != 0)
{
Sum = (Sum & 0XFFFF) + (Sum >> 16);
}
count -= 2;
}
/// * reverse padding
if (Padding)
{
Array.Resize(ref data, data.Length - 1);
//data = (byte[])Resize(data, data.Length - 1);
}
///* Return one's compliment of final sum.
//return (ushort)(ushort.MaxValue - (ushort)Sum);
return (ushort)(~Sum);
}
public static ushort GetInteger(byte B1, byte B2)
{
return BitConverter.ToUInt16(new byte[] { B2, B1 }, 0);
//return System.Convert.ToUInt16("&h" + GetHex(B1) + GetHex(B2));
}
public static uint GetLong(byte B1, byte B2, byte B3, byte B4)
{
return BitConverter.ToUInt32(new byte[] { B4, B3, B2, B1 }, 0);
//return System.Convert.ToUInt32("&h" + GetHex(B1) + GetHex(B2) + GetHex(B3) + GetHex(B4));
}
public static string GetHex(byte B)
{
return (((B < 15) ? 0 + System.Convert.ToString(B, 16).ToUpper() : System.Convert.ToString(B, 16).ToUpper()));
}
public static bool GetBit(uint B, byte Pos)
{
//return BitConverter.ToBoolean(BitConverter.GetBytes(B), Pos + 1);
return (B & (uint)(Math.Pow(2, (Pos - 1)))) == (Math.Pow(2, (Pos - 1)));
}
public static ushort RemoveBit(ushort I, byte Pos)
{
return (ushort)RemoveBit((uint)I, Pos);
}
public static uint RemoveBit(uint I, byte Pos)
{
if (GetBit(I, Pos))
{
return I - (uint)(Math.Pow(2, (Pos - 1)));
}
else
{
return I;
}
}
public static void SplitInteger(ushort I, ref byte BLeft, ref byte BRight)
{
byte[] b = BitConverter.GetBytes(I);
BLeft = b[1];
BRight = b[0];
//BLeft = I >> 8;
//BRight = (I << 8) >> 8;
}
public static void SplitLong(uint I, ref byte BLeft, ref byte BLeftMiddle, ref byte BRightMiddle, ref byte BRight)
{
byte[] b = BitConverter.GetBytes(I);
BLeft = b[3];
BLeftMiddle = b[2];
BRightMiddle = b[1];
BRight = b[0];
//BLeft = I >> 24;
//BLeftMiddle = (I << 8) >> 24;
//BRightMiddle = (I << 16) >> 24;
//BRight = (I << 24) >> 24;
}
}
public class PosixTime
{
ulong seconds;
ulong microseconds;
PosixTime(ulong Seconds, ulong Microseconds)
{
seconds = Seconds;
microseconds = Microseconds;
}
public override string ToString()
{
return seconds + "." + microseconds;
}
}
public class Packet
{
//public EtherServer2.EthernetSource Source;
public PacketSource Source;
public DateTime Timestamp;
public enum PPPType : ushort
{
IP = 0x0021, // Internet Protocol version 4 [RFC1332]
SDTP = 0x0049, // Serial Data Transport Protocol (PPP-SDTP) [RFC1963]
IPv6HeaderCompression = 0x004f, // IPv6 Header Compression
IPv6 = 0x0057, // Internet Protocol version 6 [RFC5072]
W8021dHelloPacket = 0x0201, // 802.1d Hello Packets [RFC3518]
IPv6ControlProtocol = 0x8057, // IPv6 Control Protocol [RFC5072]
}
public enum ProtocolType : ushort
{
IP = 0x800, // IPv4
ARP = 0x806, // Address Resolution Protocol
IPv6 = 0x86DD, // IPv6
FrameRelayARP = 0x0808, // Frame Relay ARP [RFC1701]
VINESLoopback = 0x0BAE, // VINES Loopback [RFC1701]
VINESEcho = 0x0BAF, // VINES ECHO [RFC1701]
TransEtherBridging = 0x6558, // TransEther Bridging [RFC1701]
RawFrameRelay = 0x6559, // Raw Frame Relay [RFC1701]
IEE8021QVLAN = 0x8100, // IEEE 802.1Q VLAN-tagged frames (initially Wellfleet)
SNMP = 0x814C, // SNMP [JKR1]
TCPIP_Compression = 0x876B, // TCP/IP Compression [RFC1144]
IPAutonomousSystems = 0x876C, // IP Autonomous Systems [RFC1701]
SecureData = 0x876D, // Secure Data [RFC1701]
PPP = 0x880B, // PPP [IANA]
MPLS = 0x8847, // MPLS [RFC5332]
MPLS_UpstreamAssignedLabel = 0x8848, // MPLS with upstream-assigned label [RFC5332]
PPPoEDiscoveryStage = 0x8863, // PPPoE Discovery Stage [RFC2516]
PPPoESessionStage = 0x8864, // PPPoE Session Stage [RFC2516]
}
/*
public static void GetPacketMACAddresses(Packet packet, out byte[] srcMAC, out byte[] dstMAC)
{
// get the node address
Packet root = packet.RootPacket;
if (root is TZSPPacket)
{
TZSPPacket tp = (TZSPPacket)root;
if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet)
{
EthernetPacket ep = (EthernetPacket)tp.SubPacket;
srcMAC = ep.SourceMAC;
dstMAC = ep.DestinationMAC;
}
else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11)
{
W802_11Packet wp = (W802_11Packet)tp.SubPacket;
srcMAC = wp.SA;
dstMAC = wp.DA;
}
else
{
srcMAC = null;
dstMAC = null;
}
}
else if (root is EthernetPacket)
{
EthernetPacket ep = (EthernetPacket)root;
srcMAC = ep.SourceMAC;
dstMAC = ep.DestinationMAC;
}
else if (root is W802_11Packet)
{
W802_11Packet wp = (W802_11Packet)root;
srcMAC = wp.SA;
dstMAC = wp.DA;
}
else
{
srcMAC = null;
dstMAC = null;
}
}
public static void GetPacketAddresses(Packet packet, ref string srcMAC, ref string dstMAC, ref string srcIP, ref string dstIP)
{
if (packet is TCPv4Packet)
{
if (packet.ParentPacket is IPv4Packet)
{
IPv4Packet ip = (IPv4Packet)packet.ParentPacket;
srcIP = ip.SourceIP.ToString();
dstIP = ip.DestinationIP.ToString();
}
}
// get the node address
Packet root = packet.RootPacket;
if (root is TZSPPacket)
{
TZSPPacket tp = (TZSPPacket)root;
if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.Ethernet)
{
EthernetPacket ep = (EthernetPacket)tp.SubPacket;
srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString();
dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString();
}
else if (tp.Protocol == TZSPPacket.TZSPEncapsulatedProtocol.IEEE802_11)
{
W802_11Packet wp = (W802_11Packet)tp.SubPacket;
srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString();
dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString();
}
}
else if (root is EthernetPacket)
{
EthernetPacket ep = (EthernetPacket)root;
srcMAC = DC.GetPhysicalAddress(ep.SourceMAC, 0).ToString();
dstMAC = DC.GetPhysicalAddress(ep.DestinationMAC, 0).ToString();
}
else if (root is W802_11Packet)
{
W802_11Packet wp = (W802_11Packet)root;
srcMAC = DC.GetPhysicalAddress(wp.SA, 0).ToString();
dstMAC = DC.GetPhysicalAddress(wp.DA, 0).ToString();
}
}
*/
//PosixTime Timeval;
public byte[] Header;
public byte[] Preamble;
//public byte[] Payload;
public byte[] Data;
public Packet SubPacket;
public Packet ParentPacket;
public virtual long Parse(byte[] data, uint offset, uint ends) { return 0; }
public virtual bool Compose() { return false; }
public Packet RootPacket
{
get
{
Packet root = this;
while (root.ParentPacket != null)
root = root.ParentPacket;
return root;
}
}
public Packet LeafPacket
{
get
{
Packet leaf = this;
while (leaf.SubPacket != null)
leaf = leaf.SubPacket;
return leaf;
}
}
}
/************************************ EOF *************************************/

View File

@@ -0,0 +1,215 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.Packets.WebSocket;
public class WebsocketPacket : Packet
{
public enum WSOpcode : byte
{
ContinuationFrame = 0x0, // %x0 denotes a continuation frame
TextFrame = 0x1, // %x1 denotes a text frame
BinaryFrame = 0x2, // %x2 denotes a binary frame
// %x3-7 are reserved for further non-control frames
ConnectionClose = 0x8, // %x8 denotes a connection close
Ping = 0x9, // %x9 denotes a ping
Pong = 0xA, // %xA denotes a pong
//* %xB-F are reserved for further control frames
}
public bool FIN;
public bool RSV1;
public bool RSV2;
public bool RSV3;
public WSOpcode Opcode;
public bool Mask;
public long PayloadLength;
// public UInt32 MaskKey;
public byte[] MaskKey;
public byte[] Message;
public override string ToString()
{
return "WebsocketPacket"
+ "\n\tFIN: " + FIN
+ "\n\tOpcode: " + Opcode
+ "\n\tPayload: " + PayloadLength
+ "\n\tMaskKey: " + MaskKey
+ "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
}
public override bool Compose()
{
var pkt = new List<byte>();
pkt.Add((byte)((FIN ? 0x80 : 0x0) |
(RSV1 ? 0x40 : 0x0) |
(RSV2 ? 0x20 : 0x0) |
(RSV3 ? 0x10 : 0x0) |
(byte)Opcode));
// calculate length
if (Message.Length > ushort.MaxValue)
// 4 bytes
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127));
pkt.AddRange(((ulong)Message.LongCount()).ToBytes(Endian.Big));
}
else if (Message.Length > 125)
// 2 bytes
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126));
pkt.AddRange(((ushort)Message.Length).ToBytes(Endian.Big));
}
else
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | Message.Length));
}
if (Mask)
{
pkt.AddRange(MaskKey);
}
pkt.AddRange(Message);
Data = pkt.ToArray();
return true;
}
public override long Parse(byte[] data, uint offset, uint ends)
{
try
{
long needed = 2;
var length = ends - offset;
if (length < needed)
{
//Console.WriteLine("stage 1 " + needed);
return length - needed;
}
uint oOffset = offset;
FIN = (data[offset] & 0x80) == 0x80;
RSV1 = (data[offset] & 0x40) == 0x40;
RSV2 = (data[offset] & 0x20) == 0x20;
RSV3 = (data[offset] & 0x10) == 0x10;
Opcode = (WSOpcode)(data[offset++] & 0xF);
Mask = (data[offset] & 0x80) == 0x80;
PayloadLength = data[offset++] & 0x7F;
if (Mask)
needed += 4;
if (PayloadLength == 126)
{
needed += 2;
if (length < needed)
{
//Console.WriteLine("stage 2 " + needed);
return length - needed;
}
PayloadLength = data.GetUInt16(offset, Endian.Big);
offset += 2;
}
else if (PayloadLength == 127)
{
needed += 8;
if (length < needed)
{
//Console.WriteLine("stage 3 " + needed);
return length - needed;
}
PayloadLength = data.GetInt64(offset, Endian.Big);
offset += 8;
}
/*
if (Mask)
{
MaskKey = new byte[4];
MaskKey[0] = data[offset++];
MaskKey[1] = data[offset++];
MaskKey[2] = data[offset++];
MaskKey[3] = data[offset++];
//MaskKey = DC.GetUInt32(data, offset);
//offset += 4;
}
*/
needed += PayloadLength;
if (length < needed)
{
//Console.WriteLine("stage 4");
return length - needed;
}
else
{
if (Mask)
{
MaskKey = new byte[4];
MaskKey[0] = data[offset++];
MaskKey[1] = data[offset++];
MaskKey[2] = data[offset++];
MaskKey[3] = data[offset++];
Message = data.Clip(offset, (uint)PayloadLength);
//var aMask = BitConverter.GetBytes(MaskKey);
for (int i = 0; i < Message.Length; i++)
Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]);
}
else
Message = data.Clip(offset, (uint)PayloadLength);
return offset - oOffset + (int)PayloadLength;
}
}
catch (Exception ex)
{
Global.Log(ex);
Global.Log("WebsocketPacket", Core.LogType.Debug, offset + "::" + data.ToHex());
throw ex;
}
}
}

View File

@@ -0,0 +1,249 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Ppap
{
public class DeterministicGenerator
: SecureRandom
{
private static long counter = DateTime.UtcNow.Ticks;
public byte[] value;
private static long NextCounterValue()
{
return Interlocked.Increment(ref counter);
}
private static readonly SecureRandom MasterRandom = new SecureRandom(new CryptoApiRandomGenerator());
internal static readonly SecureRandom ArbitraryRandom = new SecureRandom(new VmpcRandomGenerator(), 16);
private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
{
IDigest digest = DigestUtilities.GetDigest(digestName);
if (digest == null)
return null;
DigestRandomGenerator prng = new DigestRandomGenerator(digest);
if (autoSeed)
{
AutoSeed(prng, 2 * digest.GetDigestSize());
}
return prng;
}
public static new byte[] GetNextBytes(SecureRandom secureRandom, int length)
{
byte[] result = new byte[length];
secureRandom.NextBytes(result);
return result;
}
public static new SecureRandom GetInstance(string algorithm)
{
return GetInstance(algorithm, true);
}
public static new SecureRandom GetInstance(string algorithm, bool autoSeed)
{
if (algorithm == null)
throw new ArgumentNullException(nameof(algorithm));
if (algorithm.EndsWith("PRNG", StringComparison.OrdinalIgnoreCase))
{
string digestName = algorithm.Substring(0, algorithm.Length - "PRNG".Length);
DigestRandomGenerator prng = CreatePrng(digestName, autoSeed);
if (prng != null)
return new SecureRandom(prng);
}
throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
}
protected new readonly IRandomGenerator generator;
public DeterministicGenerator(byte[] value)
: this(CreatePrng("SHA256", true))
{
this.value = value;
}
public DeterministicGenerator(IRandomGenerator generator)
{
this.generator = generator;
}
public DeterministicGenerator(IRandomGenerator generator, int autoSeedLengthInBytes)
{
AutoSeed(generator, autoSeedLengthInBytes);
this.generator = generator;
}
public override byte[] GenerateSeed(int length)
{
return GetNextBytes(MasterRandom, length);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void GenerateSeed(Span<byte> seed)
{
MasterRandom.NextBytes(seed);
}
#endif
public override void SetSeed(byte[] seed)
{
generator.AddSeedMaterial(seed);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void SetSeed(Span<byte> seed)
{
generator.AddSeedMaterial(seed);
}
#endif
public override void SetSeed(long seed)
{
generator.AddSeedMaterial(seed);
}
public override int Next()
{
return NextInt() & int.MaxValue;
}
public override int Next(int maxValue)
{
if (maxValue < 2)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
return 0;
}
int bits;
// Test whether maxValue is a power of 2
if ((maxValue & (maxValue - 1)) == 0)
{
bits = NextInt() & int.MaxValue;
return (int)(((long)bits * maxValue) >> 31);
}
int result;
do
{
bits = NextInt() & int.MaxValue;
result = bits % maxValue;
}
while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
return result;
}
public override int Next(int minValue, int maxValue)
{
if (maxValue <= minValue)
{
if (maxValue == minValue)
return minValue;
throw new ArgumentException("maxValue cannot be less than minValue");
}
int diff = maxValue - minValue;
if (diff > 0)
return minValue + Next(diff);
for (; ; )
{
int i = NextInt();
if (i >= minValue && i < maxValue)
return i;
}
}
public override void NextBytes(byte[] buf)
{
Buffer.BlockCopy(value, 0, buf, 0, buf.Length);
}
public override void NextBytes(byte[] buf, int off, int len)
{
Buffer.BlockCopy(value, 0, buf, off, len);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void NextBytes(Span<byte> buffer)
{
if (generator != null)
{
generator.NextBytes(buffer);
}
else
{
byte[] tmp = new byte[buffer.Length];
NextBytes(tmp);
tmp.CopyTo(buffer);
}
}
#endif
private static readonly double DoubleScale = 1.0 / Convert.ToDouble(1L << 53);
public override double NextDouble()
{
ulong x = (ulong)NextLong() >> 11;
return Convert.ToDouble(x) * DoubleScale;
}
public override int NextInt()
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
Span<byte> bytes = stackalloc byte[4];
#else
byte[] bytes = new byte[4];
#endif
NextBytes(bytes);
return (int)0;
}
public override long NextLong()
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
Span<byte> bytes = stackalloc byte[8];
#else
byte[] bytes = new byte[8];
#endif
NextBytes(bytes);
return (long)0;
}
private static void AutoSeed(IRandomGenerator generator, int seedLength)
{
generator.AddSeedMaterial(NextCounterValue());
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
Span<byte> seed = seedLength <= 128
? stackalloc byte[seedLength]
: new byte[seedLength];
#else
byte[] seed = new byte[seedLength];
#endif
MasterRandom.NextBytes(seed);
generator.AddSeedMaterial(seed);
}
}
}

View File

@@ -0,0 +1,61 @@
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Ppap
{
internal class KeyGenerator
{
public static (byte[], byte[]) Gen(MLKemParameters parameters = null)
{
var random = new RandomGenerator();
var keyGenParameters = new MLKemKeyGenerationParameters(random, parameters ?? MLKemParameters.ml_kem_768);
var kyberKeyPairGenerator = new MLKemKeyPairGenerator();
kyberKeyPairGenerator.Init(keyGenParameters);
var keys = kyberKeyPairGenerator.GenerateKeyPair();
return ((keys.Private as MLKemPrivateKeyParameters).GetEncoded(),
(keys.Public as MLKemPublicKeyParameters).GetEncoded());
}
public static (byte[], byte[]) GenS(byte[] username, byte[] password, byte[] registrationNonce, Argon2Parameters argon2parameters = null, MLKemParameters mlkemParameters = null)
{
var secret = new byte[username.Length + password.Length + registrationNonce.Length];
Buffer.BlockCopy(username, 0, secret, 0, username.Length);
Buffer.BlockCopy(password, 0, secret, username.Length, password.Length);
Buffer.BlockCopy(registrationNonce, 0, secret, username.Length + password.Length, registrationNonce.Length);
var output = new byte[64];
//Argon2id.DeriveKey(output, secret, registrationNonce, ArgonIterations, ArgonMemory * 1024);
var argon2 = new Argon2BytesGenerator();
var argon2params = argon2parameters ?? new Argon2Parameters.Builder(Argon2Parameters.Argon2id)
.WithSalt(registrationNonce)
.WithMemoryAsKB(1024 * 10)
.WithIterations(3)
.WithParallelism(1)
.Build();
argon2.Init(argon2params);
var output2 = new byte[64];
argon2.GenerateBytes(secret, output);
var random = new DeterministicGenerator(output);
var keyGenParameters = new MLKemKeyGenerationParameters(random, mlkemParameters ?? MLKemParameters.ml_kem_768);
var kyberKeyPairGenerator = new MLKemKeyPairGenerator();
kyberKeyPairGenerator.Init(keyGenParameters);
var keys = kyberKeyPairGenerator.GenerateKeyPair();
return ((keys.Private as MLKemPrivateKeyParameters).GetEncoded(),
(keys.Public as MLKemPublicKeyParameters).GetEncoded());
}
}
}

View File

@@ -0,0 +1,247 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net.Ppap
{
public class RandomGenerator
: SecureRandom
{
private static long counter = DateTime.UtcNow.Ticks;
private static long NextCounterValue()
{
return Interlocked.Increment(ref counter);
}
private static readonly SecureRandom MasterRandom = new SecureRandom(new CryptoApiRandomGenerator());
internal static readonly SecureRandom ArbitraryRandom = new SecureRandom(new VmpcRandomGenerator(), 16);
private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
{
IDigest digest = DigestUtilities.GetDigest(digestName);
if (digest == null)
return null;
DigestRandomGenerator prng = new DigestRandomGenerator(digest);
if (autoSeed)
{
AutoSeed(prng, 2 * digest.GetDigestSize());
}
return prng;
}
public static new byte[] GetNextBytes(SecureRandom secureRandom, int length)
{
byte[] result = new byte[length];
secureRandom.NextBytes(result);
return result;
}
public static new SecureRandom GetInstance(string algorithm)
{
return GetInstance(algorithm, true);
}
public static new SecureRandom GetInstance(string algorithm, bool autoSeed)
{
if (algorithm == null)
throw new ArgumentNullException(nameof(algorithm));
if (algorithm.EndsWith("PRNG", StringComparison.OrdinalIgnoreCase))
{
string digestName = algorithm.Substring(0, algorithm.Length - "PRNG".Length);
DigestRandomGenerator prng = CreatePrng(digestName, autoSeed);
if (prng != null)
return new SecureRandom(prng);
}
throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
}
protected new readonly IRandomGenerator generator;
public RandomGenerator()
: this(CreatePrng("SHA256", true))
{
}
public RandomGenerator(IRandomGenerator generator)
{
this.generator = generator;
}
public RandomGenerator(IRandomGenerator generator, int autoSeedLengthInBytes)
{
AutoSeed(generator, autoSeedLengthInBytes);
this.generator = generator;
}
public override byte[] GenerateSeed(int length)
{
return GetNextBytes(MasterRandom, length);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void GenerateSeed(Span<byte> seed)
{
MasterRandom.NextBytes(seed);
}
#endif
public override void SetSeed(byte[] seed)
{
generator.AddSeedMaterial(seed);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void SetSeed(Span<byte> seed)
{
generator.AddSeedMaterial(seed);
}
#endif
public override void SetSeed(long seed)
{
generator.AddSeedMaterial(seed);
}
public override int Next()
{
return NextInt() & int.MaxValue;
}
public override int Next(int maxValue)
{
if (maxValue < 2)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
return 0;
}
int bits;
// Test whether maxValue is a power of 2
if ((maxValue & (maxValue - 1)) == 0)
{
bits = NextInt() & int.MaxValue;
return (int)(((long)bits * maxValue) >> 31);
}
int result;
do
{
bits = NextInt() & int.MaxValue;
result = bits % maxValue;
}
while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
return result;
}
public override int Next(int minValue, int maxValue)
{
if (maxValue <= minValue)
{
if (maxValue == minValue)
return minValue;
throw new ArgumentException("maxValue cannot be less than minValue");
}
int diff = maxValue - minValue;
if (diff > 0)
return minValue + Next(diff);
for (; ; )
{
int i = NextInt();
if (i >= minValue && i < maxValue)
return i;
}
}
public override void NextBytes(byte[] buf)
{
generator.NextBytes(buf);
}
public override void NextBytes(byte[] buf, int off, int len)
{
generator.NextBytes(buf, off, len);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void NextBytes(Span<byte> buffer)
{
if (generator != null)
{
generator.NextBytes(buffer);
}
else
{
byte[] tmp = new byte[buffer.Length];
NextBytes(tmp);
tmp.CopyTo(buffer);
}
}
#endif
private static readonly double DoubleScale = 1.0 / Convert.ToDouble(1L << 53);
public override double NextDouble()
{
ulong x = (ulong)NextLong() >> 11;
return Convert.ToDouble(x) * DoubleScale;
}
public override int NextInt()
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
Span<byte> bytes = stackalloc byte[4];
#else
byte[] bytes = new byte[4];
#endif
NextBytes(bytes);
return (int)0;
}
public override long NextLong()
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
Span<byte> bytes = stackalloc byte[8];
#else
byte[] bytes = new byte[8];
#endif
NextBytes(bytes);
return (long)0;
}
private static void AutoSeed(IRandomGenerator generator, int seedLength)
{
generator.AddSeedMaterial(NextCounterValue());
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
Span<byte> seed = seedLength <= 128
? stackalloc byte[seedLength]
: new byte[seedLength];
#else
byte[] seed = new byte[seedLength];
#endif
MasterRandom.NextBytes(seed);
generator.AddSeedMaterial(seed);
}
}
}

View File

@@ -0,0 +1,27 @@
using Esiur.Core;
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Net;
public class SendList : BinaryList
{
NetworkConnection connection;
AsyncReply<object[]> reply;
public SendList(NetworkConnection connection, AsyncReply<object[]> reply)
{
this.reply = reply;
this.connection = connection;
}
public override AsyncReply<object[]> Done()
{
var s = this.ToArray();
//Console.WriteLine($"Sending {s.Length} -> {DC.ToHex(s)}");
connection.Send(s);
return reply;
}
}

View File

@@ -0,0 +1,256 @@
using Esiur.Core;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Net.WebSockets;
using Esiur.Net.Packets;
using Esiur.Resource;
using Esiur.Misc;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Sockets;
using Microsoft.CodeAnalysis;
namespace Esiur.Net.Sockets
{
public class FrameworkWebSocket : ISocket
{
bool began;
WebSocket sock;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
NetworkBuffer sendNetworkBuffer = new NetworkBuffer();
byte[] websocketReceiveBuffer = new byte[10240];
ArraySegment<byte> websocketReceiveBufferSegment;
object sendLock = new object();
bool held;
public event DestroyedEvent OnDestroy;
long totalSent, totalReceived;
public IPEndPoint LocalEndPoint { get; } = new IPEndPoint(IPAddress.Any, 0);
public IPEndPoint RemoteEndPoint { get; } = new IPEndPoint(IPAddress.Any, 0);
public SocketState State => sock == null ? SocketState.Closed : sock.State switch
{
WebSocketState.Aborted => SocketState.Closed,
WebSocketState.Closed => SocketState.Closed,
WebSocketState.Connecting => SocketState.Connecting,
WebSocketState.Open => SocketState.Established,
WebSocketState.CloseReceived => SocketState.Closed,
WebSocketState.CloseSent => SocketState.Closed,
WebSocketState.None => SocketState.Initial,
_ => SocketState.Initial
};
public INetworkReceiver<ISocket> Receiver { get; set; }
public FrameworkWebSocket()
{
websocketReceiveBufferSegment = new ArraySegment<byte>(websocketReceiveBuffer);
}
public FrameworkWebSocket(WebSocket webSocket)
{
websocketReceiveBufferSegment = new ArraySegment<byte>(websocketReceiveBuffer);
sock = webSocket;
}
public void Send(byte[] message)
{
lock (sendLock)
{
if (held)
{
sendNetworkBuffer.Write(message);
}
else
{
totalSent += message.Length;
sock.SendAsync(new ArraySegment<byte>(message), WebSocketMessageType.Binary,
true, new System.Threading.CancellationToken());
}
}
}
public void Send(byte[] message, int offset, int size)
{
lock (sendLock)
{
if (held)
{
sendNetworkBuffer.Write(message, (uint)offset, (uint)size);
}
else
{
totalSent += size;
sock.SendAsync(new ArraySegment<byte>(message, offset, size),
WebSocketMessageType.Binary, true, new System.Threading.CancellationToken());
}
}
}
public void Close()
{
sock?.CloseAsync(WebSocketCloseStatus.NormalClosure, "", new System.Threading.CancellationToken());
}
public bool Secure { get; set; }
public async AsyncReply<bool> Connect(string hostname, ushort port)
{
var url = new Uri($"{(Secure ? "wss" : "ws")}://{hostname}:{port}");
var ws = new ClientWebSocket();
sock = ws;
await ws.ConnectAsync(url, new CancellationToken());
_ = sock.ReceiveAsync(websocketReceiveBufferSegment, CancellationToken.None)
.ContinueWith(NetworkReceive);
return true;
}
public bool Begin()
{
// Socket destroyed
if (sock == null)
return false;
if (began)
return false;
began = true;
sock.ReceiveAsync(websocketReceiveBufferSegment, CancellationToken.None)
.ContinueWith(NetworkReceive);
return true;
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
receiveNetworkBuffer = null;
Receiver = null;
sock = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public AsyncReply<ISocket> AcceptAsync()
{
throw new NotImplementedException();
}
public void Hold()
{
held = true;
}
public void Unhold()
{
lock (sendLock)
{
held = false;
var message = sendNetworkBuffer.Read();
if (message == null)
return;
totalSent += message.Length;
sock.SendAsync(new ArraySegment<byte>(message), WebSocketMessageType.Binary,
true, new System.Threading.CancellationToken());
}
}
public async AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
if (held)
{
sendNetworkBuffer.Write(message, (uint)offset, (uint)length);
}
else
{
totalSent += length;
await sock.SendAsync(new ArraySegment<byte>(message, offset, length),
WebSocketMessageType.Binary, true, new System.Threading.CancellationToken());
}
return true;
}
public ISocket Accept()
{
throw new NotImplementedException();
}
public AsyncReply<bool> BeginAsync()
{
return new AsyncReply<bool>(Begin());
}
private void NetworkReceive(Task<WebSocketReceiveResult> task)
{
if (sock.State == WebSocketState.Closed || sock.State == WebSocketState.Aborted || sock.State == WebSocketState.CloseReceived)
{
Receiver?.NetworkClose(this);
return;
}
var receivedLength = task.Result.Count;
totalReceived += receivedLength;
receiveNetworkBuffer.Write(websocketReceiveBuffer, 0, (uint)receivedLength);
Receiver?.NetworkReceive(this, receiveNetworkBuffer);
sock.ReceiveAsync(websocketReceiveBufferSegment, CancellationToken.None)
.ContinueWith(NetworkReceive);
}
public void NetworkConnect(ISocket sender)
{
Receiver?.NetworkConnect(this);
}
}
}

View File

@@ -0,0 +1,72 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using System.Collections.Concurrent;
using Esiur.Resource;
using Esiur.Core;
namespace Esiur.Net.Sockets;
//public delegate void ISocketReceiveEvent(NetworkBuffer buffer);
//public delegate void ISocketConnectEvent();
//public delegate void ISocketCloseEvent();
public interface ISocket : IDestructible
{
SocketState State { get; }
//event ISocketReceiveEvent OnReceive;
//event ISocketConnectEvent OnConnect;
//event ISocketCloseEvent OnClose;
INetworkReceiver<ISocket> Receiver { get; set; }
AsyncReply<bool> SendAsync(byte[] message, int offset, int length);
void Send(byte[] message);
void Send(byte[] message, int offset, int length);
void Close();
AsyncReply<bool> Connect(string hostname, ushort port);
bool Begin();
AsyncReply<bool> BeginAsync();
//ISocket Accept();
AsyncReply<ISocket> AcceptAsync();
ISocket Accept();
IPEndPoint RemoteEndPoint { get; }
IPEndPoint LocalEndPoint { get; }
void Hold();
void Unhold();
}

View File

@@ -0,0 +1,554 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Misc;
using Esiur.Core;
using System.Threading;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Esiur.Resource;
using System.Threading.Tasks;
using Esiur.Data;
namespace Esiur.Net.Sockets;
public class SSLSocket : ISocket
{
public INetworkReceiver<ISocket> Receiver { get; set; }
Socket sock;
byte[] receiveBuffer;
bool held;
//ArraySegment<byte> receiveBufferSegment;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
readonly object sendLock = new object();
Queue<KeyValuePair<AsyncReply<bool>, byte[]>> sendBufferQueue = new Queue<KeyValuePair<AsyncReply<bool>, byte[]>>();// Queue<byte[]>();
bool asyncSending;
bool began = false;
SocketState state = SocketState.Initial;
//public event ISocketReceiveEvent OnReceive;
//public event ISocketConnectEvent OnConnect;
//public event ISocketCloseEvent OnClose;
public event DestroyedEvent OnDestroy;
SslStream ssl;
X509Certificate2 cert;
bool server;
string hostname;
public async AsyncReply<bool> Connect(string hostname, ushort port)
{
var rt = new AsyncReply<bool>();
this.hostname = hostname;
this.server = false;
state = SocketState.Connecting;
await sock.ConnectAsync(hostname, port);
try
{
await BeginAsync();
state = SocketState.Established;
//OnConnect?.Invoke();
Receiver?.NetworkConnect(this);
}
catch (Exception ex)
{
state = SocketState.Closed;// .Terminated;
Close();
Global.Log(ex);
}
return true;
}
//private void DataSent(Task task)
//{
// try
// {
// if (sendBufferQueue.Count > 0)
// {
// byte[] data = sendBufferQueue.Dequeue();
// lock (sendLock)
// ssl.WriteAsync(data, 0, data.Length).ContinueWith(DataSent);
// }
// else
// {
// asyncSending = false;
// }
// }
// catch (Exception ex)
// {
// if (state != SocketState.Closed && !sock.Connected)
// {
// state = SocketState.Terminated;
// Close();
// }
// asyncSending = false;
// Global.Log("SSLSocket", LogType.Error, ex.ToString());
// }
//}
private void SendCallback(IAsyncResult ar)
{
if (ar != null)
{
try
{
ssl.EndWrite(ar);
if (ar.AsyncState != null)
((AsyncReply<bool>)ar.AsyncState).Trigger(true);
}
catch
{
if (state != SocketState.Closed && !sock.Connected)
{
//state = SocketState.Closed;//.Terminated;
Close();
}
}
}
lock (sendLock)
{
if (sendBufferQueue.Count > 0)
{
var kv = sendBufferQueue.Dequeue();
try
{
ssl.BeginWrite(kv.Value, 0, kv.Value.Length, SendCallback, kv.Key);
}
catch //(Exception ex)
{
asyncSending = false;
try
{
if (kv.Key != null)
kv.Key.Trigger(false);
if (state != SocketState.Closed && !sock.Connected)
{
//state = SocketState.Terminated;
Close();
}
}
catch //(Exception ex2)
{
//state = SocketState.Closed;// .Terminated;
Close();
}
//Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
else
{
asyncSending = false;
}
}
}
public IPEndPoint LocalEndPoint
{
get { return (IPEndPoint)sock.LocalEndPoint; }
}
public SSLSocket()
{
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
}
public SSLSocket(IPEndPoint localEndPoint, X509Certificate2 certificate)
{
// create the socket
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
state = SocketState.Listening;
// bind
sock.Bind(localEndPoint);
// start listening
sock.Listen(UInt16.MaxValue);
cert = certificate;
}
public IPEndPoint RemoteEndPoint
{
get { return (IPEndPoint)sock.RemoteEndPoint; }
}
public SocketState State
{
get
{
return state;
}
}
public SSLSocket(Socket socket, X509Certificate2 certificate, bool authenticateAsServer)
{
cert = certificate;
sock = socket;
receiveBuffer = new byte[sock.ReceiveBufferSize];
ssl = new SslStream(new NetworkStream(sock));
server = authenticateAsServer;
if (socket.Connected)
state = SocketState.Established;
}
public void Close()
{
if (state != SocketState.Closed)// && state != SocketState.Terminated)
{
state = SocketState.Closed;
if (sock.Connected)
{
try
{
sock.Shutdown(SocketShutdown.Both);
}
catch
{
//state = SocketState.Terminated;
}
}
Receiver?.NetworkClose(this);
//OnClose?.Invoke();
}
}
public void Send(byte[] message)
{
Send(message, 0, message.Length);
}
public void Send(byte[] message, int offset, int size)
{
var msg = message.Clip((uint)offset, (uint)size);
lock (sendLock)
{
if (!sock.Connected)
return;
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size));
}
else
{
asyncSending = true;
try
{
ssl.BeginWrite(msg, 0, msg.Length, SendCallback, null);
}
catch
{
asyncSending = false;
//state = SocketState.Terminated;
Close();
}
}
}
}
//public void Send(byte[] message)
//{
// Send(message, 0, message.Length);
//}
//public void Send(byte[] message, int offset, int size)
//{
// lock (sendLock)
// {
// if (asyncSending)
// {
// sendBufferQueue.Enqueue(message.Clip((uint)offset, (uint)size));
// }
// else
// {
// asyncSending = true;
// ssl.WriteAsync(message, offset, size).ContinueWith(DataSent);
// }
// }
//}
//private void DataReceived(Task<int> task)
//{
// try
// {
// if (state == SocketState.Closed || state == SocketState.Terminated)
// return;
// if (task.Result <= 0)
// {
// Close();
// return;
// }
// receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)task.Result);
// OnReceive?.Invoke(receiveNetworkBuffer);
// if (state == SocketState.Established)
// ssl.ReadAsync(receiveBuffer, 0, receiveBuffer.Length).ContinueWith(DataReceived);
// }
// catch (Exception ex)
// {
// if (state != SocketState.Closed && !sock.Connected)
// {
// state = SocketState.Terminated;
// Close();
// }
// Global.Log("SSLSocket", LogType.Error, ex.ToString());
// }
//}
public bool Begin()
{
if (began)
return false;
began = true;
if (server)
ssl.AuthenticateAsServer(cert);
else
ssl.AuthenticateAsClient(hostname);
if (state == SocketState.Established)
{
ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this);
return true;
}
else
return false;
}
public async AsyncReply<bool> BeginAsync()
{
if (began)
return false;
began = true;
if (server)
await ssl.AuthenticateAsServerAsync(cert);
else
await ssl.AuthenticateAsClientAsync(hostname);
if (state == SocketState.Established)
{
ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this);
return true;
}
else
return false;
}
private void ReceiveCallback(IAsyncResult results)
{
try
{
if (state != SocketState.Established)
return;
var bytesReceived = ssl.EndRead(results);
if (bytesReceived <= 0)
{
Close();
return;
}
receiveNetworkBuffer.Write(receiveBuffer, 0, (uint)bytesReceived);
//OnReceive?.Invoke(receiveNetworkBuffer);
Receiver?.NetworkReceive(this, receiveNetworkBuffer);
ssl.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveCallback, this);
}
catch //(Exception ex)
{
if (state != SocketState.Closed && !sock.Connected)
{
//state = SocketState.Terminated;
Close();
}
//Global.Log("SSLSocket", LogType.Error, ex.ToString());
}
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
Receiver = null;
receiveNetworkBuffer = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public async AsyncReply<ISocket> AcceptAsync()
{
try
{
var s = await sock.AcceptAsync();
return new SSLSocket(s, cert, true);
}
catch
{
state = SocketState.Closed;// Terminated;
return null;
}
}
public void Hold()
{
held = true;
}
public void Unhold()
{
try
{
SendCallback(null);
}
catch (Exception ex)
{
Global.Log(ex);
}
finally
{
held = false;
}
}
public AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
var msg = message.Clip((uint)offset, (uint)length);
lock (sendLock)
{
if (!sock.Connected)
return new AsyncReply<bool>(false);
var rt = new AsyncReply<bool>();
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(rt, msg));
}
else
{
asyncSending = true;
try
{
ssl.BeginWrite(msg, 0, msg.Length, SendCallback, rt);// null);
}
catch (Exception ex)
{
rt.TriggerError(ex);
asyncSending = false;
//state = SocketState.Terminated;
Close();
}
}
return rt;
}
}
public ISocket Accept()
{
try
{
return new SSLSocket(sock.Accept(), cert, true);
}
catch
{
state = SocketState.Closed;// .Terminated;
return null;
}
}
}

View File

@@ -0,0 +1,39 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Sockets;
public enum SocketState
{
Initial,
Listening,
Connecting,
Established,
Closed,
}

View File

@@ -0,0 +1,520 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Misc;
using Esiur.Core;
using System.Threading;
using Esiur.Resource;
using System.Threading.Tasks;
using Esiur.Data;
namespace Esiur.Net.Sockets;
public class TCPSocket : ISocket
{
public INetworkReceiver<ISocket> Receiver { get; set; }
Socket sock;
byte[] receiveBuffer;
bool held;
public Socket Socket => sock;
int bytesSent, bytesReceived;
public int BytesSent => bytesSent;
public int BytesReceived => bytesReceived;
//ArraySegment<byte> receiveBufferSegment;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
readonly object sendLock = new object();
Queue<KeyValuePair<AsyncReply<bool>, byte[]>> sendBufferQueue = new Queue<KeyValuePair<AsyncReply<bool>, byte[]>>();// Queue<byte[]>();
bool asyncSending;
bool began = false;
SocketState state = SocketState.Initial;
//public event ISocketReceiveEvent OnReceive;
//public event ISocketConnectEvent OnConnect;
//public event ISocketCloseEvent OnClose;
public event DestroyedEvent OnDestroy;
//SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs();
//private AsyncCallback receiveCallback;
//private AsyncCallback sendCallback;
public AsyncReply<bool> BeginAsync()
{
return new AsyncReply<bool>(Begin());
}
private AsyncReply<bool> currentReply = null;
public bool Begin()
{
// Socket destroyed
if (receiveBuffer == null)
return false;
if (began)
return false;
began = true;
/*
socketArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
socketArgs.Completed += SocketArgs_Completed;
if (!sock.ReceiveAsync(socketArgs))
SocketArgs_Completed(null, socketArgs);
*/
//receiveCallback = new AsyncCallback(ReceiveCallback);
//sendCallback = new AsyncCallback(SendCallback);
sock.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ReceiveCallback, this);
//sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived);
return true;
}
private static void ReceiveCallback(IAsyncResult ar)
{
var socket = ar.AsyncState as TCPSocket;
try
{
if (socket.state != SocketState.Established)
return;
var recCount = socket.sock.EndReceive(ar);
if (recCount > 0)
{
socket.bytesReceived += recCount;
socket.receiveNetworkBuffer.Write(socket.receiveBuffer, 0, (uint)recCount);
socket.Receiver?.NetworkReceive(socket, socket.receiveNetworkBuffer);
if (socket.state == SocketState.Established)
socket.sock.BeginReceive(socket.receiveBuffer, 0, socket.receiveBuffer.Length, SocketFlags.None, ReceiveCallback, socket);
}
else
{
socket.Close();
return;
}
}
catch //(Exception ex)
{
if (socket.state != SocketState.Closed && !socket.sock.Connected)
{
//socket.state = SocketState.Terminated;
socket.Close();
}
//Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
public AsyncReply<bool> Connect(string hostname, ushort port)
{
var rt = new AsyncReply<bool>();
try
{
state = SocketState.Connecting;
sock.ConnectAsync(hostname, port).ContinueWith((x) =>
{
if (x.IsFaulted)
rt.TriggerError(x.Exception);
else
{
state = SocketState.Established;
//OnConnect?.Invoke();
Receiver?.NetworkConnect(this);
Begin();
rt.Trigger(true);
}
});
}
catch (Exception ex)
{
rt.TriggerError(ex);
}
return rt;
}
public IPEndPoint LocalEndPoint
{
get { return (IPEndPoint)sock.LocalEndPoint; }
}
public TCPSocket()
{
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
//receiveBufferSegment = new ArraySegment<byte>(receiveBuffer);
}
public TCPSocket(string hostname, ushort port)
{
// create the socket
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
//receiveBufferSegment = new ArraySegment<byte>(receiveBuffer);
Connect(hostname, port);
}
public TCPSocket(IPEndPoint localEndPoint)
{
// create the socket
sock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
receiveBuffer = new byte[sock.ReceiveBufferSize];
state = SocketState.Listening;
// bind
sock.Bind(localEndPoint);
// start listening
sock.Listen(UInt16.MaxValue);
}
public IPEndPoint RemoteEndPoint
{
get { return (IPEndPoint)sock.RemoteEndPoint; }
}
public SocketState State
{
get
{
return state;
}
}
public TCPSocket(Socket socket)
{
sock = socket;
receiveBuffer = new byte[sock.ReceiveBufferSize];
// receiveBufferSegment = new ArraySegment<byte>(receiveBuffer);
if (socket.Connected)
state = SocketState.Established;
}
public void Close()
{
if (state == SocketState.Closed)
return; // && state != SocketState.Terminated)
state = SocketState.Closed;
if (sock.Connected)
{
try
{
sock.Shutdown(SocketShutdown.Both);
}
catch
{
}
}
try
{
sendBufferQueue?.Clear();
Receiver?.NetworkClose(this);
}
catch (Exception ex)
{
Global.Log(ex);
}
}
public void Send(byte[] message)
{
Send(message, 0, message.Length);
}
public void Send(byte[] message, int offset, int size)
{
if (state == SocketState.Closed)// || state == SocketState.Terminated)
return;
bytesSent += size;
var msg = message.Clip((uint)offset, (uint)size);
lock (sendLock)
{
if (state == SocketState.Closed)// || state == SocketState.Terminated)
return;
if (!sock.Connected)
return;
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(null, msg));// message.Clip((uint)offset, (uint)size));
}
else
{
asyncSending = true;
try
{
sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, SendCallback, this);
}
catch
{
asyncSending = false;
//state = SocketState.Closed;//.Terminated;
Close();
}
//sock.SendAsync(new ArraySegment<byte>(msg), SocketFlags.None).ContinueWith(DataSent);
}
}
}
private static void Flush(TCPSocket socket)
{
lock (socket.sendLock)
{
socket.currentReply?.Trigger(true);
socket.currentReply = null;
if (socket.state == SocketState.Closed) //|| socket.state == SocketState.Terminated)
return;
if (socket.sendBufferQueue.Count > 0)
{
var kv = socket.sendBufferQueue.Dequeue();
try
{
socket.currentReply = kv.Key;
socket.sock.BeginSend(kv.Value, 0, kv.Value.Length, SocketFlags.None,
SendCallback, socket);
}
catch (Exception ex)
{
socket.asyncSending = false;
try
{
kv.Key?.Trigger(false);
if (socket.state != SocketState.Closed && !socket.sock.Connected)
{
// socket.state = SocketState.Closed;// Terminated;
socket.Close();
}
}
catch //(Exception ex2)
{
socket.Close();
//socket.state = SocketState.Closed;// .Terminated;
}
Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
else
{
socket.asyncSending = false;
}
}
}
private static void SendCallback(IAsyncResult ar)
{
try
{
var socket = (TCPSocket)ar.AsyncState;
socket.sock?.EndSend(ar);
Flush(socket);
}
catch (Exception ex)
{
Global.Log(ex);
}
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
receiveNetworkBuffer = null;
//receiveCallback = null;
//sendCallback = null;
sock = null;
receiveBuffer = null;
receiveNetworkBuffer = null;
sendBufferQueue = null;
//socketArgs.Completed -= SocketArgs_Completed;
//socketArgs.Dispose();
//socketArgs = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public ISocket Accept()
{
try
{
var s = sock.Accept();
return new TCPSocket(s);
}
catch
{
state = SocketState.Closed;// Terminated;
return null;
}
}
public async AsyncReply<ISocket> AcceptAsync()
{
try
{
var s = await sock.AcceptAsync();
return new TCPSocket(s);
}
catch
{
state = SocketState.Closed;// Terminated;
return null;
}
}
public void Hold()
{
held = true;
}
public void Unhold()
{
try
{
Flush(this);
//SendCallback(null);
}
catch (Exception ex)
{
Global.Log(ex);
}
finally
{
held = false;
}
}
public AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
if (state == SocketState.Closed)
return new AsyncReply<bool>(false);
var msg = message.Clip((uint)offset, (uint)length);
lock (sendLock)
{
if (state == SocketState.Closed)
return new AsyncReply<bool>(false);
if (!sock.Connected)
return new AsyncReply<bool>(false);
var rt = new AsyncReply<bool>();
if (asyncSending || held)
{
sendBufferQueue.Enqueue(new KeyValuePair<AsyncReply<bool>, byte[]>(rt, msg));
}
else
{
asyncSending = true;
try
{
currentReply = rt;
sock.BeginSend(msg, 0, msg.Length, SocketFlags.None, SendCallback, this);
}
catch (Exception ex)
{
rt.TriggerError(ex);
asyncSending = false;
Close();
}
//sock.SendAsync(new ArraySegment<byte>(msg), SocketFlags.None).ContinueWith(DataSent);
}
return rt;
}
}
}

View File

@@ -0,0 +1,354 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Misc;
using System.IO;
using Esiur.Core;
using Esiur.Resource;
using Esiur.Data;
using System.Globalization;
using Esiur.Net.Packets.WebSocket;
namespace Esiur.Net.Sockets;
public class WSocket : ISocket, INetworkReceiver<ISocket>
{
WebsocketPacket pkt_receive = new WebsocketPacket();
WebsocketPacket pkt_send = new WebsocketPacket();
ISocket sock;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
NetworkBuffer sendNetworkBuffer = new NetworkBuffer();
object sendLock = new object();
bool held;
//public event ISocketReceiveEvent OnReceive;
//public event ISocketConnectEvent OnConnect;
//public event ISocketCloseEvent OnClose;
public event DestroyedEvent OnDestroy;
long totalSent, totalReceived;
public IPEndPoint LocalEndPoint
{
get { return (IPEndPoint)sock.LocalEndPoint; }
}
public IPEndPoint RemoteEndPoint
{
get { return sock.RemoteEndPoint; }
}
public SocketState State
{
get
{
return sock.State;
}
}
public INetworkReceiver<ISocket> Receiver { get; set; }
public WSocket(ISocket socket)
{
pkt_send.FIN = true;
pkt_send.Mask = false;
pkt_send.Opcode = WebsocketPacket.WSOpcode.BinaryFrame;
sock = socket;
sock.Receiver = this;
//sock.OnClose += Sock_OnClose;
//sock.OnConnect += Sock_OnConnect;
//sock.OnReceive += Sock_OnReceive;
}
//private void Sock_OnReceive(NetworkBuffer buffer)
//{
//}
//private void Sock_OnConnect()
//{
// OnConnect?.Invoke();
//}
//private void Sock_OnClose()
//{
// OnClose?.Invoke();
//}
public void Send(WebsocketPacket packet)
{
lock (sendLock)
if (packet.Compose())
sock.Send(packet.Data);
}
public void Send(byte[] message)
{
lock (sendLock)
{
if (held)
{
sendNetworkBuffer.Write(message);
}
else
{
totalSent += message.Length;
//Console.WriteLine("TX " + message.Length +"/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size));
pkt_send.Message = message;
if (pkt_send.Compose())
sock?.Send(pkt_send.Data);
}
}
}
public void Send(byte[] message, int offset, int size)
{
lock (sendLock)
{
if (held)
{
sendNetworkBuffer.Write(message, (uint)offset, (uint)size);
}
else
{
totalSent += size;
//Console.WriteLine("TX " + size + "/"+totalSent);// + " " + DC.ToHex(message, 0, (uint)size));
pkt_send.Message = new byte[size];
Buffer.BlockCopy(message, offset, pkt_send.Message, 0, size);
if (pkt_send.Compose())
sock.Send(pkt_send.Data);
}
}
}
public void Close()
{
sock?.Close();
}
public AsyncReply<bool> Connect(string hostname, ushort port)
{
throw new NotImplementedException();
}
public bool Begin()
{
return sock.Begin();
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
//OnClose = null;
//OnConnect = null;
//OnReceive = null;
receiveNetworkBuffer = null;
//sock.OnReceive -= Sock_OnReceive;
//sock.OnClose -= Sock_OnClose;
//sock.OnConnect -= Sock_OnConnect;
sock.Receiver = null;
sock = null;
OnDestroy?.Invoke(this);
OnDestroy = null;
}
public AsyncReply<ISocket> AcceptAsync()
{
throw new NotImplementedException();
}
public void Hold()
{
//Console.WriteLine("WS Hold ");
held = true;
}
public void Unhold()
{
lock (sendLock)
{
held = false;
var message = sendNetworkBuffer.Read();
//Console.WriteLine("WS Unhold {0}", message == null ? 0 : message.Length);
if (message == null)
return;
totalSent += message.Length;
pkt_send.Message = message;
if (pkt_send.Compose())
sock.Send(pkt_send.Data);
}
}
public AsyncReply<bool> SendAsync(byte[] message, int offset, int length)
{
throw new NotImplementedException();
}
public ISocket Accept()
{
throw new NotImplementedException();
}
public AsyncReply<bool> BeginAsync()
{
return sock.BeginAsync();
}
public void NetworkClose(ISocket sender)
{
Receiver?.NetworkClose(sender);
}
public void NetworkReceive(ISocket sender, NetworkBuffer buffer)
{
if (sock.State == SocketState.Closed)
return;
if (buffer.Protected)
return;
var msg = buffer.Read();
if (msg == null)
return;
var wsPacketLength = pkt_receive.Parse(msg, 0, (uint)msg.Length);
if (wsPacketLength < 0)
{
buffer.Protect(msg, 0, (uint)msg.Length + (uint)-wsPacketLength);
return;
}
uint offset = 0;
while (wsPacketLength > 0)
{
if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.ConnectionClose)
{
Close();
return;
}
else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Ping)
{
var pkt_pong = new WebsocketPacket()
{
FIN = true,
Mask = false,
Opcode = WebsocketPacket.WSOpcode.Pong,
Message = pkt_receive.Message
};
offset += (uint)wsPacketLength;
Send(pkt_pong);
}
else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.Pong)
{
offset += (uint)wsPacketLength;
}
else if (pkt_receive.Opcode == WebsocketPacket.WSOpcode.BinaryFrame
|| pkt_receive.Opcode == WebsocketPacket.WSOpcode.TextFrame
|| pkt_receive.Opcode == WebsocketPacket.WSOpcode.ContinuationFrame)
{
totalReceived += pkt_receive.Message.Length;
//Console.WriteLine("RX " + pkt_receive.Message.Length + "/" + totalReceived);// + " " + DC.ToHex(message, 0, (uint)size));
receiveNetworkBuffer.Write(pkt_receive.Message);
offset += (uint)wsPacketLength;
//Console.WriteLine("WS IN: " + pkt_receive.Opcode.ToString() + " " + pkt_receive.Message.Length + " | " + offset + " " + string.Join(" ", pkt_receive.Message));// DC.ToHex(pkt_receive.Message));
}
else
{
Global.Log("WSocket", LogType.Debug, "Unknown WS opcode:" + pkt_receive.Opcode);
}
if (offset == msg.Length)
{
Receiver?.NetworkReceive(this, receiveNetworkBuffer);
return;
}
wsPacketLength = pkt_receive.Parse(msg, offset, (uint)msg.Length);
}
if (wsPacketLength < 0)
{
// save the incomplete packet to the heldBuffer queue
buffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)(msg.Length - offset) + (uint)-wsPacketLength);
}
//Console.WriteLine("WS IN: " + receiveNetworkBuffer.Available);
Receiver?.NetworkReceive(this, receiveNetworkBuffer);
if (buffer.Available > 0 && !buffer.Protected)
NetworkReceive(this, buffer);
}
public void NetworkConnect(ISocket sender)
{
Receiver?.NetworkConnect(this);
}
}

View File

@@ -0,0 +1,65 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using Esiur.Net.Sockets;
using System.Net;
using System.Collections;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.Tcp;
public class TcpConnection : NetworkConnection
{
private KeyList<string, object> variables = new KeyList<string, object>();
public TcpServer Server { get; internal set; }
public KeyList<string, object> Variables
{
get
{
return variables;
}
}
protected override void Connected()
{
// do nothing
}
protected override void DataReceived(NetworkBuffer buffer)
{
Server?.Execute(this, buffer);
}
protected override void Disconnected()
{
// do nothing
}
}

View File

@@ -0,0 +1,67 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Collections;
using Esiur.Data;
using Esiur.Net.Sockets;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.Tcp;
public abstract class TcpFilter : IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public virtual bool Connected(TcpConnection sender)
{
return false;
}
public virtual bool Disconnected(TcpConnection sender)
{
return false;
}
public abstract bool Execute(byte[] msg, NetworkBuffer data, TcpConnection sender);
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}

View File

@@ -0,0 +1,162 @@
/*
Copyright (c) 2017-2019 Ahmed Kh. Zamil
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.Text;
using Esiur.Net.Sockets;
using Esiur.Misc;
using System.Threading;
using Esiur.Data;
using Esiur.Core;
using System.Net;
using Esiur.Resource;
namespace Esiur.Net.Tcp;
public class TcpServer : NetworkServer<TcpConnection>, IResource
{
[Attribute]
public string IP
{
get;
set;
}
[Attribute]
public ushort Port
{
get;
set;
}
//[Storable]
//public uint Timeout
//{
// get;
// set;
//}
//[Attribute]
//public uint Clock
//{
// get;
// set;
//}
public Instance Instance { get; set; }
TcpFilter[] filters = null;
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
TCPSocket listener;
if (IP != null)
listener = new TCPSocket(new IPEndPoint(IPAddress.Parse(IP), Port));
else
listener = new TCPSocket(new IPEndPoint(IPAddress.Any, Port));
Start(listener);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
else if (trigger == ResourceTrigger.SystemInitialized)
{
Instance.Children<TcpFilter>().Then(x => filters = x);
}
return new AsyncReply<bool>(true);
}
internal bool Execute(TcpConnection sender, NetworkBuffer data)
{
if (filters == null)
return false;
var msg = data.Read();
foreach (var filter in filters)
{
if (filter.Execute(msg, data, sender))
return true;
}
return false;
}
private void SessionModified(TcpConnection session, string key, object newValue)
{
}
protected override void ClientDisconnected(TcpConnection connection)
{
if (filters == null)
return;
foreach (var filter in filters)
{
filter.Disconnected(connection);
}
}
public override void Add(TcpConnection connection)
{
connection.Server = this;
base.Add(connection);
}
public override void Remove(TcpConnection connection)
{
connection.Server = null;
base.Remove(connection);
}
protected override void ClientConnected(TcpConnection connection)
{
if (filters == null)
return;
foreach (var filter in filters)
{
filter.Connected(connection);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Tcp;
public class TcpSession : NetworkSession
{
}

View File

@@ -0,0 +1,58 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Text;
using System.Collections;
using System.Net;
using Esiur.Data;
using Esiur.Core;
using Esiur.Resource;
namespace Esiur.Net.UDP;
public abstract class UdpFilter : IResource
{
public Instance Instance
{
get;
set;
}
public event DestroyedEvent OnDestroy;
public abstract AsyncReply<bool> Trigger(ResourceTrigger trigger);
public abstract bool Execute(byte[] data, IPEndPoint sender);
public void Destroy()
{
OnDestroy?.Invoke(this);
}
}

View File

@@ -0,0 +1,203 @@
/*
Copyright (c) 2017 Ahmed Kh. Zamil
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.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Collections;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Resource;
using Esiur.Core;
namespace Esiur.Net.UDP;
/* public class EPConnection
{
public EndPoint SenderPoint;
public
}*/
public class UdpServer : IResource
{
Thread receiver;
UdpClient udp;
UdpFilter[] filters = new UdpFilter[0];
public event DestroyedEvent OnDestroy;
public Instance Instance
{
get;
set;
}
[Attribute]
string IP
{
get;
set;
}
[Attribute]
ushort Port
{
get;
set;
}
private void Receiving()
{
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] b = udp.Receive(ref ep);
foreach (var child in filters)
{
var f = child as UdpFilter;
try
{
if (f.Execute(b, ep))
{
break;
}
}
catch (Exception ex)
{
Global.Log("UDPServer", LogType.Error, ex.ToString());
//Console.WriteLine(ex.ToString());
}
}
}
}
public bool Send(byte[] Data, int Count, IPEndPoint EP)
{
try
{
udp.Send(Data, Count, EP);
return true;
}
catch
{
return false;
}
}
public bool Send(byte[] Data, IPEndPoint EP)
{
try
{
udp.Send(Data, Data.Length, EP);
return true;
}
catch
{
return false;
}
}
public bool Send(byte[] Data, int Count, string Host, int Port)
{
try
{
udp.Send(Data, Count, Host, Port);
return true;
}
catch
{
return false;
}
}
public bool Send(byte[] Data, string Host, int Port)
{
try
{
udp.Send(Data, Data.Length, Host, Port);
return true;
}
catch
{
return false;
}
}
public bool Send(string Data, IPEndPoint EP)
{
try
{
udp.Send(Encoding.Default.GetBytes(Data), Data.Length, EP);
return true;
}
catch
{
return false;
}
}
public bool Send(string Data, string Host, int Port)
{
try
{
udp.Send(Encoding.Default.GetBytes(Data), Data.Length, Host, Port);
return true;
}
catch
{
return false;
}
}
public void Destroy()
{
udp.Close();
OnDestroy?.Invoke(this);
}
async AsyncReply<bool> IResource.Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
var address = IP == null ? IPAddress.Any : IPAddress.Parse(IP);
udp = new UdpClient(new IPEndPoint(address, Port));
receiver = new Thread(Receiving);
receiver.Start();
}
else if (trigger == ResourceTrigger.Terminate)
{
if (receiver != null)
receiver.Abort();
}
else if (trigger == ResourceTrigger.SystemInitialized)
{
filters = await Instance.Children<UdpFilter>();
}
return true;
}
}