2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-06-26 21:13:13 +00:00

Add project files.

This commit is contained in:
Ahmed Zamil
2017-09-15 23:40:03 +03:00
parent 4c95cb1cc6
commit 7ae722ab51
99 changed files with 14687 additions and 0 deletions

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Engine;
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()
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Engine;
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()
{
throw new NotImplementedException();
}
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
foreach (Instance instance in Instance.Children)
{
if (instance.Resource is PacketFilter)
{
filters.Add(instance.Resource as PacketFilter);
}
else if (instance.Resource is PacketSource)
{
sources.Add(instance.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,71 @@
using Esiur.Net.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Engine;
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()
{
throw new NotImplementedException();
}
/*
public virtual string TypeName
{
get
{
return "Raw";
}
}
*/
public abstract byte[] Address
{
get;
}
public abstract string DeviceId
{
get;
}
}
}

View File

@ -0,0 +1,346 @@
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.Net.Packets;
using Esiur.Misc;
using System.Security.Cryptography;
namespace Esiur.Net.HTTP
{
//[Serializable]
public class HTTPConnection : NetworkConnection
{
/*
public enum SendOptions : int
{
AllCalculateLength,
AllDontCalculateLength,
SpecifiedHeadersOnly,
DataOnly
}
*/
public HTTPConnection()
{
Response = new HTTPResponsePacket();
variables = new KeyList<string, object>();
}
public void SetParent(HTTPServer Parent)
{
Server = Parent;
}
//public bool HeadersSent;
private KeyList<string, object> variables;
private bool Busy = false;
private DateTime RequestTime = DateTime.MinValue;
public bool WSMode;
private HTTPServer Server;
public WebsocketPacket WSRequest;
public HTTPRequestPacket Request;
public HTTPResponsePacket Response;
HTTPSession session;
public KeyList<string, object> Variables
{
get
{
return variables;
}
}
public bool IsBusy()
{
return Busy;
}
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
{
HTTPRequestPacket rp = new HTTPRequestPacket();
var pSize = rp.Parse(data, 0, (uint)data.Length);
if (pSize > 0)
{
Request = rp;
return 0;
}
else
{
return pSize;
}
}
}
/*
public override void Send(string Response)
{
Send(Response, SendOptions.AllCalculateLength);
}
public void Send(string Message, SendOptions Options)
{
if (Response.Handled)
return;
if (Response != null)
Send(Encoding.Default.GetBytes(Response), Options);
else
Send((byte[])null, Options);
}
public void Send(MemoryStream ms)
{
Send(ms.ToArray(), SendOptions.AllCalculateLength);
}
*/
public void Flush()
{
// close the connection
if (Request.Headers["connection"].ToLower() != "keep-alive" & Connected)
Close();
}
public bool Upgrade()
{
if (IsWebsocketRequest())
{
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.Headers["Sec-WebSocket-Protocol"] = Request.Headers["Sec-WebSocket-Protocol"];
//Response.Headers["Origin"] = Request.Headers["Origin"];
Response.Number = HTTPResponsePacket.ResponseCode.HTTP_SWITCHING;
Response.Text = "Switching Protocols";
WSMode = true;
//Send((byte[])null, SendOptions.AllDontCalculateLength);
Send();
return true;
}
return false;
}
public HTTPServer Parent
{
get
{
return Server;
}
}
public override void Send(string data)
{
Response.Message = Encoding.UTF8.GetBytes(data);
Send();
}
public override void Send(byte[] message)
{
Response.Message = message;
Send();
}
public void Send(HTTPResponsePacket.ComposeOptions Options = HTTPResponsePacket.ComposeOptions.AllCalculateLength)
{
if (Response.Handled)
return;
Busy = true;
try
{
Response.Compose(Options);
base.Send(Response.Data);
// Refresh the current session
if (session != null)
session.Refresh();
}
catch
{
try
{
Close();// Server.CloseClient(Connection);
}
finally { }
}
finally
{
Busy = false;
}
}
public void CreateNewSession()
{
if (session == null)
{
// Create a new one
session = Server.CreateSession(Global.GenerateCode(12), 60 * 20);
HTTPResponsePacket.HTTPCookie cookie = new HTTPResponsePacket.HTTPCookie("SID", session.Id);
cookie.Expires = DateTime.MaxValue;
cookie.Path = "/";
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
}
}
public bool IsWebsocketRequest()
{
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;
}
}
public void SendFile(string filename)
{
if (Response.Handled == true)
return;
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 = HTTPResponsePacket.ResponseCode.HTTP_NOTFOUND;
Send("File Not Found");//, SendOptions.AllCalculateLength);
return;
}
Busy = true;
System.DateTime FWD = File.GetLastWriteTime(filename);
if (Request.Headers.ContainsKey("if-modified-since"))// != DateTime.Parse("12:00:00 AM"))
{
try
{
DateTime IMS = DateTime.Parse(Request.Headers["if-modified-since"]);
if (FWD <= IMS)
{
Response.Number = HTTPResponsePacket.ResponseCode.HTTP_NOTMODIFIED;
Response.Text = "Not Modified";
}
}
catch
{
}
}
if (Response.Number == HTTPResponsePacket.ResponseCode.HTTP_NOTMODIFIED)
{
Send((byte[])null);
}
else
{
// Fri, 30 Oct 2007 14:19:41 GMT
Response.Headers["Last-Modified"] = FWD.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss");
FileInfo fi = new FileInfo(filename);
Response.Headers["Content-Length"] = fi.Length.ToString();
Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly);
using (var fs = new FileStream(filename, FileMode.Open))
{
var buffer = new byte[5000];
var offset = 0;
while (offset < fs.Length)
{
var n = fs.Read(buffer, offset, buffer.Length);
offset += n;
base.Send(buffer);
}
}
}
Busy = false;
return;
}
catch
{
Busy = false;
try
{
Close();
}
finally { }
}
}
}
}

View File

@ -0,0 +1,58 @@
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.Engine;
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 bool Execute(HTTPConnection sender);
public virtual void ClientConnected(HTTPConnection HTTP)
{
//return false;
}
public virtual void ClientDisconnected(HTTPConnection HTTP)
{
//return false;
}
public void Destroy()
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,416 @@
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.Engine;
using Esiur.Net.Packets;
using System.Security.Cryptography.X509Certificates;
using Esiur.Resource;
namespace Esiur.Net.HTTP
{
public class HTTPServer : NetworkServer<HTTPConnection>, IResource
{
Dictionary<string, HTTPSession> sessions= new Dictionary<string, HTTPSession>();
public Instance Instance
{
get;
set;
}
[Storable]
string ip
{
get;
set;
}
[Storable]
ushort port
{
get;
set;
}
[Storable]
uint timeout
{
get;
set;
}
[Storable]
uint clock
{
get;
set;
}
[Storable]
uint maxPost
{
get;
set;
}
[Storable]
bool ssl
{
get;
set;
}
[Storable]
string certificate
{
get;
set;
}
//public override void ClientConnected(TClient Sender)
//{
//}
/*
public DStringDictionary Configurations
{
get { return config; }
}
*/
public enum ResponseCodes : int
{
HTTP_OK = 200,
HTTP_NOTFOUND = 404,
HTTP_SERVERERROR = 500,
HTTP_MOVED = 301,
HTTP_NOTMODIFIED = 304,
HTTP_REDIRECT = 307
}
public HTTPSession CreateSession(string id, int timeout)
{
var s = new HTTPSession();
s.Set(id, timeout);
sessions.Add(id, s);
return s;
}
/*
protected override void SessionModified(NetworkSession session, string key, object oldValue, object newValue)
{
foreach (var instance in Instance.Children)
{
var f = (HTTPFilter)instance;
f.SessionModified(session as HTTPSession, key, oldValue, newValue);
}
}
*/
//public override object InitializeLifetimeService()
//{
// return null;
//}
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 sender)
{
Console.WriteLine("OUT: " + this.Connections.Count);
foreach (IResource resource in Instance.Children)
{
if (resource is HTTPFilter)
{
(resource as HTTPFilter).ClientDisconnected(sender);
}
}
}
protected override void DataReceived(HTTPConnection sender, NetworkBuffer data)
{
//Console.WriteLine(Data);
// Initialize a new session
//HTTPConnection HTTP = (HTTPConnection)sender.ExtraObject;
//string Data = System.Text.Encoding.Default.GetString(ReceivedData);
byte[] msg = data.Read();
var BL = sender.Parse(msg);
if (BL == 0)
{
if (sender.Request.Method == HTTPRequestPacket.HTTPMethod.UNKNOWN)
{
sender.Close();
return;
}
if (sender.Request.URL == "")
{
sender.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 > maxPost)
{
sender.Send(
"<html><body>POST method content is larger than "
+ maxPost
+ " bytes.</body></html>");
sender.Close();
}
else
{
data.HoldFor(msg, (uint)(msg.Length + BL));
}
return;
}
else if (BL < 0) // for security
{
sender.Close();
return;
}
if (sender.IsWebsocketRequest() & !sender.WSMode)
{
sender.Upgrade();
//return;
}
//return;
try
{
foreach (IResource resource in Instance.Children)
{
if (resource is HTTPFilter)
{
if ((resource as HTTPFilter).Execute(sender))
return;
}
}
sender.Send("Bad Request");
sender.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);
sender.Send(Return500(ex.Message));
}
}
}
private string Return500(string sMessage)
{
string sTMP = null;
sTMP = "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE></HEAD><br>\r\n";
sTMP = sTMP + "<BODY BGCOLOR=" + (char)(34) + "#FFFFFF" + (char)(34) + " Text=" + (char)(34) + "#000000" + (char)(34) + " LINK=" + (char)(34) + "#0000FF" + (char)(34) + " VLINK=" + (char)(34) + "#000080" + (char)(34) + " ALINK=" + (char)(34) + "#008000" + (char)(34) + "><br>\r\n";
sTMP = sTMP + "<b>500</b> Sorry - Internal Server Error<br>" + sMessage + "\r\n";
sTMP = sTMP + "</BODY><br>\r\n";
sTMP = sTMP + "</HTML><br>\r\n";
return sTMP;
}
/*
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 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;
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,
timeout,
clock);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
return new AsyncReply<bool>(true);
}
protected override void ClientConnected(HTTPConnection sender)
{
//sender.SessionModified += SessionModified;
//sender.SessionEnded += SessionExpired;
sender.SetParent(this);
Console.WriteLine("IN: " + this.Connections.Count);
foreach (IResource resource in Instance.Children)
{
if (resource is HTTPFilter)
{
(resource as HTTPFilter).ClientConnected(sender);
}
}
}
public void Destroy()
{
throw new NotImplementedException();
}
/*
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,106 @@
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.Engine;
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)
{
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; }
}
}
}

51
Esiur/Net/HTTP/IIPoWS.cs Normal file
View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esiur.Resource;
using Esiur.Net.IIP;
using Esiur.Net.Sockets;
using Esiur.Engine;
namespace Esiur.Net.HTTP
{
public class IIPoWS: HTTPFilter
{
public override bool Execute(HTTPConnection sender)
{
if (sender.Request.Filename.StartsWith("/iip/"))
{
// find the service
var path = sender.Request.Filename.Substring(5);// sender.Request.Query["path"];
Warehouse.Get(path).Then((r) =>
{
if (r is DistributedServer)
{
var httpServer = sender.Parent;
var iipServer = r as DistributedServer;
var tcpSocket = sender.Unassign();
var wsSocket = new WSSocket(tcpSocket);
httpServer.Connections.Remove(sender);
var iipConnection = new DistributedConnection();
iipConnection.Server = iipServer;
iipConnection.Assign(wsSocket);
}
});
return true;
}
return false;
}
public override AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>(true);
}
}
}

View File

@ -0,0 +1,514 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using Esiur.Net.Sockets;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Engine;
using Esiur.Net.Packets;
using Esiur.Resource;
using Esiur.Security.Authority;
using Esiur.Resource.Template;
using System.Linq;
using System.Diagnostics;
namespace Esiur.Net.IIP
{
public partial class DistributedConnection : NetworkConnection, IStore
{
public delegate void ReadyEvent(DistributedConnection sender);
public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage);
/// <summary>
/// Ready event is raised when the connection is fully established.
/// </summary>
public event ReadyEvent OnReady;
/// <summary>
/// Error event
/// </summary>
public event ErrorEvent OnError;
IIPPacket packet = new IIPPacket();
IIPAuthPacket authPacket = new IIPAuthPacket();
byte[] sessionId;
AuthenticationType hostType;
string domain;
string localUsername, remoteUsername;
byte[] localPassword;
byte[] localNonce, remoteNonce;
bool ready, readyToEstablish;
DateTime loginDate;
KeyList<string, object> variables = new KeyList<string, object>();
/// <summary>
/// Local username to authenticate ourselves.
/// </summary>
public string LocalUsername { get; set; }
/// <summary>
/// Peer's username.
/// </summary>
public string RemoteUsername { get; set; }
/// <summary>
/// Working domain.
/// </summary>
public string Domain { get { return domain; } }
/// <summary>
/// Distributed server responsible for this connection, usually for incoming connections.
/// </summary>
public DistributedServer Server
{
get;
set;
}
/// <summary>
/// Send data to the other end as parameters
/// </summary>
/// <param name="values">Values will be converted to bytes then sent.</param>
internal void SendParams(params object[] values)
{
var ar = BinaryList.ToBytes(values);
Send(ar);
//StackTrace stackTrace = new StackTrace(;
// Get calling method name
//Console.WriteLine("TX " + hostType + " " + ar.Length + " " + stackTrace.GetFrame(1).GetMethod().ToString());
}
/// <summary>
/// Send raw data through the connection.
/// </summary>
/// <param name="data">Data to send.</param>
public override void Send(byte[] data)
{
//Console.WriteLine("Client: {0}", Data.Length);
Global.Counters["IIP Sent Packets"]++;
base.Send(data);
}
/// <summary>
/// KeyList to store user variables related to this connection.
/// </summary>
public KeyList<string, object> Variables
{
get
{
return variables;
}
}
/// <summary>
/// IResource interface.
/// </summary>
public Instance Instance
{
get;
set;
}
/// <summary>
/// Assign a socket to the connection.
/// </summary>
/// <param name="socket">Any socket that implements ISocket.</param>
public override void Assign(ISocket socket)
{
base.Assign(socket);
if (hostType == AuthenticationType.Client)
{
// declare (Credentials -> No Auth, No Enctypt)
var un = DC.ToBytes(localUsername);
var dmn = DC.ToBytes(domain);
if (socket.State == SocketState.Established)
{
SendParams((byte)0x60, (byte)dmn.Length, dmn, localNonce, (byte)un.Length, un);
}
else
{
socket.OnConnect += () =>
{ // declare (Credentials -> No Auth, No Enctypt)
SendParams((byte)0x60, (byte)dmn.Length, dmn, localNonce, (byte)un.Length, un);
};
}
}
}
/// <summary>
/// Create a new distributed connection.
/// </summary>
/// <param name="socket">Socket to transfer data through.</param>
/// <param name="domain">Working domain.</param>
/// <param name="username">Username.</param>
/// <param name="password">Password.</param>
public DistributedConnection(ISocket socket, string domain, string username, string password)
{
//Instance.Name = Global.GenerateCode(12);
this.hostType = AuthenticationType.Client;
this.domain = domain;
this.localUsername = username;
this.localPassword = DC.ToBytes(password);
init();
Assign(socket);
}
/// <summary>
/// Create a new instance of a distributed connection
/// </summary>
public DistributedConnection()
{
//myId = Global.GenerateCode(12);
// localParams.Host = DistributedParameters.HostType.Host;
init();
}
public string Link(IResource resource)
{
if (resource is DistributedConnection)
{
var r = resource as DistributedResource;
if (r.Instance.Store == this)
return this.Instance.Name + "/" + r.Id;
}
return null;
}
void init()
{
queue.Then((x) =>
{
if (x.Type == DistributedResourceQueueItem.DistributedResourceQueueItemType.Event)
x.Resource._EmitEventByIndex(x.Index, (object[])x.Value);
else
x.Resource.UpdatePropertyByIndex(x.Index, x.Value);
});
var r = new Random();
localNonce = new byte[32];
r.NextBytes(localNonce);
}
protected override void DataReceived(NetworkBuffer data)
{
// Console.WriteLine("DR " + hostType + " " + data.Available + " " + RemoteEndPoint.ToString());
var msg = data.Read();
uint offset = 0;
uint ends = (uint)msg.Length;
while (offset < ends)
{
if (ready)
{
var rt = packet.Parse(msg, offset, ends);
if (rt <= 0)
{
data.HoldFor(msg, offset, ends - offset, (uint)(-rt));
return;
}
else
{
offset += (uint)rt;
if (packet.Command == IIPPacket.IIPPacketCommand.Event)
{
switch (packet.Event)
{
case IIPPacket.IIPPacketEvent.ResourceReassigned:
IIPEventResourceReassigned(packet.ResourceId, packet.NewResourceId);
break;
case IIPPacket.IIPPacketEvent.ResourceDestroyed:
IIPEventResourceDestroyed(packet.ResourceId);
break;
case IIPPacket.IIPPacketEvent.PropertyUpdated:
IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, packet.Content);
break;
case IIPPacket.IIPPacketEvent.EventOccured:
IIPEventEventOccured(packet.ResourceId, packet.MethodIndex, packet.Content);
break;
}
}
else if (packet.Command == IIPPacket.IIPPacketCommand.Request)
{
switch (packet.Action)
{
case IIPPacket.IIPPacketAction.AttachResource:
IIPRequestAttachResource(packet.CallbackId, packet.ResourceId);
break;
case IIPPacket.IIPPacketAction.ReattachResource:
IIPRequestReattachResource(packet.CallbackId, packet.ResourceId, packet.ResourceAge);
break;
case IIPPacket.IIPPacketAction.DetachResource:
IIPRequestDetachResource(packet.CallbackId, packet.ResourceId);
break;
case IIPPacket.IIPPacketAction.CreateResource:
IIPRequestCreateResource(packet.CallbackId, packet.ClassName);
break;
case IIPPacket.IIPPacketAction.DeleteResource:
IIPRequestDeleteResource(packet.CallbackId, packet.ResourceId);
break;
case IIPPacket.IIPPacketAction.TemplateFromClassName:
IIPRequestTemplateFromClassName(packet.CallbackId, packet.ClassName);
break;
case IIPPacket.IIPPacketAction.TemplateFromClassId:
IIPRequestTemplateFromClassId(packet.CallbackId, packet.ClassId);
break;
case IIPPacket.IIPPacketAction.TemplateFromResourceLink:
IIPRequestTemplateFromResourceLink(packet.CallbackId, packet.ResourceLink);
break;
case IIPPacket.IIPPacketAction.TemplateFromResourceId:
IIPRequestTemplateFromResourceId(packet.CallbackId, packet.ResourceId);
break;
case IIPPacket.IIPPacketAction.ResourceIdFromResourceLink:
IIPRequestResourceIdFromResourceLink(packet.CallbackId, packet.ResourceLink);
break;
case IIPPacket.IIPPacketAction.InvokeFunction:
IIPRequestInvokeFunction(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
break;
case IIPPacket.IIPPacketAction.GetProperty:
IIPRequestGetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex);
break;
case IIPPacket.IIPPacketAction.GetPropertyIfModified:
IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge);
break;
case IIPPacket.IIPPacketAction.SetProperty:
IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.Content);
break;
}
}
else if (packet.Command == IIPPacket.IIPPacketCommand.Reply)
{
switch (packet.Action)
{
case IIPPacket.IIPPacketAction.AttachResource:
IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.Content);
//IIPReplyAttachResource(packet.CallbackId, packet.ResourceAge, Codec.ParseValues(packet.Content));
break;
case IIPPacket.IIPPacketAction.ReattachResource:
//IIPReplyReattachResource(packet.CallbackId, packet.ResourceAge, Codec.ParseValues(packet.Content));
IIPReply(packet.CallbackId, packet.ResourceAge, packet.Content);
break;
case IIPPacket.IIPPacketAction.DetachResource:
//IIPReplyDetachResource(packet.CallbackId);
IIPReply(packet.CallbackId);
break;
case IIPPacket.IIPPacketAction.CreateResource:
//IIPReplyCreateResource(packet.CallbackId, packet.ClassId, packet.ResourceId);
IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceId);
break;
case IIPPacket.IIPPacketAction.DeleteResource:
//IIPReplyDeleteResource(packet.CallbackId);
IIPReply(packet.CallbackId);
break;
case IIPPacket.IIPPacketAction.TemplateFromClassName:
//IIPReplyTemplateFromClassName(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
break;
case IIPPacket.IIPPacketAction.TemplateFromClassId:
//IIPReplyTemplateFromClassId(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
break;
case IIPPacket.IIPPacketAction.TemplateFromResourceLink:
//IIPReplyTemplateFromResourceLink(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
break;
case IIPPacket.IIPPacketAction.TemplateFromResourceId:
//IIPReplyTemplateFromResourceId(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
IIPReply(packet.CallbackId, ResourceTemplate.Parse(packet.Content));
break;
case IIPPacket.IIPPacketAction.ResourceIdFromResourceLink:
//IIPReplyResourceIdFromResourceLink(packet.CallbackId, packet.ClassId, packet.ResourceId, packet.ResourceAge);
IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceId, packet.ResourceAge);
break;
case IIPPacket.IIPPacketAction.InvokeFunction:
//IIPReplyInvokeFunction(packet.CallbackId, Codec.Parse(packet.Content, 0));
IIPReply(packet.CallbackId, packet.Content);
break;
case IIPPacket.IIPPacketAction.GetProperty:
//IIPReplyGetProperty(packet.CallbackId, Codec.Parse(packet.Content, 0));
IIPReply(packet.CallbackId, packet.Content);
break;
case IIPPacket.IIPPacketAction.GetPropertyIfModified:
//IIPReplyGetPropertyIfModifiedSince(packet.CallbackId, Codec.Parse(packet.Content, 0));
IIPReply(packet.CallbackId, packet.Content);
break;
case IIPPacket.IIPPacketAction.SetProperty:
//IIPReplySetProperty(packet.CallbackId);
IIPReply(packet.CallbackId);
break;
}
}
}
}
else
{
var rt = authPacket.Parse(msg, offset, ends);
Console.WriteLine(hostType.ToString() + " " + offset + " " + ends + " " + rt + " " + authPacket.ToString());
if (rt <= 0)
{
data.HoldFor(msg, ends + (uint)(-rt));
return;
}
else
{
offset += (uint)rt;
if (hostType == AuthenticationType.Host)
{
if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Declare)
{
if (authPacket.RemoteMethod == IIPAuthPacket.IIPAuthPacketMethod.Credentials && authPacket.LocalMethod == IIPAuthPacket.IIPAuthPacketMethod.None)
{
remoteUsername = authPacket.RemoteUsername;
remoteNonce = authPacket.RemoteNonce;
domain = authPacket.Domain;
SendParams((byte)0xa0, localNonce);
}
}
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action)
{
if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash)
{
var remoteHash = authPacket.Hash;
Server.Membership.GetPassword(remoteUsername, domain).Then((pw) =>
{
if (pw != null)
{
var hashFunc = SHA256.Create();
var hash = hashFunc.ComputeHash(BinaryList.ToBytes(pw, remoteNonce, localNonce));
if (hash.SequenceEqual(remoteHash))
{
// send our hash
var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localNonce, remoteNonce, pw));
SendParams((byte)0, localHash);
readyToEstablish = true;
}
else
{
Console.WriteLine("Incorrect password");
SendParams((byte)0xc0, (byte)1, (ushort)5, DC.ToBytes("Error"));
}
}
});
}
else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.NewConnection)
{
if (readyToEstablish)
{
var r = new Random();
sessionId = new byte[32];
r.NextBytes(sessionId);
SendParams((byte)0x28, sessionId);
ready = true;
OnReady?.Invoke(this);
}
}
}
}
else if (hostType == AuthenticationType.Client)
{
if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge)
{
remoteNonce = authPacket.RemoteNonce;
// send our hash
var hashFunc = SHA256.Create();
var localHash = hashFunc.ComputeHash(BinaryList.ToBytes(localPassword, localNonce, remoteNonce));
SendParams((byte)0, localHash);
}
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action)
{
if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash)
{
// check if the server knows my password
var hashFunc = SHA256.Create();
var remoteHash = hashFunc.ComputeHash(BinaryList.ToBytes(remoteNonce, localNonce, localPassword));
if (remoteHash.SequenceEqual(authPacket.Hash))
{
// send establish request
SendParams((byte)0x20, (ushort)0);
}
else
{
SendParams((byte)0xc0, 1, (ushort)5, DC.ToBytes("Error"));
}
}
else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.ConnectionEstablished)
{
sessionId = authPacket.SessionId;
ready = true;
OnReady?.Invoke(this);
}
}
else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error)
{
OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage);
Close();
}
}
}
}
}
}
/// <summary>
/// Resource interface
/// </summary>
/// <param name="trigger">Resource trigger.</param>
/// <returns></returns>
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
return new AsyncReply<bool>();
}
/// <summary>
/// Store interface.
/// </summary>
/// <param name="resource">Resource.</param>
/// <returns></returns>
public bool Put(IResource resource)
{
resources.Add(Convert.ToUInt32(resource.Instance.Name), (DistributedResource)resource);
return true;
}
}
}

View File

@ -0,0 +1,802 @@
using Esiur.Data;
using Esiur.Engine;
using Esiur.Net.Packets;
using Esiur.Resource;
using Esiur.Resource.Template;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.IIP
{
partial class DistributedConnection
{
KeyList<uint, DistributedResource> resources = new KeyList<uint, DistributedResource>();
KeyList<uint, AsyncReply<DistributedResource>> resourceRequests = new KeyList<uint, AsyncReply<DistributedResource>>();
KeyList<Guid, AsyncReply<ResourceTemplate>> templateRequests = new KeyList<Guid, AsyncReply<ResourceTemplate>>();
KeyList<string, AsyncReply<IResource>> pathRequests = new KeyList<string, AsyncReply<IResource>>();
Dictionary<Guid, ResourceTemplate> templates = new Dictionary<Guid, ResourceTemplate>();
KeyList<uint, AsyncReply<object[]>> requests = new KeyList<uint, AsyncReply<object[]>>();
uint callbackCounter = 0;
AsyncQueue<DistributedResourceQueueItem> queue = new AsyncQueue<DistributedResourceQueueItem>();
/// <summary>
/// Send IIP request.
/// </summary>
/// <param name="action">Packet action.</param>
/// <param name="args">Arguments to send.</param>
/// <returns></returns>
internal AsyncReply<object[]> SendRequest(IIPPacket.IIPPacketAction action, params object[] args)
{
var reply = new AsyncReply<object[]>();
callbackCounter++;
var bl = new BinaryList((byte)(0x40 | (byte)action), callbackCounter);
bl.AddRange(args);
Send(bl.ToArray());
requests.Add(callbackCounter, reply);
return reply;
}
void IIPReply(uint callbackId, params object[] results)
{
var req = requests.Take(callbackId);
req?.Trigger(results);
}
void IIPEventResourceReassigned(uint resourceId, uint newResourceId)
{
}
void IIPEventResourceDestroyed(uint resourceId)
{
if (resources.Contains(resourceId))
{
var r = resources[resourceId];
resources.Remove(resourceId);
r.Destroy();
}
}
void IIPEventPropertyUpdated(uint resourceId, byte index, byte[] content)
{
if (resources.Contains(resourceId))
{
// push to the queue to gaurantee serialization
var reply = new AsyncReply<DistributedResourceQueueItem>();
queue.Add(reply);
var r = resources[resourceId];
Codec.Parse(content, 0, this).Then((arguments) =>
{
var pt = r.Template.GetPropertyTemplate(index);
if (pt != null)
{
reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, DistributedResourceQueueItem.DistributedResourceQueueItemType.Propery, arguments, index));
}
else
{ // ft found, fi not found, this should never happen
queue.Remove(reply);
}
});
}
}
void IIPEventEventOccured(uint resourceId, byte index, byte[] content)
{
if (resources.Contains(resourceId))
{
// push to the queue to gaurantee serialization
var reply = new AsyncReply<DistributedResourceQueueItem>();
var r = resources[resourceId];
queue.Add(reply);
Codec.ParseVarArray(content, this).Then((arguments) =>
{
var et = r.Template.GetEventTemplate(index);
if (et != null)
{
reply.Trigger(new DistributedResourceQueueItem((DistributedResource)r, DistributedResourceQueueItem.DistributedResourceQueueItemType.Event, arguments, index));
}
else
{ // ft found, fi not found, this should never happen
queue.Remove(reply);
}
});
}
}
void IIPRequestAttachResource(uint callback, uint resourceId)
{
Warehouse.Get(resourceId).Then((res) =>
{
if (res != null)
{
var r = res as IResource;
r.Instance.ResourceEventOccured += Instance_EventOccured;
r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
var link = DC.ToBytes(r.Instance.Link);
// reply ok
SendParams((byte)0x80, callback, r.Instance.Template.ClassId, r.Instance.Age, (ushort)link.Length, link, Codec.ComposeVarArray(r.Instance.Serialize(), this, true));
}
else
{
// reply failed
//SendParams(0x80, r.Instance.Id, r.Instance.Age, r.Instance.Serialize(false, this));
}
});
}
void IIPRequestReattachResource(uint callback, uint resourceId, uint resourceAge)
{
Warehouse.Get(resourceId).Then((res) =>
{
if (res != null)
{
var r = res as IResource;
r.Instance.ResourceEventOccured += Instance_EventOccured;
r.Instance.ResourceModified += Instance_PropertyModified;
r.Instance.ResourceDestroyed += Instance_ResourceDestroyed;
// reply ok
SendParams((byte)0x81, callback, r.Instance.Age, Codec.ComposeVarArray(r.Instance.Serialize(), this, true));
}
else
{
// reply failed
}
});
}
void IIPRequestDetachResource(uint callback, uint resourceId)
{
Warehouse.Get(resourceId).Then((res) =>
{
if (res != null)
{
var r = res as IResource;
r.Instance.ResourceEventOccured -= Instance_EventOccured;
r.Instance.ResourceModified -= Instance_PropertyModified;
r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed;
// reply ok
SendParams((byte)0x82, callback);
}
else
{
// reply failed
}
});
}
void IIPRequestCreateResource(uint callback, string className)
{
// not implemented
}
void IIPRequestDeleteResource(uint callback, uint resourceId)
{
// not implemented
}
void IIPRequestTemplateFromClassName(uint callback, string className)
{
Warehouse.GetTemplate(className).Then((t) =>
{
if (t != null)
SendParams((byte)0x88, callback, t.Content);
else
{
// reply failed
}
});
}
void IIPRequestTemplateFromClassId(uint callback, Guid classId)
{
Warehouse.GetTemplate(classId).Then((t) =>
{
if (t != null)
SendParams((byte)0x89, callback, (uint)t.Content.Length, t.Content);
else
{
// reply failed
}
});
}
void IIPRequestTemplateFromResourceLink(uint callback, string resourceLink)
{
Warehouse.GetTemplate(resourceLink).Then((t) =>
{
if (t != null)
SendParams((byte)0x8A, callback, t.Content);
else
{
// reply failed
}
});
}
void IIPRequestTemplateFromResourceId(uint callback, uint resourceId)
{
Warehouse.Get(resourceId).Then((r) =>
{
if (r != null)
SendParams((byte)0x8B, callback, r.Instance.Template.Content);
else
{
// reply failed
}
});
}
void IIPRequestResourceIdFromResourceLink(uint callback, string resourceLink)
{
Warehouse.Get(resourceLink).Then((r) =>
{
if (r != null)
SendParams((byte)0x8C, callback, r.Instance.Template.ClassId, r.Instance.Id, r.Instance.Age);
else
{
// reply failed
}
});
}
void IIPRequestInvokeFunction(uint callback, uint resourceId, byte index, byte[] content)
{
Warehouse.Get(resourceId).Then((r) =>
{
if (r != null)
{
Codec.ParseVarArray(content, this).Then(async (arguments) =>
{
var ft = r.Instance.Template.GetFunctionTemplate(index);
if (ft != null)
{
if (r is DistributedResource)
{
var rt = (r as DistributedResource)._Invoke(index, arguments);
if (rt != null)
{
rt.Then(res =>
{
SendParams((byte)0x90, callback, Codec.Compose(res, this));
});
}
else
{
// function not found on a distributed object
}
}
else
{
#if NETSTANDARD1_5
var fi = r.GetType().GetTypeInfo().GetMethod(ft.Name);
#else
var fi = r.GetType().GetMethod(ft.Name);
#endif
if (fi != null)
{
// cast shit
ParameterInfo[] pi = fi.GetParameters();
object[] args = null;
if (pi.Length > 0)
{
int argsCount = pi.Length;
args = new object[pi.Length];
if (pi[pi.Length - 1].ParameterType == typeof(DistributedConnection))
{
args[--argsCount] = this;
}
if (arguments != null)
{
for (int i = 0; i < argsCount && i < arguments.Length; i++)
{
args[i] = DC.CastConvert(arguments[i], pi[i].ParameterType);
}
}
}
var rt = fi.Invoke(r, args);
if (rt is Task)
{
var t = (Task)rt;
//Console.WriteLine(t.IsCompleted);
await t;
#if NETSTANDARD1_5
var res = t.GetType().GetTypeInfo().GetProperty("Result").GetValue(t);
#else
var res = t.GetType().GetProperty("Result").GetValue(t);
#endif
SendParams((byte)0x90, callback, Codec.Compose(res, this));
}
else if (rt is AsyncReply) //(rt.GetType().IsGenericType && (rt.GetType().GetGenericTypeDefinition() == typeof(AsyncReply<>)))
{
(rt as AsyncReply).Then(res =>
{
SendParams((byte)0x90, callback, Codec.Compose(res, this));
});
}
else
{
SendParams((byte)0x90, callback, Codec.Compose(rt, this));
}
}
else
{
// ft found, fi not found, this should never happen
}
}
}
else
{
// no function at this index
}
});
}
else
{
// no resource with this id
}
});
}
void IIPRequestGetProperty(uint callback, uint resourceId, byte index)
{
Warehouse.Get(resourceId).Then((r) =>
{
if (r != null)
{
var pt = r.Instance.Template.GetFunctionTemplate(index);
if (pt != null)
{
if (r is DistributedResource)
{
SendParams((byte)0x91, callback, Codec.Compose((r as DistributedResource)._Get(pt.Index), this));
}
else
{
#if NETSTANDARD1_5
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
#endif
if (pi != null)
{
SendParams((byte)0x91, callback, Codec.Compose(pi.GetValue(r), this));
}
else
{
// pt found, pi not found, this should never happen
}
}
}
else
{
// pt not found
}
}
else
{
// resource not found
}
});
}
void IIPRequestGetPropertyIfModifiedSince(uint callback, uint resourceId, byte index, uint age)
{
Warehouse.Get(resourceId).Then((r) =>
{
if (r != null)
{
var pt = r.Instance.Template.GetFunctionTemplate(index);
if (pt != null)
{
if (r.Instance.GetAge(index) > age)
{
#if NETSTANDARD1_5
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
#endif
if (pi != null)
{
SendParams((byte)0x92, callback, Codec.Compose(pi.GetValue(r), this));
}
else
{
// pt found, pi not found, this should never happen
}
}
else
{
SendParams((byte)0x92, callback, (byte)DataType.NotModified);
}
}
else
{
// pt not found
}
}
else
{
// resource not found
}
});
}
void IIPRequestSetProperty(uint callback, uint resourceId, byte index, byte[] content)
{
Warehouse.Get(resourceId).Then((r) =>
{
if (r != null)
{
var pt = r.Instance.Template.GetPropertyTemplate(index);
if (pt != null)
{
Codec.Parse(content, 0, this).Then((value) =>
{
if (r is DistributedResource)
{
// propagation
(r as DistributedResource)._Set(index, value).Then((x) =>
{
SendParams((byte)0x93, callback);
});
}
else
{
#if NETSTANDARD1_5
var pi = r.GetType().GetTypeInfo().GetProperty(pt.Name);
#else
var pi = r.GetType().GetProperty(pt.Name);
#endif
if (pi != null)
{
// cast new value type to property type
var v = DC.CastConvert(value, pi.PropertyType);
pi.SetValue(r, v);
SendParams((byte)0x93, callback);
}
else
{
// pt found, pi not found, this should never happen
}
}
});
}
else
{
// property not found
}
}
else
{
// resource not found
}
});
}
/*
void IIPReplyAttachResource(uint callback, uint resourceAge, object[] properties)
{
if (requests.ContainsKey(callback))
{
var req = requests[callback];
var r = resources[(uint)req.Arguments[0]];
if (r == null)
{
r.Instance.Deserialize(properties);
r.Instance.Age = resourceAge;
r.Attached();
// process stack
foreach (var rr in resources.Values)
rr.Stack.ProcessStack();
}
else
{
// resource not found
}
}
}
void IIPReplyReattachResource(uint callback, uint resourceAge, object[] properties)
{
var req = requests.Take(callback);
if (req != null)
{
var r = resources[(uint)req.Arguments[0]];
if (r == null)
{
r.Instance.Deserialize(properties);
r.Instance.Age = resourceAge;
r.Attached();
// process stack
foreach (var rr in resources.Values)
rr.Stack.ProcessStack();
}
else
{
// resource not found
}
}
}
void IIPReplyDetachResource(uint callback)
{
var req = requests.Take(callback);
// nothing to do
}
void IIPReplyCreateResource(uint callback, Guid classId, uint resourceId)
{
var req = requests.Take(callback);
// nothing to do
}
void IIPReplyDeleteResource(uint callback)
{
var req = requests.Take(callback);
// nothing to do
}
void IIPReplyTemplateFromClassName(uint callback, ResourceTemplate template)
{
// cache
if (!templates.ContainsKey(template.ClassId))
templates.Add(template.ClassId, template);
var req = requests.Take(callback);
req?.Trigger(template);
}
void IIPReplyTemplateFromClassId(uint callback, ResourceTemplate template)
{
// cache
if (!templates.ContainsKey(template.ClassId))
templates.Add(template.ClassId, template);
var req = requests.Take(callback);
req?.Trigger(template);
}
void IIPReplyTemplateFromResourceLink(uint callback, ResourceTemplate template)
{
// cache
if (!templates.ContainsKey(template.ClassId))
templates.Add(template.ClassId, template);
var req = requests.Take(callback);
req?.Trigger(template);
}
void IIPReplyTemplateFromResourceId(uint callback, ResourceTemplate template)
{
// cache
if (!templates.ContainsKey(template.ClassId))
templates.Add(template.ClassId, template);
var req = requests.Take(callback);
req?.Trigger(template);
}
void IIPReplyResourceIdFromResourceLink(uint callback, Guid classId, uint resourceId, uint resourceAge)
{
var req = requests.Take(callback);
req?.Trigger(template);
}
void IIPReplyInvokeFunction(uint callback, object returnValue)
{
}
void IIPReplyGetProperty(uint callback, object value)
{
}
void IIPReplyGetPropertyIfModifiedSince(uint callback, object value)
{
}
void IIPReplySetProperty(uint callback)
{
}
*/
/// <summary>
/// Get the ResourceTemplate for a given class Id.
/// </summary>
/// <param name="classId">Class GUID.</param>
/// <returns>ResourceTemplate.</returns>
public AsyncReply<ResourceTemplate> GetTemplate(Guid classId)
{
if (templates.ContainsKey(classId))
return new AsyncReply<ResourceTemplate>(templates[classId]);
else if (templateRequests.ContainsKey(classId))
return templateRequests[classId];
var reply = new AsyncReply<ResourceTemplate>();
templateRequests.Add(classId, reply);
SendRequest(IIPPacket.IIPPacketAction.TemplateFromClassId, classId).Then((rt) =>
{
templateRequests.Remove(classId);
templates.Add(((ResourceTemplate)rt[0]).ClassId, (ResourceTemplate)rt[0]);
reply.Trigger(rt[0]);
});
return reply;
}
// IStore interface
/// <summary>
/// Get a resource by its path.
/// </summary>
/// <param name="path">Path to the resource.</param>
/// <returns>Resource</returns>
public AsyncReply<IResource> Get(string path)
{
if (pathRequests.ContainsKey(path))
return pathRequests[path];
var reply = new AsyncReply<IResource>();
pathRequests.Add(path, reply);
var bl = new BinaryList(path);
bl.Insert(0, (ushort)bl.Length);
SendRequest(IIPPacket.IIPPacketAction.ResourceIdFromResourceLink, bl.ToArray()).Then((rt) =>
{
pathRequests.Remove(path);
//(Guid)rt[0],
Fetch( (uint)rt[1]).Then((r) =>
{
reply.Trigger(r);
});
});
return reply;
}
/// <summary>
/// Retrive a resource by its instance Id.
/// </summary>
/// <param name="iid">Instance Id</param>
/// <returns>Resource</returns>
public AsyncReply<IResource> Retrieve(uint iid)
{
foreach (var r in resources.Values)
if (r.Instance.Id == iid)
return new AsyncReply<IResource>(r);
return new AsyncReply<IResource>(null);
}
/// <summary>
/// Fetch a resource from the other end
/// </summary>
/// <param name="classId">Class GUID</param>
/// <param name="id">Resource Id</param>Guid classId
/// <returns>DistributedResource</returns>
public AsyncReply<DistributedResource> Fetch( uint id)
{
if (resourceRequests.ContainsKey(id) && resources.ContainsKey(id))
{
// dig for dead locks
return resourceRequests[id];
}
else if (resourceRequests.ContainsKey(id))
return resourceRequests[id];
else if (resources.ContainsKey(id))
return new AsyncReply<DistributedResource>(resources[id]);
var reply = new AsyncReply<DistributedResource>();
SendRequest(IIPPacket.IIPPacketAction.AttachResource, id).Then((rt) =>
{
GetTemplate((Guid)rt[0]).Then((tmp) =>
{
// ClassId, ResourceAge, ResourceLink, Content
//var dr = Warehouse.New<DistributedResource>(id.ToString(), this);
//var dr = nInitialize(this, tmp, id, (uint)rt[0]);
var dr = new DistributedResource(this, tmp, id, (uint)rt[1], (string)rt[2]);
Warehouse.Put(dr, id.ToString(), this);
Codec.ParseVarArray((byte[])rt[3], this).Then((ar) =>
{
dr._Attached(ar);
resourceRequests.Remove(id);
reply.Trigger(dr);
});
});
});
return reply;
}
private void Instance_ResourceDestroyed(IResource resource)
{
// compose the packet
SendParams((byte)0x1, resource.Instance.Id);
}
private void Instance_PropertyModified(IResource resource, string name, object newValue, object oldValue)
{
var pt = resource.Instance.Template.GetPropertyTemplate(name);
if (pt == null)
return;
// compose the packet
if (newValue is Func<DistributedConnection, object>)
SendParams((byte)0x10, resource.Instance.Id, pt.Index, Codec.Compose((newValue as Func<DistributedConnection, object>)(this), this));
else
SendParams((byte)0x10, resource.Instance.Id, pt.Index, Codec.Compose(newValue, this));
}
private void Instance_EventOccured(IResource resource, string name, string[] receivers, object[] args)
{
var et = resource.Instance.Template.GetEventTemplate(name);
if (et == null)
return;
if (receivers != null)
if (!receivers.Contains(RemoteUsername))
return;
var clientArgs = new object[args.Length];
for (var i = 0; i < args.Length; i++)
if (args[i] is Func<DistributedConnection, object>)
clientArgs[i] = (args[i] as Func<DistributedConnection, object>)(this);
else
clientArgs[i] = args[i];
// compose the packet
SendParams((byte)0x11, resource.Instance.Id, (byte)et.Index, Codec.ComposeVarArray(args, this, true));
}
}
}

View File

@ -0,0 +1,374 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Collections;
using System.ComponentModel;
using Esiur.Misc;
using Esiur.Data;
using System.Dynamic;
using System.Security.Cryptography;
using Esiur.Engine;
using System.Runtime.CompilerServices;
using System.Reflection.Emit;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Esiur.Resource;
using Esiur.Resource.Template;
namespace Esiur.Net.IIP
{
//[System.Runtime.InteropServices.ComVisible(true)]
public class DistributedResource : DynamicObject, IResource
{
/// <summary>
/// Raised when the distributed resource is destroyed.
/// </summary>
public event DestroyedEvent OnDestroy;
uint instanceId;
DistributedConnection connection;
bool isAttached = false;
bool isReady = false;
//Structure properties = new Structure();
string link;
uint age;
uint[] ages;
object[] properties;
DistributedResourceEvent[] events;
ResourceTemplate template;
//DistributedResourceStack stack;
bool destroyed;
/// <summary>
/// Resource template for the remotely located resource.
/// </summary>
public ResourceTemplate Template
{
get { return template; }
}
/// <summary>
/// Connection responsible for the distributed resource.
/// </summary>
public DistributedConnection Connection
{
get { return connection; }
}
/// <summary>
/// Resource link
/// </summary>
public string Link
{
get { return link; }
}
/// <summary>
/// Instance Id given by the other end.
/// </summary>
public uint Id
{
get { return instanceId; }
}
/// <summary>
/// IDestructible interface.
/// </summary>
public void Destroy()
{
destroyed = true;
OnDestroy?.Invoke(this);
}
/// <summary>
/// Resource is ready when all its properties are attached.
/// </summary>
internal bool IsReady
{
get
{
return isReady;
}
}
/// <summary>
/// Resource is attached when all its properties are received.
/// </summary>
internal bool IsAttached
{
get
{
return isAttached;
}
}
// public DistributedResourceStack Stack
//{
// get { return stack; }
//}
/// <summary>
/// Create a new distributed resource.
/// </summary>
/// <param name="connection">Connection responsible for the distributed resource.</param>
/// <param name="template">Resource template.</param>
/// <param name="instanceId">Instance Id given by the other end.</param>
/// <param name="age">Resource age.</param>
public DistributedResource(DistributedConnection connection, ResourceTemplate template, uint instanceId, uint age, string link)
{
this.link = link;
this.connection = connection;
this.instanceId = instanceId;
this.template = template;
this.age = age;
}
internal void _Ready()
{
isReady = true;
}
internal bool _Attached(object[] properties)
{
if (isAttached)
return false;
else
{
this.properties = properties;
ages = new uint[properties.Length];
this.events = new DistributedResourceEvent[template.Events.Length];
isAttached = true;
}
return true;
}
internal void _EmitEventByIndex(byte index, object[] args)
{
var et = template.GetEventTemplate(index);
events[index]?.Invoke(this, args);
Instance.EmitResourceEvent(et.Name, null, args);
}
public AsyncReply _Invoke(byte index, object[] args)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
if (index >= template.Functions.Length)
throw new Exception("Function index is incorrect");
var reply = new AsyncReply();
var parameters = Codec.ComposeVarArray(args, connection, true);
connection.SendRequest(Packets.IIPPacket.IIPPacketAction.InvokeFunction, instanceId, index, parameters).Then((res) =>
{
Codec.Parse((byte[])res[0], 0, connection).Then((rt) =>
{
reply.Trigger(rt);
});
});
return reply;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var ft = template.GetFunctionTemplate(binder.Name);
var reply = new AsyncReply();
if (isAttached && ft!=null)
{
result = _Invoke(ft.Index, args);
return true;
}
else
{
result = null;
return false;
}
}
/// <summary>
/// Get a property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <returns>Value</returns>
internal object _Get(byte index)
{
if (index >= properties.Length)
return null;
return properties[index];
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
result = null;
if (!isAttached)
return false;
var pt = template.GetPropertyTemplate(binder.Name);
if (pt != null)
{
result = properties[pt.Index];
return true;
}
else
{
var et = template.GetEventTemplate(binder.Name);
if (et == null)
return false;
result = events[et.Index];
return true;
}
}
internal void UpdatePropertyByIndex(byte index, object value)
{
var pt = template.GetPropertyTemplate(index);
properties[index] = value;
Instance.Modified(pt.Name, value);
}
/// <summary>
/// Set property value.
/// </summary>
/// <param name="index">Zero-based property index.</param>
/// <param name="value">Value</param>
/// <returns>Indicator when the property is set.</returns>
internal AsyncReply _Set(byte index, object value)
{
if (index >= properties.Length)
return null;
var reply = new AsyncReply();
var parameters = Codec.Compose(value, connection);
connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty, instanceId, index, parameters).Then((res) =>
{
// not really needed, server will always send property modified, this only happens if the programmer forgot to emit in property setter
//Update(index, value);
reply.Trigger(null);
// nothing to do here
});
return reply;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (destroyed)
throw new Exception("Trying to access destroyed object");
if (!isAttached)
return false;
var pt = template.GetPropertyTemplate(binder.Name);
if (pt != null)
{
_Set(pt.Index, value);
return true;
}
else
{
var et = template.GetEventTemplate(binder.Name);
if (et == null)
return false;
events[et.Index] = (DistributedResourceEvent)value;
return true;
}
}
/*
public async void InvokeMethod(byte index, object[] arguments, DistributedConnection sender)
{
// get function parameters
Type t = this.GetType();
MethodInfo mi = t.GetMethod(GetFunctionName(index), BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance | BindingFlags.InvokeMethod);
if (mi != null)
{
try
{
var res = await invokeMethod(mi, arguments, sender);
object rt = Codec.Compose(res);
sender.SendParams((byte)0x80, instanceId, index, rt);
}
catch(Exception ex)
{
var msg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
sender.SendParams((byte)0x8E, instanceId, index, Codec.Compose(msg));
}
}
}
*/
/// <summary>
/// Resource interface.
/// </summary>
public Instance Instance
{
get;
set;
}
/// <summary>
/// Create a new instance of distributed resource.
/// </summary>
public DistributedResource()
{
//stack = new DistributedResourceStack(this);
}
/// <summary>
/// Resource interface.
/// </summary>
/// <param name="trigger"></param>
/// <returns></returns>
public AsyncReply<bool> Trigger(ResourceTrigger trigger)
{
// do nothing.
return new AsyncReply<bool>(true);
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.IIP
{
public delegate void DistributedResourceEvent(DistributedResource sender, params object[] arguments);
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.IIP
{
public class DistributedResourceQueueItem
{
public enum DistributedResourceQueueItemType
{
Propery,
Event
}
DistributedResourceQueueItemType type;
byte index;
object value;
DistributedResource resource;
public DistributedResourceQueueItem(DistributedResource resource, DistributedResourceQueueItemType type, object value, byte index)
{
this.resource = resource;
this.index = index;
this.type = type;
this.value = value;
}
public DistributedResource Resource
{
get { return resource; }
}
public DistributedResourceQueueItemType Type
{
get { return type; }
}
public byte Index
{
get { return index; }
}
public object Value
{
get { return value; }
}
}
}

View File

@ -0,0 +1,117 @@
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.Engine;
using System.Net;
using Esiur.Resource;
using Esiur.Security.Membership;
namespace Esiur.Net.IIP
{
public class DistributedServer : NetworkServer<DistributedConnection>, IResource
{
[Storable]
[ResourceProperty]
public string ip
{
get;
set;
}
[Storable]
[ResourceProperty]
public IMembership Membership
{
get;
set;
}
[Storable]
[ResourceProperty]
public ushort port
{
get;
set;
}
[Storable]
[ResourceProperty]
public uint timeout
{
get;
set;
}
[Storable]
[ResourceProperty]
public uint clock
{
get;
set;
}
public Instance Instance
{
get;
set;
}
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, timeout, clock);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
return new AsyncReply<bool>(true);
}
protected override void DataReceived(DistributedConnection sender, NetworkBuffer data)
{
//throw new NotImplementedException();
}
private void SessionModified(DistributedConnection Session, string Key, object NewValue)
{
}
protected override void ClientConnected(DistributedConnection sender)
{
Console.WriteLine("DistributedConnection Client Connected");
sender.Server = this;
}
protected override void ClientDisconnected(DistributedConnection sender)
{
Console.WriteLine("DistributedConnection Client Disconnected");
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using Esiur.Net.Sockets;
using Esiur.Security.Authority;
namespace Esiur.Net.IIP
{
public class DistributedSession : NetworkSession
{
Source Source { get; }
Authentication Authentication;
}
}

167
Esiur/Net/NetworkBuffer.cs Normal file
View File

@ -0,0 +1,167 @@
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;
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)
{
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)
{
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()
{
if (data.Length == 0)
return null;
byte[] rt = null;
if (neededDataLength == 0)
{
rt = data;
data = new byte[0];
}
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;
}
}
return rt;
}
}
}

View File

@ -0,0 +1,248 @@
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.Engine;
using Esiur.Data;
using Esiur.Net.Sockets;
using Esiur.Resource;
namespace Esiur.Net
{
public class NetworkConnection: IDestructible// <TS>: IResource where TS : NetworkSession
{
private 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 ConnectionEstablishedEvent(NetworkConnection sender);
public event ConnectionEstablishedEvent OnConnect;
public event DataReceivedEvent OnDataReceived;
public event ConnectionClosedEvent OnClose;
public event DestroyedEvent OnDestroy;
public void Destroy()
{
// if (connected)
Close();
OnDestroy?.Invoke(this);
}
public NetworkConnection()
{
}
public ISocket Socket
{
get
{
return sock;
}
}
public virtual void Assign(ISocket socket)
{
lastAction = DateTime.Now;
sock = socket;
//connected = true;
socket.OnReceive += Socket_OnReceive;
socket.OnClose += Socket_OnClose;
socket.OnConnect += Socket_OnConnect;
if (socket.State == SocketState.Established)
socket.Begin();
}
private void Socket_OnConnect()
{
OnConnect?.Invoke(this);
}
private void Socket_OnClose()
{
OnClose?.Invoke(this);
}
private void Socket_OnReceive(NetworkBuffer buffer)
{
try
{
// Unassigned ?
if (sock == null)
return;
// Closed ?
if (sock.State == SocketState.Closed || sock.State == SocketState.Terminated) // || !connected)
return;
lastAction = DateTime.Now;
while (buffer.Available > 0 && !buffer.Protected)
DataReceived(buffer);
}
catch (Exception ex)
{
Global.Log("NetworkConnection", LogType.Warning, ex.ToString());
}
}
public ISocket Unassign()
{
if (sock != null)
{
// connected = false;
sock.OnClose -= Socket_OnClose;
sock.OnConnect -= Socket_OnConnect;
sock.OnReceive -= Socket_OnReceive;
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 Connected
{
get
{
return sock.State == SocketState.Established;// connected;
}
}
/*
public void CloseAndWait()
{
try
{
if (!connected)
return;
if (sock != null)
sock.Close();
while (connected)
{
Thread.Sleep(100);
}
}
finally
{
}
}
*/
public virtual void Send(byte[] msg)
{
//Console.WriteLine("TXX " + msg.Length);
try
{
//if (!connected)
//{
//Console.WriteLine("not connected");
// return;
//}
if (sock != null)
{
lastAction = DateTime.Now;
sock.Send(msg);
}
}
catch
{
}
}
public virtual void Send(string data)
{
Send(Encoding.UTF8.GetBytes(data));
}
}
}

346
Esiur/Net/NetworkServer.cs Normal file
View File

@ -0,0 +1,346 @@
using System;
using System.Threading;
using System.Collections.Generic;
using Esiur.Data;
using Esiur.Misc;
using Esiur.Engine;
using Esiur.Net.Sockets;
using Esiur.Resource;
using System.Threading.Tasks;
namespace Esiur.Net
{
//public abstract class NetworkServer<TConnection, TSession> : IResource where TSession : NetworkSession, new() where TConnection : NetworkConnection<TSession>, new()
public abstract class NetworkServer<TConnection>: IDestructible where TConnection : NetworkConnection, new()
{
//private bool isRunning;
uint clock;
private ISocket listener;
private AutoList<TConnection, NetworkServer<TConnection>> connections;
//private Thread thread;
protected abstract void DataReceived(TConnection sender, NetworkBuffer data);
protected abstract void ClientConnected(TConnection sender);
protected abstract void ClientDisconnected(TConnection sender);
// private int port;
// private IPAddress ip = null;
private uint timeout;
private Timer timer;
//public KeyList<string, TSession> Sessions = new KeyList<string, TSession>();
public event DestroyedEvent OnDestroy;
public AutoList<TConnection, NetworkServer<TConnection>> Connections
{
get
{
return connections;
}
}
/*
public void RemoveSession(string ID)
{
Sessions.Remove(ID);
}
public void RemoveSession(TSession Session)
{
if (Session != null)
Sessions.Remove(Session.Id);
}
*/
/*
public TSession CreateSession(string ID, int Timeout)
{
TSession s = new TSession();
s.SetSession(ID, Timeout, new NetworkSession.SessionModifiedEvent(SessionModified)
, new NetworkSession.SessionEndedEvent(SessionEnded));
Sessions.Add(ID, s);
return s;
}
*/
/*
private void pSessionModified(TSession session, string key, object oldValue, object newValue)
{
SessionModified((TSession)session, key, oldValue, newValue);
}
private void pSessionEnded(NetworkSession session)
{
SessionEnded((TSession)session);
}
*/
/*
protected virtual void SessionModified(NetworkSession session, string key, object oldValue, object newValue)
{
}
protected virtual void SessionEnded(NetworkSession session)
{
Sessions.Remove(session.Id);
session.Destroy();
}
*/
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);
}
}
}
//Console.WriteLine("UnLock MinuteThread");
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(ISocket socket, uint timeout, uint clock)
{
if (listener != null)
return;
//if (socket.State == SocketState.Listening)
// return;
//if (isRunning)
// return;
connections = new AutoList<TConnection, NetworkServer<TConnection>>(this);
if (timeout > 0 & clock > 0)
{
timer = new Timer(MinuteThread, null, TimeSpan.FromMinutes(0), TimeSpan.FromSeconds(clock));
this.timeout = timeout;
}
//this.ip = ip;
//this.port = port;
this.clock = clock;
// start a new thread for the server to live on
//isRunning = true;
listener = socket;
// Start accepting
listener.Accept().Then(NewConnection);
//var rt = listener.Accept().Then()
//thread = new Thread(new System.Threading.ThreadStart(ListenForConnections));
//thread.Start();
}
/*
public int LocalPort
{
get
{
return port;
}
}
*/
public uint Clock
{
get { return clock; }
}
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
{
Console.WriteLine("Server@{0} is down", port);
}
}
private void NewConnection(ISocket sock)
{
try
{
/*
if (listener.State == SocketState.Closed || listener.State == SocketState.Terminated)
{
Console.WriteLine("Listen socket break ");
Console.WriteLine(listener.LocalEndPoint.Port);
break;
}
*/
if (sock == null)
{
Console.Write("sock == null");
return;
}
//sock.ReceiveBufferSize = 102400;
//sock.SendBufferSize = 102400;
TConnection c = new TConnection();
c.OnDataReceived += OnDataReceived;
c.OnConnect += OnClientConnect;
c.OnClose += OnClientClose;
connections.Add(c);
c.Assign(sock);
ClientConnected(c);
// Accept more
listener.Accept().Then(NewConnection);
}
catch (Exception ex)
{
Console.WriteLine("TSERVER " + ex.ToString());
Global.Log("TServer", LogType.Error, ex.ToString());
}
//isRunning = false;
}
public bool IsRunning
{
get
{
return listener.State == SocketState.Listening;
//isRunning;
}
}
public void OnDataReceived(NetworkConnection sender, NetworkBuffer data)
{
DataReceived((TConnection)sender, data);
}
public void OnClientConnect(NetworkConnection 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(NetworkConnection sender)
{
try
{
sender.Destroy();
ClientDisconnected((TConnection)sender);
}
catch (Exception ex)
{
Global.Log("NetworkServer:OnClientDisconnect", LogType.Error, ex.ToString());
}
sender = null;
GC.Collect();
}
public void Destroy()
{
Stop();
OnDestroy?.Invoke(this);
}
~NetworkServer()
{
Stop();
//Connections = null;
listener = null;
}
}
}

106
Esiur/Net/NetworkSession.cs Normal file
View File

@ -0,0 +1,106 @@
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.Engine;
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)
{
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,287 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Misc;
using Esiur.Data;
using System.Net;
namespace Esiur.Net.Packets
{
public class HTTPRequestPacket : Packet
{
public enum HTTPMethod:byte
{
GET,
POST,
HEAD,
PUT,
DELETE,
OPTIONS,
TRACE,
CONNECT,
UNKNOWN
}
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 byte[] PostContents;
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].Substring(0, 7) == "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((string)Headers["content-length"]);
// check limit
if (postSize > data.Length - headerSize)
return postSize - (data.Length - headerSize);
if (Headers["content-type"] == "application/x-www-form-urlencoded"
|| Headers["content-type"] == ""
|| Headers["content-type"] == null)
{
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
{
//PostForms.Add(Headers["content-type"], Encoding.Default.GetString( ));
Message = DC.Clip(data, headerSize, postSize);
}
return headerSize + postSize;
}
catch
{
return 0;
}
}
return headerSize;
}
}
}

View File

@ -0,0 +1,284 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.Packets
{
public class HTTPResponsePacket : Packet
{
public enum ComposeOptions : int
{
AllCalculateLength,
AllDontCalculateLength,
SpecifiedHeadersOnly,
DataOnly
}
public enum ResponseCode : int
{
HTTP_SWITCHING = 101,
HTTP_OK = 200,
HTTP_NOTFOUND = 404,
HTTP_SERVERERROR = 500,
HTTP_MOVED = 301,
HTTP_NOTMODIFIED = 304,
HTTP_REDIRECT = 307
}
public class 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)
{
this.Name = Name;
this.Value = Value;
}
public HTTPCookie(string Name, string Value, DateTime Expires)
{
this.Name = Name;
this.Value = Value;
this.Expires = Expires;
}
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=/
string 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;
}
}
public StringKeyList Headers = new StringKeyList(true);
public string Version = "HTTP/1.1";
public byte[] Message;
public ResponseCode Number;
public string Text;
//public DStringDictionary Cookies;
public List<HTTPCookie> Cookies = new List<HTTPCookie>();
public bool Handled;
//public bool ResponseHandled; //flag this as true if you are handling it yourself
//private bool createSession;
//private HTTPServer Server;
//public HTTPSession Session;
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(ComposeOptions Options)
{
string header = Version + " " + (int)Number + " " + Text + "\r\n"
+ "Server: Delta Web Server\r\n"
//Fri, 30 Oct 2007 14:19:41 GMT"
+ "Date: " + DateTime.Now.ToUniversalTime().ToString("r") + "\r\n";
if (Options == ComposeOptions.AllCalculateLength && Message != null)
{
Headers["Content-Length"] = Message.Length.ToString();
}
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(ComposeOptions options)
{
List<byte> msg = new List<byte>();
if (options != ComposeOptions.DataOnly)
{
msg.AddRange(Encoding.UTF8.GetBytes(MakeHeader(options)));
}
if (options != ComposeOptions.SpecifiedHeadersOnly)
{
if (Message != null)
msg.AddRange(Message);
}
Data = msg.ToArray();
return true;
}
public override bool Compose()
{
return Compose(ComposeOptions.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;
//Cookies = new DStringDictionary();
//Headers = new DStringDictionary(true);
sMethod = sLines[0].Split(' ');
if (sMethod.Length == 3)
{
Version = sMethod[0].Trim();
Number = (ResponseCode)(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((string)Headers["content-length"]);
// check limit
if (contentLength > data.Length - headerSize)
{
return contentLength - (data.Length - headerSize);
}
Message = DC.Clip(data, offset, contentLength);
return headerSize + contentLength;
}
catch
{
return 0;
}
}
}
}

View File

@ -0,0 +1,382 @@
 using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Packets
{
class IIPAuthPacket : Packet
{
public enum IIPAuthPacketCommand: byte
{
Action = 0,
Declare,
Acknowledge,
Error,
}
public enum IIPAuthPacketAction: byte
{
// Authenticate
AuthenticateHash,
//Challenge,
//CertificateRequest,
//CertificateReply,
//EstablishRequest,
//EstablishReply
NewConnection = 0x20,
ResumeConnection,
ConnectionEstablished = 0x28
}
public enum IIPAuthPacketMethod: byte
{
None,
Certificate,
Credentials,
Token
}
public IIPAuthPacketCommand Command
{
get;
set;
}
public IIPAuthPacketAction Action
{
get;
set;
}
public byte ErrorCode { get; set; }
public string ErrorMessage { get; set; }
public IIPAuthPacketMethod LocalMethod
{
get;
set;
}
public byte[] SourceInfo
{
get;
set;
}
public byte[] Hash
{
get;
set;
}
public byte[] SessionId
{
get;
set;
}
public IIPAuthPacketMethod RemoteMethod
{
get;
set;
}
public string Domain
{
get;
set;
}
public long CertificateId
{
get;set;
}
public string LocalUsername
{
get;
set;
}
public string RemoteUsername
{
get;
set;
}
public byte[] LocalPassword
{
get;
set;
}
public byte[] RemotePassword
{
get;
set;
}
public byte[] LocalToken
{
get;
set;
}
public byte[] RemoteToken
{
get;
set;
}
public byte[] AsymetricEncryptionKey
{
get;
set;
}
public byte[] LocalNonce
{
get;
set;
}
public byte[] RemoteNonce
{
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 = (IIPAuthPacketCommand)(data[offset] >> 6);
if (Command == IIPAuthPacketCommand.Action)
{
Action = (IIPAuthPacketAction)(data[offset++] & 0x3f);
if (Action == IIPAuthPacketAction.AuthenticateHash)
{
if (NotEnough(offset, ends, 32))
return -dataLengthNeeded;
Hash = data.Clip(offset, 32);
//var hash = new byte[32];
//Buffer.BlockCopy(data, (int)offset, hash, 0, 32);
//Hash = hash;
offset += 32;
}
else if (Action == IIPAuthPacketAction.NewConnection)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var length = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, length))
return -dataLengthNeeded;
SourceInfo = data.Clip(offset, length);
//var sourceInfo = new byte[length];
//Buffer.BlockCopy(data, (int)offset, sourceInfo, 0, length);
//SourceInfo = sourceInfo;
offset += 32;
}
else if (Action == IIPAuthPacketAction.ResumeConnection
|| Action == IIPAuthPacketAction.ConnectionEstablished)
{
//var sessionId = new byte[32];
if (NotEnough(offset, ends, 32))
return -dataLengthNeeded;
SessionId = data.Clip(offset, 32);
//Buffer.BlockCopy(data, (int)offset, sessionId, 0, 32);
//SessionId = sessionId;
offset += 32;
}
}
else if (Command == IIPAuthPacketCommand.Declare)
{
RemoteMethod = (IIPAuthPacketMethod)((data[offset] >> 4) & 0x3);
LocalMethod = (IIPAuthPacketMethod)((data[offset] >> 2) & 0x3);
var encrypt = ((data[offset++] & 0x2) == 0x2);
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var domainLength = data[offset++];
if (NotEnough(offset, ends, domainLength))
return -dataLengthNeeded;
var domain = data.GetString(offset, domainLength);
Domain = domain;
offset += domainLength;
if (RemoteMethod == IIPAuthPacketMethod.Credentials)
{
if (LocalMethod == IIPAuthPacketMethod.None)
{
if (NotEnough(offset, ends, 33))
return -dataLengthNeeded;
//var remoteNonce = new byte[32];
//Buffer.BlockCopy(data, (int)offset, remoteNonce, 0, 32);
//RemoteNonce = remoteNonce;
RemoteNonce = data.Clip(offset, 32);
offset += 32;
var length = data[offset++];
if (NotEnough(offset, ends, length))
return -dataLengthNeeded;
RemoteUsername = data.GetString(offset, length);
offset += length;
}
}
if (encrypt)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var keyLength = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, keyLength))
return -dataLengthNeeded;
//var key = new byte[keyLength];
//Buffer.BlockCopy(data, (int)offset, key, 0, keyLength);
//AsymetricEncryptionKey = key;
AsymetricEncryptionKey = data.Clip(offset, keyLength);
offset += keyLength;
}
}
else if (Command == IIPAuthPacketCommand.Acknowledge)
{
RemoteMethod = (IIPAuthPacketMethod)((data[offset] >> 4) & 0x3);
LocalMethod = (IIPAuthPacketMethod)((data[offset] >> 2) & 0x3);
var encrypt = ((data[offset++] & 0x2) == 0x2);
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
if (RemoteMethod == IIPAuthPacketMethod.Credentials)
{
if (LocalMethod == IIPAuthPacketMethod.None)
{
if (NotEnough(offset, ends, 32))
return -dataLengthNeeded;
/*
var remoteNonce = new byte[32];
Buffer.BlockCopy(data, (int)offset, remoteNonce, 0, 32);
RemoteNonce = remoteNonce;
*/
RemoteNonce = data.Clip(offset, 32);
offset += 32;
}
}
if (encrypt)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var keyLength = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, keyLength))
return -dataLengthNeeded;
//var key = new byte[keyLength];
//Buffer.BlockCopy(data, (int)offset, key, 0, keyLength);
//AsymetricEncryptionKey = key;
AsymetricEncryptionKey = data.Clip(offset, keyLength);
offset += keyLength;
}
}
else if (Command == IIPAuthPacketCommand.Error)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
offset++;
ErrorCode = data[offset++];
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ErrorMessage = data.GetString(offset, cl);
offset += cl;
}
return offset - oOffset;
}
}
}

View File

@ -0,0 +1,550 @@
 using Esiur.Data;
using Esiur.Engine;
using Esiur.Misc;
using Esiur.Net.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Esiur.Net.Packets
{
class IIPPacket : Packet
{
public enum IIPPacketCommand : byte
{
Event = 0,
Request,
Reply,
Error,
}
public enum IIPPacketEvent: byte
{
// Event Manage
ResourceReassigned = 0,
ResourceDestroyed,
// Event Invoke
PropertyUpdated = 0x10,
EventOccured,
}
public enum IIPPacketAction : byte
{
// Request Manage
AttachResource = 0,
ReattachResource,
DetachResource,
CreateResource,
DeleteResource,
// Request Inquire
TemplateFromClassName = 0x8,
TemplateFromClassId,
TemplateFromResourceLink,
TemplateFromResourceId,
ResourceIdFromResourceLink,
// Request Invoke
InvokeFunction = 0x10,
GetProperty,
GetPropertyIfModified,
SetProperty,
}
public IIPPacketCommand Command
{
get;
set;
}
public IIPPacketAction Action
{
get;
set;
}
public IIPPacketEvent Event
{
get;
set;
}
public uint ResourceId { get; set; }
public uint NewResourceId { get; set; }
public uint ResourceAge { get; set; }
public byte[] Content { get; set; }
public byte ErrorCode { get; set; }
public string ErrorMessage { get; set; }
public string ClassName { get; set; }
public string ResourceLink { get; set; }
public Guid ClassId { get; set; }
public byte MethodIndex { get; set; }
public string MethodName { get; set; }
public uint CallbackId { get; set; }
private uint dataLengthNeeded;
public override bool Compose()
{
return base.Compose();
}
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)
{
var oOffset = offset;
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
Command = (IIPPacketCommand)(data[offset] >> 6);
if (Command == IIPPacketCommand.Event)
{
Event = (IIPPacketEvent)(data[offset++] & 0x3f);
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else
{
Action = (IIPPacketAction)(data[offset++] & 0x3f);
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
CallbackId = data.GetUInt32(offset);
offset += 4;
}
if (Command == IIPPacketCommand.Event)
{
if (Event == IIPPacketEvent.ResourceReassigned)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
NewResourceId = data.GetUInt32( offset);
offset += 4;
}
else if (Event == IIPPacketEvent.ResourceDestroyed)
{
// nothing to parse
}
else if (Event == IIPPacketEvent.PropertyUpdated)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
MethodIndex = data[offset++];
var dt = (DataType)data[offset++];
var size = dt.Size();// Codec.SizeOf(dt);
if (size < 0)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32( offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip( offset - 5, cl + 5);
offset += cl;
}
else
{
if (NotEnough(offset, ends, (uint)size))
return -dataLengthNeeded;
Content = data.Clip(offset - 1, (uint)size + 1);
offset += (uint)size;
}
}
else if (Event == IIPPacketEvent.EventOccured)
{
if (NotEnough(offset, ends, 5))
return -dataLengthNeeded;
MethodIndex = data[offset++];
var cl = data.GetUInt32( offset);
offset += 4;
Content = data.Clip( offset, cl);
offset += cl;
}
}
else if (Command == IIPPacketCommand.Request)
{
if (Action == IIPPacketAction.AttachResource)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.ReattachResource)
{
if (NotEnough(offset, ends, 8))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
ResourceAge = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.DetachResource)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.CreateResource)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var cl = data[offset++];
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ClassName = data.GetString(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.DeleteResource)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.TemplateFromClassName)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var cl = data[offset++];
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ClassName = data.GetString(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.TemplateFromClassId)
{
if (NotEnough(offset, ends, 16))
return -dataLengthNeeded;
ClassId = data.GetGuid(offset);
offset += 16;
}
else if (Action == IIPPacketAction.TemplateFromResourceLink)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ResourceLink = data.GetString(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.TemplateFromResourceId)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.ResourceIdFromResourceLink)
{
if (NotEnough(offset, ends, 2))
return -dataLengthNeeded;
var cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ResourceLink = data.GetString(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.InvokeFunction)
{
if (NotEnough(offset, ends, 9))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.GetProperty)
{
if (NotEnough(offset, ends, 5))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
}
else if (Action == IIPPacketAction.GetPropertyIfModified)
{
if (NotEnough(offset, ends, 9))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
ResourceAge = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.SetProperty)
{
if (NotEnough(offset, ends, 6))
return -dataLengthNeeded;
ResourceId = data.GetUInt32(offset);
offset += 4;
MethodIndex = data[offset++];
var dt = (DataType)data[offset++];
var size = dt.Size();// Codec.SizeOf(dt);
if (size < 0)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset-5, cl + 5);
offset += cl;
}
else
{
if (NotEnough(offset, ends, (uint)size))
return -dataLengthNeeded;
Content = data.Clip(offset-1, (uint)size + 1);
offset += (uint)size;
}
}
}
else if (Command == IIPPacketCommand.Reply)
{
if (Action == IIPPacketAction.AttachResource
|| Action == IIPPacketAction.ReattachResource)
{
if (NotEnough(offset, ends, 26))
return -dataLengthNeeded;
ClassId = data.GetGuid(offset);
offset += 16;
ResourceAge = data.GetUInt32(offset);
offset += 4;
uint cl = data.GetUInt16(offset);
offset += 2;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ResourceLink = data.GetString(offset, cl);
offset += cl;
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.DetachResource)
{
// nothing to do
}
else if (Action == IIPPacketAction.CreateResource)
{
if (NotEnough(offset, ends, 20))
return -dataLengthNeeded;
ClassId = data.GetGuid(offset);
offset += 16;
ResourceId = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.DetachResource)
{
// nothing to do
}
else if (Action == IIPPacketAction.TemplateFromClassName
|| Action == IIPPacketAction.TemplateFromClassId
|| Action == IIPPacketAction.TemplateFromResourceLink
|| Action == IIPPacketAction.TemplateFromResourceId)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset, cl);
offset += cl;
}
else if (Action == IIPPacketAction.ResourceIdFromResourceLink)
{
if (NotEnough(offset, ends, 24))
return -dataLengthNeeded;
ClassId = data.GetGuid(offset);
offset += 16;
ResourceId = data.GetUInt32(offset);
offset += 4;
ResourceAge = data.GetUInt32(offset);
offset += 4;
}
else if (Action == IIPPacketAction.InvokeFunction
|| Action == IIPPacketAction.GetProperty
|| Action == IIPPacketAction.GetPropertyIfModified)
{
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
var dt = (DataType)data[offset++];
var size = dt.Size();// Codec.SizeOf(dt);
if (size < 0)
{
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
Content = data.Clip(offset - 5, cl + 5);
offset += cl;
}
else
{
if (NotEnough(offset, ends, (uint)size))
return -dataLengthNeeded;
Content = data.Clip(offset - 1, (uint)size + 1);
offset += (uint)size;
}
}
else if (Action == IIPPacketAction.SetProperty)
{
// nothing to do
}
}
else if (Command == IIPPacketCommand.Error)
{
// Error
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
CallbackId = data.GetUInt32(offset);
if (NotEnough(offset, ends, 1))
return -dataLengthNeeded;
ErrorCode = data[offset++];
if (NotEnough(offset, ends, 4))
return -dataLengthNeeded;
var cl = data.GetUInt32(offset);
offset += 4;
if (NotEnough(offset, ends, cl))
return -dataLengthNeeded;
ErrorMessage = data.GetString(offset, cl);
offset += cl;
}
return offset - oOffset;
}
}
}

367
Esiur/Net/Packets/Packet.cs Normal file
View File

@ -0,0 +1,367 @@
/******************************************************************************\
* Uruky Sniffer Project *
* *
* Copyright (C) 2006 Ahmed Khalaf - ahmed@uruky.com *
* ahmed_baghdad@yahoo.com *
* http://www.uruky.com *
* http://www.dijlh.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* 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,188 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Esiur.Misc;
using Esiur.Data;
namespace Esiur.Net.Packets
{
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 > UInt16.MaxValue)
// 4 bytes
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127));
pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount()));
}
else if (Message.Length > 125)
// 2 bytes
{
pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126));
pkt.AddRange(DC.ToBytes((UInt16)Message.Length));
}
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 = (long)(data[offset++] & 0x7F);
if (Mask)
needed += 4;
if (PayloadLength == 126)
{
needed += 2;
if (length < needed)
{
//Console.WriteLine("stage 2 " + needed);
return length - needed;
}
PayloadLength = DC.GetUInt16(data, offset);
offset += 2;
}
else if (PayloadLength == 127)
{
needed += 8;
if (length < needed)
{
//Console.WriteLine("stage 3 " + needed);
return length - needed;
}
PayloadLength = DC.GetInt64(data, offset);
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;
}
// if ((int)PayloadLength > (ends - offset))
// {
// return -((int)PayloadLength - (ends - offset));
// }
else
{
Message = DC.Clip(data, offset, (uint)PayloadLength);
if (Mask)
{
//var aMask = BitConverter.GetBytes(MaskKey);
for (int i = 0; i < Message.Length; i++)
{
Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]);
}
}
return (offset - oOffset) + (int)PayloadLength;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine(offset + "::" + DC.ToHex(data));
throw ex;
}
}
}
}

View File

@ -0,0 +1,39 @@
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.Engine;
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;
void Send(byte[] message);
void Send(byte[] message, int offset, int size);
void Close();
bool Connect(string hostname, ushort port);
bool Begin();
//ISocket Accept();
AsyncReply<ISocket> Accept();
IPEndPoint RemoteEndPoint { get; }
IPEndPoint LocalEndPoint { get; }
}
}

View File

@ -0,0 +1,310 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Misc;
using Esiur.Engine;
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
{
Socket sock;
byte[] receiveBuffer;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
object sendLock = new object();
Queue<byte[]> sendBufferQueue = new Queue<byte[]>();
bool asyncSending;
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;
private void Connected(Task t)
{
if (server)
{
ssl.AuthenticateAsServerAsync(cert).ContinueWith(Authenticated);
}
else
{
ssl.AuthenticateAsClientAsync(hostname).ContinueWith(Authenticated);
}
}
public bool Connect(string hostname, ushort port)
{
try
{
this.hostname = hostname;
server = false;
state = SocketState.Connecting;
sock.ConnectAsync(hostname, port).ContinueWith(Connected);
return true;
}
catch
{
return false;
}
}
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());
}
}
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;
}
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;
}
}
sock.Shutdown(SocketShutdown.Both);
OnClose?.Invoke();
}
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);
}
}
}
void Authenticated(Task task)
{
try
{
state = SocketState.Established;
OnConnect?.Invoke();
if (!server)
Begin();
}
catch (Exception ex)
{
state = SocketState.Terminated;
Close();
Global.Log(ex);
}
}
private void DataReceived(Task<int> task)
{
try
{
// SocketError err;
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 (state == SocketState.Established)
{
ssl.ReadAsync(receiveBuffer, 0, receiveBuffer.Length).ContinueWith(DataReceived);
return true;
}
else
return false;
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
OnDestroy?.Invoke(this);
}
public AsyncReply<ISocket> Accept()
{
var reply = new AsyncReply<ISocket>();
try
{
sock.AcceptAsync().ContinueWith((x) =>
{
try
{
reply.Trigger(new SSLSocket(x.Result, cert, true));
}
catch
{
reply.Trigger(null);
}
}, null);
}
catch
{
state = SocketState.Terminated;
return null;
}
return reply;
}
}
}

View File

@ -0,0 +1,18 @@
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,
Terminated
}
}

View File

@ -0,0 +1,291 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Misc;
using Esiur.Engine;
using System.Threading;
using Esiur.Resource;
using System.Threading.Tasks;
using Esiur.Data;
namespace Esiur.Net.Sockets
{
public class TCPSocket : ISocket
{
Socket sock;
byte[] receiveBuffer;
ArraySegment<byte> receiveBufferSegment;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
object sendLock = new object();
Queue<byte[]> sendBufferQueue = new Queue<byte[]>();
bool asyncSending;
SocketState state = SocketState.Initial;
public event ISocketReceiveEvent OnReceive;
public event ISocketConnectEvent OnConnect;
public event ISocketCloseEvent OnClose;
public event DestroyedEvent OnDestroy;
private void Connected(Task t)
{
state = SocketState.Established;
OnConnect?.Invoke();
Begin();
}
public bool Begin()
{
sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived);
return true;
}
public bool Connect(string hostname, ushort port)
{
try
{
state = SocketState.Connecting;
sock.ConnectAsync(hostname, port).ContinueWith(Connected);
return true;
}
catch
{
return false;
}
}
private void DataReceived(Task<int> task)
{
try
{
// SocketError err;
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)
sock.ReceiveAsync(receiveBufferSegment, SocketFlags.None).ContinueWith(DataReceived);
}
catch (Exception ex)
{
if (state != SocketState.Closed && !sock.Connected)
{
state = SocketState.Terminated;
Close();
}
Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
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);
}
private void DataSent(Task<int> task)
{
try
{
if (sendBufferQueue.Count > 0)
{
byte[] data = sendBufferQueue.Dequeue();
lock (sendLock)
sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None).ContinueWith(DataSent);
}
else
{
asyncSending = false;
}
}
catch (Exception ex)
{
if (state != SocketState.Closed && !sock.Connected)
{
state = SocketState.Terminated;
Close();
}
asyncSending = false;
Global.Log("TCPSocket", LogType.Error, ex.ToString());
}
}
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 && state != SocketState.Terminated)
state = SocketState.Closed;
if (sock.Connected)
{
try
{
sock.Shutdown(SocketShutdown.Both);
}
catch
{
state = SocketState.Terminated;
}
sock.Shutdown(SocketShutdown.Both);// Close();
OnClose?.Invoke();
}
}
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;
sock.SendAsync(new ArraySegment<byte>(message, offset, size), SocketFlags.None).ContinueWith(DataSent);
}
}
}
public bool Trigger(ResourceTrigger trigger)
{
return true;
}
public void Destroy()
{
Close();
OnDestroy?.Invoke(this);
}
public AsyncReply<ISocket> Accept()
{
var reply = new AsyncReply<ISocket>();
try
{
sock.AcceptAsync().ContinueWith((x) =>
{
try
{
reply.Trigger(new TCPSocket(x.Result));
}
catch
{
reply.Trigger(null);
}
});
}
catch
{
state = SocketState.Terminated;
return null;
}
return reply;
}
}
}

View File

@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Esiur.Net.Packets;
using Esiur.Misc;
using System.IO;
using Esiur.Engine;
using Esiur.Resource;
namespace Esiur.Net.Sockets
{
public class WSSocket : ISocket
{
WebsocketPacket pkt_receive = new WebsocketPacket();
WebsocketPacket pkt_send = new WebsocketPacket();
ISocket sock;
NetworkBuffer receiveNetworkBuffer = new NetworkBuffer();
object sendLock = new object();
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 WSSocket(ISocket socket)
{
pkt_send.FIN = true;
pkt_send.Mask = false;
pkt_send.Opcode = WebsocketPacket.WSOpcode.BinaryFrame;
sock = socket;
sock.OnClose += Sock_OnClose;
sock.OnConnect += Sock_OnConnect;
sock.OnReceive += Sock_OnReceive;
}
private void Sock_OnReceive(NetworkBuffer buffer)
{
if (sock.State == SocketState.Closed || sock.State == SocketState.Terminated)
return;
if (buffer.Protected)
return;
var msg = buffer.Read();
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();
pkt_pong.FIN = true;
pkt_pong.Mask = false;
pkt_pong.Opcode = WebsocketPacket.WSOpcode.Pong;
pkt_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;
}
else
Console.WriteLine("Unknown WS opcode:" + pkt_receive.Opcode);
if (offset == msg.Length)
{
OnReceive?.Invoke(receiveNetworkBuffer);
return;
}
wsPacketLength = pkt_receive.Parse(msg, offset, (uint)msg.Length);
}
if (wsPacketLength < 0)//(offset < msg.Length) && (offset > 0))
{
//receiveNetworkBuffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)msg.Length + (uint)-wsPacketLength);
// save the incomplete packet to the heldBuffer queue
receiveNetworkBuffer.HoldFor(msg, offset, (uint)(msg.Length - offset), (uint)(msg.Length - offset) + (uint)-wsPacketLength);
}
OnReceive?.Invoke(receiveNetworkBuffer);
}
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)
{
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)
{
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 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();
OnDestroy?.Invoke(this);
}
public AsyncReply<ISocket> Accept()
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,27 @@
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 KeyList<string, object> Variables
{
get
{
return variables;
}
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Esiur.Data;
using Esiur.Net.Sockets;
using Esiur.Engine;
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()
{
throw new NotImplementedException();
}
}
}

195
Esiur/Net/TCP/TCPServer.cs Normal file
View File

@ -0,0 +1,195 @@
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.Engine;
using System.Net;
using Esiur.Resource;
namespace Esiur.Net.TCP
{
public class TCPServer : NetworkServer<TCPConnection>, IResource
{
[Storable]
string ip
{
get;
set;
}
[Storable]
ushort port
{
get;
set;
}
[Storable]
uint timeout
{
get;
set;
}
[Storable]
uint clock
{
get;
set;
}
public Instance Instance { get; set; }
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, timeout, clock);
}
else if (trigger == ResourceTrigger.Terminate)
{
Stop();
}
else if (trigger == ResourceTrigger.SystemReload)
{
Trigger(ResourceTrigger.Terminate);
Trigger(ResourceTrigger.Initialize);
}
return new AsyncReply<bool>(true);
}
protected override void DataReceived(TCPConnection sender, NetworkBuffer data)
{
//throw new NotImplementedException();
var msg = data.Read();
foreach (Instance instance in Instance.Children)
{
var f = instance.Resource as TCPFilter;
if (f.Execute(msg, data, sender))
return;
}
}
private void SessionModified(TCPConnection Session, string Key, object NewValue)
{
}
/*
public TCPServer(string IP, int Port, int Timeout, int Clock)
: base(IP, Port, Timeout, Clock)
{
if (Timeout > 0 && Clock > 0)
{
mTimer = new Timer(OnlineThread, null, 0, Clock * 1000);// TimeSpan.FromSeconds(Clock));
mTimeout = Timeout;
}
}
*/
/*
private void OnlineThread(object state)
{
List<TCPConnection> ToBeClosed = null;
//Console.WriteLine("Minute Thread");
if (Connections.Count > 0)
{
Global.Log("TCPServer:OnlineThread", LogType.Debug,
//"Tick:" + DateTime.Now.Subtract(Connections[0].LastAction).TotalSeconds + ":" + mTimeout + ":" +
"Tick | Connections: " + Connections.Count + " Threads:" + System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
}
try
{
foreach (TCPConnection c in Connections)//.Values)
{
if (DateTime.Now.Subtract(c.LastAction).TotalSeconds >= mTimeout)
{
if (ToBeClosed == null)
ToBeClosed = new List<TCPConnection>();
ToBeClosed.Add(c);
}
}
if (ToBeClosed != null)
{
Global.Log("TCPServer:OnlineThread", LogType.Debug, "Inactive Closed:" + ToBeClosed.Count);
foreach (TCPConnection c in ToBeClosed)
c.Close();
ToBeClosed.Clear();
ToBeClosed = null;
}
}
catch (Exception ex)
{
Global.Log("TCPServer:OnlineThread", LogType.Debug, ex.ToString());
}
}
*/
//~TCPServer()
//{
// StopServer();
//}
protected override void ClientConnected(TCPConnection sender)
{
//Console.WriteLine("TCP Client Connected");
// Global.Log("TCPServer",
// LogType.Debug,
// "Connected:" + Connections.Count
// + ":" + sender.RemoteEndPoint.ToString());
foreach (Instance instance in Instance.Children)
{
var f = instance.Resource as TCPFilter;
f.Connected(sender);
}
}
protected override void ClientDisconnected(TCPConnection sender)
{
//Console.WriteLine("TCP Client Disconnected");
// Global.Log("TCPServer", LogType.Debug, "Disconnected:" + Connections.Count);// + ":" + sender.RemoteEndPoint.ToString());
foreach (Instance instance in Instance.Children)
{
try
{
var f = instance.Resource as TCPFilter;
f.Disconnected(sender);
}
catch(Exception ex)
{
Global.Log(ex);
}
}
}
}
}

View File

@ -0,0 +1,13 @@
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,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Net;
using Esiur.Data;
using Esiur.Engine;
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()
{
throw new NotImplementedException();
}
}
}

173
Esiur/Net/UDP/UDPServer.cs Normal file
View File

@ -0,0 +1,173 @@
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.Engine;
using Esiur.Resource;
namespace Esiur.Net.UDP
{
/* public class IIPConnection
{
public EndPoint SenderPoint;
public
}*/
public class UDPServer : IResource
{
Thread Receiver;
UdpClient Udp;
public event DestroyedEvent OnDestroy;
public Instance Instance
{
get;
set;
}
[Storable]
string ip
{
get;
set;
}
[Storable]
ushort port
{
get;
set;
}
public bool Trigger(ResourceTrigger trigger)
{
if (trigger == ResourceTrigger.Initialize)
{
var address = ip == null ? IPAddress.Any : IPAddress.Parse(ip);
Udp = new UdpClient(new IPEndPoint(address, (int)port));
Receiver = new Thread(Receiving);
Receiver.Start();
}
else if (trigger == ResourceTrigger.Terminate)
{
if (Receiver != null)
Receiver.Abort();
}
return true;
}
private void Receiving()
{
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] b = Udp.Receive(ref ep);
foreach(var child in Instance.Children)
{
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);
}
}
}