parent
def44384aa
commit
190b8f904b
|
@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.UPnP.Services", "UP
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UPnPReader", "UPnPReader\UPnPReader.csproj", "{5E066080-8EC9-47B8-A1D3-171D06829484}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.Rest", "Rest\Network.Rest.csproj", "{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.UPnP.DLNA", "DLNA\Network.UPnP.DLNA.csproj", "{8BF16D75-B05B-48AF-A72D-5CDDC861DFD6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MEF.Bonjour", "MEF.Bonjour\MEF.Bonjour.csproj", "{94D114DE-DA48-4060-9B7A-3059BF75E87D}"
|
||||
|
@ -25,7 +23,66 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.Rest.MEF", "Network
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.Bonjour.Services", "Network.Bonjour.Services\Network.Bonjour.Services.csproj", "{8CC2B14D-E24B-41A8-AB93-17F130905E29}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Network", "Network", "{94021DC9-3285-44A8-B830-64489127EE2D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network", "Network\Network.csproj", "{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.Rest", "Network.Rest\Network.Rest.csproj", "{13A68F9C-F095-409E-A97D-A05FFCDCE210}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.Tests", "Network.Tests\Network.Tests.csproj", "{61DB9D8D-F2EA-40DC-8F37-58092891A6A5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 15
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = https://tfs09.codeplex.com/
|
||||
SccLocalPath0 = .
|
||||
SccProjectUniqueName1 = SD\\Network.ZeroConf.csproj
|
||||
SccProjectName1 = SD
|
||||
SccLocalPath1 = SD
|
||||
SccProjectUniqueName2 = Bonjour.NET\\Network.Bonjour.csproj
|
||||
SccProjectName2 = Bonjour.NET
|
||||
SccLocalPath2 = Bonjour.NET
|
||||
SccProjectUniqueName3 = mDNSReader\\mDNSReader.csproj
|
||||
SccProjectName3 = mDNSReader
|
||||
SccLocalPath3 = mDNSReader
|
||||
SccProjectUniqueName4 = DnsResolver\\Network.Dns.csproj
|
||||
SccProjectName4 = DnsResolver
|
||||
SccLocalPath4 = DnsResolver
|
||||
SccProjectUniqueName5 = UPnP\\Network.UPnP.Services.csproj
|
||||
SccProjectName5 = UPnP
|
||||
SccLocalPath5 = UPnP
|
||||
SccProjectUniqueName6 = UPnPReader\\UPnPReader.csproj
|
||||
SccProjectName6 = UPnPReader
|
||||
SccLocalPath6 = UPnPReader
|
||||
SccProjectUniqueName7 = DLNA\\Network.UPnP.DLNA.csproj
|
||||
SccProjectName7 = DLNA
|
||||
SccLocalPath7 = DLNA
|
||||
SccProjectUniqueName8 = MEF.Bonjour\\MEF.Bonjour.csproj
|
||||
SccProjectName8 = MEF.Bonjour
|
||||
SccLocalPath8 = MEF.Bonjour
|
||||
SccProjectUniqueName9 = MEF.Bonjour.Tests\\MEF.Bonjour.Tests.csproj
|
||||
SccProjectName9 = MEF.Bonjour.Tests
|
||||
SccLocalPath9 = MEF.Bonjour.Tests
|
||||
SccProjectUniqueName10 = Network.Rest.MEF\\Network.Rest.MEF.csproj
|
||||
SccProjectName10 = Network.Rest.MEF
|
||||
SccLocalPath10 = Network.Rest.MEF
|
||||
SccProjectUniqueName11 = Network.Bonjour.Services\\Network.Bonjour.Services.csproj
|
||||
SccProjectName11 = Network.Bonjour.Services
|
||||
SccLocalPath11 = Network.Bonjour.Services
|
||||
SccProjectUniqueName12 = Network\\Network.csproj
|
||||
SccProjectTopLevelParentUniqueName12 = Bonjour.NET.sln
|
||||
SccProjectName12 = Network
|
||||
SccLocalPath12 = Network
|
||||
SccProjectUniqueName13 = Network.Rest\\Network.Rest.csproj
|
||||
SccProjectTopLevelParentUniqueName13 = Bonjour.NET.sln
|
||||
SccProjectName13 = Network.Rest
|
||||
SccLocalPath13 = Network.Rest
|
||||
SccProjectUniqueName14 = Network.Tests\\Network.Tests.csproj
|
||||
SccProjectTopLevelParentUniqueName14 = Bonjour.NET.sln
|
||||
SccProjectName14 = Network.Tests
|
||||
SccLocalPath14 = Network.Tests
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
|
@ -55,10 +112,6 @@ Global
|
|||
{5E066080-8EC9-47B8-A1D3-171D06829484}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E066080-8EC9-47B8-A1D3-171D06829484}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5E066080-8EC9-47B8-A1D3-171D06829484}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8BF16D75-B05B-48AF-A72D-5CDDC861DFD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8BF16D75-B05B-48AF-A72D-5CDDC861DFD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8BF16D75-B05B-48AF-A72D-5CDDC861DFD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -79,8 +132,25 @@ Global
|
|||
{8CC2B14D-E24B-41A8-AB93-17F130905E29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8CC2B14D-E24B-41A8-AB93-17F130905E29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8CC2B14D-E24B-41A8-AB93-17F130905E29}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{13A68F9C-F095-409E-A97D-A05FFCDCE210}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{13A68F9C-F095-409E-A97D-A05FFCDCE210}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{13A68F9C-F095-409E-A97D-A05FFCDCE210}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{13A68F9C-F095-409E-A97D-A05FFCDCE210}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{61DB9D8D-F2EA-40DC-8F37-58092891A6A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{61DB9D8D-F2EA-40DC-8F37-58092891A6A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{61DB9D8D-F2EA-40DC-8F37-58092891A6A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{61DB9D8D-F2EA-40DC-8F37-58092891A6A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F} = {94021DC9-3285-44A8-B830-64489127EE2D}
|
||||
{13A68F9C-F095-409E-A97D-A05FFCDCE210} = {94021DC9-3285-44A8-B830-64489127EE2D}
|
||||
{61DB9D8D-F2EA-40DC-8F37-58092891A6A5} = {94021DC9-3285-44A8-B830-64489127EE2D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
|
||||
}
|
|
@ -42,8 +42,8 @@ namespace Network.Bonjour
|
|||
EnhanceService(a);
|
||||
}
|
||||
|
||||
MDnsClient resolver;
|
||||
MDnsClient publisher;
|
||||
MDnsServer resolver;
|
||||
MDnsServer publisher;
|
||||
AutoResetEvent resolved = new AutoResetEvent(false);
|
||||
bool needsToBeResolvedLater = false;
|
||||
|
||||
|
@ -58,9 +58,9 @@ namespace Network.Bonjour
|
|||
return;
|
||||
}
|
||||
needsToBeResolvedLater = false;
|
||||
resolver = MDnsClient.CreateAndResolve(HostName);
|
||||
resolver = new MDnsServer().Resolve(HostName);
|
||||
resolver.AnswerReceived += client_AnswerReceived;
|
||||
resolver.Start();
|
||||
resolver.StartUdp();
|
||||
resolved.WaitOne();
|
||||
}
|
||||
|
||||
|
@ -176,26 +176,10 @@ namespace Network.Bonjour
|
|||
|
||||
public void Publish()
|
||||
{
|
||||
publisher = new MDnsClient(new IPEndPoint(IPAddress.Any, 5353));
|
||||
publisher.QueryReceived += new ObjectEvent<Message>(publisher_QueryReceived);
|
||||
publisher.Start();
|
||||
Message m = new Message();
|
||||
m.From = MDnsClient.EndPoint;
|
||||
m.QueryResponse = Qr.Answer;
|
||||
m.OpCode = OpCode.Query;
|
||||
m.AuthoritativeAnswer = true;
|
||||
m.ID = 0;
|
||||
m.ResponseCode = ResponseCode.NoError;
|
||||
foreach (Network.Dns.EndPoint ep in Addresses)
|
||||
{
|
||||
foreach (var address in ep.Addresses)
|
||||
m.Additionals.Add(new Answer() { Class = Class.IN, DomainName = HostName, Ttl = 500, Type = address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? Network.Dns.Type.A : Network.Dns.Type.AAAA, ResponseData = new HostAddress() { Address = address } });
|
||||
m.Additionals.Add(new Answer() { Class = Class.IN, DomainName = Name + "." + Protocol, Ttl = 500, Type = Network.Dns.Type.SRV, ResponseData = new Srv() { Port = ep.Port, Target = ep.DomainName } });
|
||||
m.Additionals.Add(new Answer() { Class = Class.IN, DomainName = Name + "." + Protocol, Ttl = 500, Type = Network.Dns.Type.TXT, ResponseData = new Txt() { Properties = properties } });
|
||||
m.Authorities.Add(new Answer() { Class = Class.IN, DomainName = Protocol, Ttl = 500, Type = Network.Dns.Type.PTR, ResponseData = new Ptr() { DomainName = Name + "." + Protocol } });
|
||||
}
|
||||
|
||||
publisher.Send(m, m.From);
|
||||
publisher = new MDnsServer(new IPEndPoint(IPAddress.Any, 5353));
|
||||
publisher.QueryReceived += publisher_QueryReceived;
|
||||
publisher.StartUdp();
|
||||
Renew(500);
|
||||
}
|
||||
|
||||
void publisher_QueryReceived(Message item)
|
||||
|
@ -216,7 +200,7 @@ namespace Network.Bonjour
|
|||
item.Answers.Add(new Answer() { Class = Class.IN, DomainName = Protocol, Ttl = 5, Type = Network.Dns.Type.TXT, ResponseData = new Txt() { Properties = properties } });
|
||||
}
|
||||
|
||||
publisher.Send(item, item.From);
|
||||
//publisher.Send(item, item.From);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,6 +281,23 @@ namespace Network.Bonjour
|
|||
public void Renew(uint ttl)
|
||||
{
|
||||
expiration = DateTime.Now.AddSeconds(ttl);
|
||||
Message m = new Message();
|
||||
m.From = MDnsServer.EndPoint;
|
||||
m.QueryResponse = Qr.Answer;
|
||||
m.OpCode = OpCode.Query;
|
||||
m.AuthoritativeAnswer = true;
|
||||
m.ID = 0;
|
||||
m.ResponseCode = ResponseCode.NoError;
|
||||
foreach (Network.Dns.EndPoint ep in Addresses)
|
||||
{
|
||||
foreach (var address in ep.Addresses)
|
||||
m.Additionals.Add(new Answer() { Class = Class.IN, DomainName = HostName, Ttl = ttl, Type = address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? Network.Dns.Type.A : Network.Dns.Type.AAAA, ResponseData = new HostAddress() { Address = address } });
|
||||
m.Additionals.Add(new Answer() { Class = Class.IN, DomainName = Name + "." + Protocol, Ttl = ttl, Type = Network.Dns.Type.SRV, ResponseData = new Srv() { Port = ep.Port, Target = ep.DomainName } });
|
||||
m.Additionals.Add(new Answer() { Class = Class.IN, DomainName = Name + "." + Protocol, Ttl = ttl, Type = Network.Dns.Type.TXT, ResponseData = new Txt() { Properties = properties } });
|
||||
m.Authorities.Add(new Answer() { Class = Class.IN, DomainName = Protocol, Ttl = ttl, Type = Network.Dns.Type.PTR, ResponseData = new Ptr() { DomainName = Name + "." + Protocol } });
|
||||
}
|
||||
|
||||
publisher.Send(m, m.From);
|
||||
}
|
||||
|
||||
#region IService Members
|
||||
|
@ -315,6 +316,7 @@ namespace Network.Bonjour
|
|||
else
|
||||
AddAddress(endpoint);
|
||||
}
|
||||
State = State.Updated;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Network.Bonjour
|
|||
|
||||
public class BonjourServiceResolver : IServiceResolver, IDisposable
|
||||
{
|
||||
MDnsClient client;
|
||||
MDnsServer client;
|
||||
IList<IService> services;
|
||||
private StringCollection protocols;
|
||||
|
||||
|
@ -46,13 +46,12 @@ namespace Network.Bonjour
|
|||
protocols.Add(protocol);
|
||||
if (client == null)
|
||||
{
|
||||
client = MDnsClient.CreateAndResolve(protocol);
|
||||
client = new MDnsServer();
|
||||
client.AnswerReceived += client_AnswerReceived;
|
||||
client.Resolve(protocol);
|
||||
}
|
||||
else
|
||||
client.Resolve(protocol);
|
||||
if (!client.IsStarted)
|
||||
client.Start();
|
||||
}
|
||||
|
||||
public IList<IService> Resolve(string protocol, TimeSpan timeout, int minCountServices, int maxCountServices)
|
||||
|
@ -93,6 +92,7 @@ namespace Network.Bonjour
|
|||
rightService.Merge(service);
|
||||
break;
|
||||
case State.Removed:
|
||||
((Service)rightService).State = State.Removed;
|
||||
services.Remove(rightService);
|
||||
if (ServiceRemoved != null)
|
||||
ServiceRemoved(rightService);
|
||||
|
@ -109,6 +109,16 @@ namespace Network.Bonjour
|
|||
else
|
||||
AddService(service);
|
||||
}
|
||||
|
||||
foreach (var service in services)
|
||||
{
|
||||
if (service.State == State.Updated)
|
||||
{
|
||||
if (ServiceFound != null)
|
||||
ServiceFound(service);
|
||||
((Service)service).State = State.UpToDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddService(IService service)
|
||||
|
@ -116,9 +126,6 @@ namespace Network.Bonjour
|
|||
if (!protocols.Contains(service.Protocol))
|
||||
return;
|
||||
this.services.Add(service);
|
||||
if (ServiceFound != null)
|
||||
ServiceFound(service);
|
||||
((Service)service).State = State.UpToDate;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Network.Dns;
|
||||
using System.Net;
|
||||
using Network.ZeroConf;
|
||||
|
||||
namespace Network.Bonjour
|
||||
{
|
||||
public class MDnsServer : DnsServer
|
||||
{
|
||||
public static readonly IPEndPoint EndPoint = new IPEndPoint(IPAddress.Parse("224.0.0.251"), 5353);
|
||||
|
||||
public MDnsServer(ushort port)
|
||||
: base(port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MDnsServer(IPAddress address, ushort port)
|
||||
: base(address, port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MDnsServer(IPEndPoint host)
|
||||
: base(host)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
public MDnsServer()
|
||||
: this(EndPoint)
|
||||
{
|
||||
this.Started += new EventHandler(MDnsServer_Started);
|
||||
}
|
||||
|
||||
void MDnsServer_Started(object sender, EventArgs e)
|
||||
{
|
||||
if (this.IsUdp)
|
||||
udp.MulticastLoopback = true;
|
||||
}
|
||||
|
||||
public event ObjectEvent<Message> AnswerReceived;
|
||||
public event ObjectEvent<Message> QueryReceived;
|
||||
|
||||
ushort requestId;
|
||||
|
||||
public MDnsServer Resolve(string dname)
|
||||
{
|
||||
Message message = new Message();
|
||||
List<byte> guid = Guid.NewGuid().ToByteArray().Take(2).ToList();
|
||||
requestId = (ushort)(guid[0] * byte.MaxValue + guid[1]);
|
||||
message.ID = requestId;
|
||||
message.Questions.Add(new Question(dname));
|
||||
if (!IsStarted)
|
||||
StartUdp();
|
||||
Send(message, EndPoint);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected override void OnRequestReceived(RequestEventArgs<Message, Message> rea)
|
||||
{
|
||||
base.OnRequestReceived(rea);
|
||||
if ((rea.Request.ID == requestId && rea.Request.QueryResponse == Qr.Answer) || rea.Request.ID == 0)
|
||||
{
|
||||
if (AnswerReceived != null)
|
||||
AnswerReceived(rea.Request.Clone());
|
||||
}
|
||||
if ((rea.Request.ID != requestId || rea.Request.ID == 0) && rea.Request.QueryResponse == Qr.Query)
|
||||
{
|
||||
this.requestId = 0;
|
||||
Message response = rea.Request.Clone();
|
||||
if (QueryReceived != null)
|
||||
QueryReceived(response);
|
||||
if (response.AnswerEntries > 0)
|
||||
rea.Response = response;
|
||||
}
|
||||
}
|
||||
|
||||
internal new void Send(Message response, IPEndPoint remote)
|
||||
{
|
||||
base.Send(response, remote);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>Bonjour.NET</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -47,7 +51,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="BonjourService.cs" />
|
||||
<Compile Include="BonjourServiceResolver.cs" />
|
||||
<Compile Include="MDnsClient.cs" />
|
||||
<Compile Include="MDnsServer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -55,6 +59,10 @@
|
|||
<Project>{36528547-53DC-46CD-8C97-1BAE69262B00}</Project>
|
||||
<Name>Network.Dns</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SD\Network.ZeroConf.csproj">
|
||||
<Project>{2B2D41E0-DBC7-4075-873C-394D02448281}</Project>
|
||||
<Name>Network.ZeroConf</Name>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -6,6 +6,7 @@ using Network.Rest;
|
|||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using System.Net;
|
||||
using Network;
|
||||
|
||||
namespace DLNA.ContentDirectory
|
||||
{
|
||||
|
@ -13,7 +14,7 @@ namespace DLNA.ContentDirectory
|
|||
{
|
||||
public Browse(string connectionString) : base(connectionString) { }
|
||||
|
||||
public override void Initialize(HttpRequest request)
|
||||
public override Command<HttpRequestEventArgs, HttpRequest, HttpResponse> Initialize(HttpRequest request, IServiceProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ namespace DLNA.ContentDirectory
|
|||
return request;
|
||||
}
|
||||
|
||||
public override void Execute(RequestEventArgs e)
|
||||
public override void Execute(HttpRequestEventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>Network.UPnP.DLNA</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -50,10 +54,14 @@
|
|||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Rest\Network.Rest.csproj">
|
||||
<Project>{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}</Project>
|
||||
<ProjectReference Include="..\Network.Rest\Network.Rest.csproj">
|
||||
<Project>{13A68F9C-F095-409E-A97D-A05FFCDCE210}</Project>
|
||||
<Name>Network.Rest</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\UPnP\Network.UPnP.Services.csproj">
|
||||
<Project>{39E23211-B902-4FE9-8A61-264F81D63864}</Project>
|
||||
<Name>Network.UPnP.Services</Name>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
|
||||
namespace Network.Dns
|
||||
{
|
||||
public class Answer
|
||||
public class Answer: IResponse
|
||||
{
|
||||
public DomainName DomainName { get; set; }
|
||||
public Type Type { get; set; }
|
||||
|
@ -13,39 +13,39 @@ namespace Network.Dns
|
|||
public uint Ttl { get; set; }
|
||||
public ResponseData ResponseData { get; set; }
|
||||
|
||||
public byte[] ToBytes()
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
bytes.AddRange(DomainName.ToBytes());
|
||||
bytes.AddRange(Message.ToBytes((ushort)Type));
|
||||
bytes.AddRange(Message.ToBytes((ushort)Class));
|
||||
bytes.AddRange(Message.ToBytes(Ttl));
|
||||
bytes.AddRange(ResponseData.ToBytes());
|
||||
return bytes.ToArray();
|
||||
}
|
||||
|
||||
public static Answer FromBytes(byte[] bytes, ref int index)
|
||||
{
|
||||
Answer a = new Answer();
|
||||
a.DomainName = DomainName.FromBytes(bytes, ref index);
|
||||
ushort s;
|
||||
Message.FromBytes(bytes, index, out s);
|
||||
a.Type = (Type)s;
|
||||
index += 2;
|
||||
Message.FromBytes(bytes, index, out s);
|
||||
a.Class = (Class)s;
|
||||
index += 2;
|
||||
uint ttl;
|
||||
Message.FromBytes(bytes, index, out ttl);
|
||||
a.Ttl = ttl;
|
||||
index += 4;
|
||||
a.ResponseData = ResponseData.FromBytes(a.Type, bytes, ref index);
|
||||
return a;
|
||||
return BinaryHelper.GetBytes(this);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}, Type: {1}, Class: {2}, TTL: {3} = {4}", DomainName, Type, Class, Ttl, ResponseData);
|
||||
}
|
||||
|
||||
internal static Answer Get(System.IO.BinaryReader reader)
|
||||
{
|
||||
Answer a = new Answer();
|
||||
a.DomainName = DomainName.Get(reader);
|
||||
ushort s;
|
||||
Message.FromBytes(reader.ReadBytes(2), out s);
|
||||
a.Type = (Type)s;
|
||||
Message.FromBytes(reader.ReadBytes(2), out s);
|
||||
a.Class = (Class)s;
|
||||
uint ttl;
|
||||
Message.FromBytes(reader.ReadBytes(4), out ttl);
|
||||
a.Ttl = ttl;
|
||||
a.ResponseData = ResponseData.Get(a.Type, reader);
|
||||
return a;
|
||||
}
|
||||
|
||||
public void WriteTo(System.IO.BinaryWriter writer)
|
||||
{
|
||||
DomainName.WriteTo(writer);
|
||||
writer.Write(Message.ToBytes((ushort)Type));
|
||||
writer.Write(Message.ToBytes((ushort)Class));
|
||||
writer.Write(Message.ToBytes(Ttl));
|
||||
ResponseData.WriteTo(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Network.Dns
|
||||
{
|
||||
class BackReferenceBinaryReader : BinaryReader
|
||||
{
|
||||
public BackReferenceBinaryReader(Stream input)
|
||||
: base(input)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BackReferenceBinaryReader(Stream input, Encoding encoding)
|
||||
: base(input, encoding)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SortedDictionary<int, object> registeredElements = new SortedDictionary<int, object>();
|
||||
|
||||
public T Get<T>(int p)
|
||||
{
|
||||
return (T)registeredElements[p];
|
||||
}
|
||||
|
||||
public void Register(int p, object value)
|
||||
{
|
||||
registeredElements.Add(p,value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -124,7 +124,12 @@ namespace Network.Dns
|
|||
/// <summary>
|
||||
/// the location of the server(s) for a specific protocol and domain
|
||||
/// </summary>
|
||||
SRV = 33
|
||||
SRV = 33,
|
||||
|
||||
/// <summary>
|
||||
/// EDNS0 option
|
||||
/// </summary>
|
||||
OPT=41
|
||||
}
|
||||
|
||||
public enum QType
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.Dns
|
||||
{
|
||||
public class DnsServer : Server<Message, Message>
|
||||
{
|
||||
public DnsServer(ushort port)
|
||||
: base(port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DnsServer(IPAddress address, ushort port)
|
||||
: base(address, port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DnsServer(IPEndPoint host)
|
||||
: base(host)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
public DnsServer()
|
||||
: this(53)
|
||||
{
|
||||
|
||||
}
|
||||
protected override RequestEventArgs<Message, Message> GetEventArgs(Message request)
|
||||
{
|
||||
return new RequestEventArgs<Message, Message>() { Request = request };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,10 +2,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Network.Dns
|
||||
{
|
||||
public class DomainName : List<string>
|
||||
public class DomainName : List<string>, IResponse
|
||||
{
|
||||
public DomainName() { }
|
||||
|
||||
|
@ -24,6 +25,20 @@ namespace Network.Dns
|
|||
return bytes.ToArray();
|
||||
}
|
||||
|
||||
public ushort GetByteCount()
|
||||
{
|
||||
ushort result = 1;
|
||||
foreach (string label in this)
|
||||
{
|
||||
if (label.Length == 0)
|
||||
break;
|
||||
int bytes = Encoding.UTF8.GetByteCount(label);
|
||||
result += (ushort)(bytes + 1);
|
||||
//labels.Add(new KeyValuePair<byte[], byte>(bytes, (byte)bytes.Length));
|
||||
//totalLength += (ushort)(bytes.Length + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static DomainName FromBytes(byte[] bytes, ref int index)
|
||||
{
|
||||
|
@ -74,5 +89,69 @@ namespace Network.Dns
|
|||
dn.AddRange(s.Split('.'));
|
||||
return dn;
|
||||
}
|
||||
|
||||
#region IResponse Members
|
||||
|
||||
public void WriteTo(BinaryWriter writer)
|
||||
{
|
||||
//ushort totalLength = 0;
|
||||
//List<KeyValuePair<byte[], byte>> labels = new List<KeyValuePair<byte[], byte>>();
|
||||
foreach (string label in this)
|
||||
{
|
||||
if (label.Length == 0)
|
||||
break;
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(label);
|
||||
//labels.Add(new KeyValuePair<byte[], byte>(bytes, (byte)bytes.Length));
|
||||
//totalLength += (ushort)(bytes.Length + 1);
|
||||
writer.Write((byte)bytes.Length);
|
||||
writer.Write(bytes);
|
||||
}
|
||||
writer.Write((byte)0);
|
||||
//writer.Write(totalLength);
|
||||
//foreach (var label in labels)
|
||||
//{
|
||||
// writer.Write(label.Value);
|
||||
// writer.Write(label.Key);
|
||||
//}
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
return BinaryHelper.GetBytes(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static DomainName Get(BinaryReader reader)
|
||||
{
|
||||
byte stringLength = reader.ReadByte();
|
||||
if (stringLength >> 6 == 3)
|
||||
{
|
||||
|
||||
if (!(reader is BackReferenceBinaryReader))
|
||||
throw new NotSupportedException("The given binary reader does not support back reference");
|
||||
//In case of pointer
|
||||
ushort ptr;
|
||||
Message.FromBytes(new byte[] { (byte)(stringLength - (3 << 6)), reader.ReadByte() }, out ptr);
|
||||
return ((BackReferenceBinaryReader)reader).Get<DomainName>(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
DomainName dn = new DomainName();
|
||||
if (reader is BackReferenceBinaryReader)
|
||||
((BackReferenceBinaryReader)reader).Register((int)reader.BaseStream.Position - 1, dn);
|
||||
//stringLength = reader.ReadByte();
|
||||
if (stringLength != 0)
|
||||
{
|
||||
dn.Add(Encoding.UTF8.GetString(reader.ReadBytes(stringLength)));
|
||||
//dn.Add(Encoding.UTF8.GetString(bytes, index + 1, bytes[index]));
|
||||
|
||||
dn.AddRange(DomainName.Get(reader));
|
||||
}
|
||||
//else
|
||||
// index++;
|
||||
return dn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
namespace Network.Dns
|
||||
{
|
||||
public class Message
|
||||
public class Message : IRequest<Message>, IResponse
|
||||
{
|
||||
public Message()
|
||||
{
|
||||
|
@ -50,41 +51,47 @@ namespace Network.Dns
|
|||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
//ID
|
||||
bytes.AddRange(ToBytes(ID));
|
||||
//Qr, Opcode, Aa, Tc, Rd
|
||||
byte b = 0;
|
||||
b += (byte)QueryResponse;
|
||||
b = (byte)(b << 4);
|
||||
b += (byte)OpCode;
|
||||
b = (byte)(b << 1);
|
||||
b += (AuthoritativeAnswer) ? (byte)1 : (byte)0;
|
||||
b = (byte)(b << 1);
|
||||
b += (Truncated) ? (byte)1 : (byte)0;
|
||||
b = (byte)(b << 1);
|
||||
b += (RecursionDesired) ? (byte)1 : (byte)0;
|
||||
bytes.Add(b);
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
WriteTo(new BinaryWriter(stream));
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
//Ra, Z, Rcode
|
||||
b = 0;
|
||||
b += (RecursionAvailable) ? (byte)1 : (byte)0;
|
||||
b = (byte)(b << 7);
|
||||
b += (byte)ResponseCode;
|
||||
bytes.Add(b);
|
||||
bytes.AddRange(ToBytes(QuestionEntries));
|
||||
bytes.AddRange(ToBytes(AnswerEntries));
|
||||
bytes.AddRange(ToBytes(AuthorityEntries));
|
||||
bytes.AddRange(ToBytes(AdditionalEntries));
|
||||
foreach (Question q in Questions)
|
||||
bytes.AddRange(q.ToBytes());
|
||||
foreach (Answer a in Answers)
|
||||
bytes.AddRange(a.ToBytes());
|
||||
foreach (Answer a in Authorities)
|
||||
bytes.AddRange(a.ToBytes());
|
||||
foreach (Answer a in Additionals)
|
||||
bytes.AddRange(a.ToBytes());
|
||||
return bytes.ToArray();
|
||||
//List<byte> bytes = new List<byte>();
|
||||
////ID
|
||||
//bytes.AddRange(ToBytes(ID));
|
||||
////Qr, Opcode, Aa, Tc, Rd
|
||||
//byte b = 0;
|
||||
//b += (byte)QueryResponse;
|
||||
//b = (byte)(b << 4);
|
||||
//b += (byte)OpCode;
|
||||
//b = (byte)(b << 1);
|
||||
//b += (AuthoritativeAnswer) ? (byte)1 : (byte)0;
|
||||
//b = (byte)(b << 1);
|
||||
//b += (Truncated) ? (byte)1 : (byte)0;
|
||||
//b = (byte)(b << 1);
|
||||
//b += (RecursionDesired) ? (byte)1 : (byte)0;
|
||||
//bytes.Add(b);
|
||||
|
||||
////Ra, Z, Rcode
|
||||
//b = 0;
|
||||
//b += (RecursionAvailable) ? (byte)1 : (byte)0;
|
||||
//b = (byte)(b << 7);
|
||||
//b += (byte)ResponseCode;
|
||||
//bytes.Add(b);
|
||||
//bytes.AddRange(ToBytes(QuestionEntries));
|
||||
//bytes.AddRange(ToBytes(AnswerEntries));
|
||||
//bytes.AddRange(ToBytes(AuthorityEntries));
|
||||
//bytes.AddRange(ToBytes(AdditionalEntries));
|
||||
//foreach (Question q in Questions)
|
||||
// bytes.AddRange(q.ToBytes());
|
||||
//foreach (Answer a in Answers)
|
||||
// bytes.AddRange(a.ToBytes());
|
||||
//foreach (Answer a in Authorities)
|
||||
// bytes.AddRange(a.ToBytes());
|
||||
//foreach (Answer a in Additionals)
|
||||
// bytes.AddRange(a.ToBytes());
|
||||
//return bytes.ToArray();
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,47 +152,6 @@ namespace Network.Dns
|
|||
public IList<Answer> Authorities { get; set; }
|
||||
public IList<Answer> Additionals { get; set; }
|
||||
|
||||
public static Message FromBytes(byte[] bytes)
|
||||
{
|
||||
Message m = new Message();
|
||||
ushort id;
|
||||
int index = 0;
|
||||
FromBytes(bytes, out id);
|
||||
m.ID = id;
|
||||
index++; index++;
|
||||
byte b = bytes[index++];
|
||||
//Qr, Opcode, Aa, Tc, Rd
|
||||
m.RecursionDesired = (b % 2) == 1;
|
||||
b = (byte)(b >> 1);
|
||||
m.Truncated = (b % 2) == 1;
|
||||
b = (byte)(b >> 1);
|
||||
m.AuthoritativeAnswer = (b % 2) == 1;
|
||||
b = (byte)(b >> 1);
|
||||
int opCodeNumber = b % 16;
|
||||
m.OpCode = (OpCode)opCodeNumber;
|
||||
b = (byte)(b >> 4);
|
||||
m.QueryResponse = (Qr)b;
|
||||
//Ra, Z, Rcode
|
||||
b = bytes[index++];
|
||||
m.RecursionAvailable = b > 127;
|
||||
b = (byte)((b << 1) >> 1);
|
||||
m.ResponseCode = (ResponseCode)b;
|
||||
ushort questionEntryCount, answerEntryCount, authorityEntryCount, additionalEntryCount;
|
||||
FromBytes(new byte[] { bytes[index++], bytes[index++] }, out questionEntryCount);
|
||||
FromBytes(new byte[] { bytes[index++], bytes[index++] }, out answerEntryCount);
|
||||
FromBytes(new byte[] { bytes[index++], bytes[index++] }, out authorityEntryCount);
|
||||
FromBytes(new byte[] { bytes[index++], bytes[index++] }, out additionalEntryCount);
|
||||
for (int i = 0; i < questionEntryCount; i++)
|
||||
m.Questions.Add(Question.FromBytes(bytes, ref index));
|
||||
for (int i = 0; i < answerEntryCount; i++)
|
||||
m.Answers.Add(Answer.FromBytes(bytes, ref index));
|
||||
for (int i = 0; i < authorityEntryCount; i++)
|
||||
m.Authorities.Add(Answer.FromBytes(bytes, ref index));
|
||||
for (int i = 0; i < additionalEntryCount; i++)
|
||||
m.Additionals.Add(Answer.FromBytes(bytes, ref index));
|
||||
return m;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
@ -207,5 +173,124 @@ namespace Network.Dns
|
|||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
#region IResponse Members
|
||||
|
||||
public void WriteTo(BinaryWriter writer)
|
||||
{
|
||||
//ID
|
||||
writer.Write(Message.ToBytes(ID));
|
||||
//Qr, Opcode, Aa, Tc, Rd
|
||||
byte b = 0;
|
||||
b += (byte)QueryResponse;
|
||||
b = (byte)(b << 4);
|
||||
b += (byte)OpCode;
|
||||
b = (byte)(b << 1);
|
||||
b += (AuthoritativeAnswer) ? (byte)1 : (byte)0;
|
||||
b = (byte)(b << 1);
|
||||
b += (Truncated) ? (byte)1 : (byte)0;
|
||||
b = (byte)(b << 1);
|
||||
b += (RecursionDesired) ? (byte)1 : (byte)0;
|
||||
writer.Write(b);
|
||||
|
||||
//Ra, Z, Rcode
|
||||
b = 0;
|
||||
b += (RecursionAvailable) ? (byte)1 : (byte)0;
|
||||
b = (byte)(b << 7);
|
||||
b += (byte)ResponseCode;
|
||||
writer.Write(b);
|
||||
writer.Write(Message.ToBytes(QuestionEntries));
|
||||
writer.Write(Message.ToBytes(AnswerEntries));
|
||||
writer.Write(Message.ToBytes(AuthorityEntries));
|
||||
writer.Write(Message.ToBytes(AdditionalEntries));
|
||||
foreach (Question q in Questions)
|
||||
q.WriteTo(writer);
|
||||
foreach (Answer a in Answers)
|
||||
a.WriteTo(writer);
|
||||
foreach (Answer a in Authorities)
|
||||
a.WriteTo(writer);
|
||||
foreach (Answer a in Additionals)
|
||||
a.WriteTo(writer);
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
return this.ToByteArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IRequest<Message> Members
|
||||
|
||||
public Message GetRequest(BinaryReader reader)
|
||||
{
|
||||
if (!(reader is BackReferenceBinaryReader))
|
||||
reader = new BackReferenceBinaryReader(reader.BaseStream, Encoding.BigEndianUnicode);
|
||||
Message m = new Message();
|
||||
ushort id;
|
||||
int index = 0;
|
||||
Message.FromBytes(reader.ReadBytes(2), out id);
|
||||
//FromBytes(bytes, out id);
|
||||
m.ID = id;
|
||||
index++; index++;
|
||||
byte b = reader.ReadByte();
|
||||
//byte b = bytes[index++];
|
||||
//Qr, Opcode, Aa, Tc, Rd
|
||||
m.RecursionDesired = (b % 2) == 1;
|
||||
b = (byte)(b >> 1);
|
||||
m.Truncated = (b % 2) == 1;
|
||||
b = (byte)(b >> 1);
|
||||
m.AuthoritativeAnswer = (b % 2) == 1;
|
||||
b = (byte)(b >> 1);
|
||||
int opCodeNumber = b % 16;
|
||||
m.OpCode = (OpCode)opCodeNumber;
|
||||
b = (byte)(b >> 4);
|
||||
m.QueryResponse = (Qr)b;
|
||||
//Ra, Z, Rcode
|
||||
b = reader.ReadByte();
|
||||
//b = bytes[index++];
|
||||
m.RecursionAvailable = b > 127;
|
||||
b = (byte)((b << 1) >> 1);
|
||||
m.ResponseCode = (ResponseCode)b;
|
||||
ushort questionEntryCount, answerEntryCount, authorityEntryCount, additionalEntryCount;
|
||||
Message.FromBytes(reader.ReadBytes(2), out questionEntryCount);
|
||||
Message.FromBytes(reader.ReadBytes(2), out answerEntryCount);
|
||||
Message.FromBytes(reader.ReadBytes(2), out authorityEntryCount);
|
||||
Message.FromBytes(reader.ReadBytes(2), out additionalEntryCount);
|
||||
//FromBytes(new byte[] { bytes[index++], bytes[index++] }, out questionEntryCount);
|
||||
//FromBytes(new byte[] { bytes[index++], bytes[index++] }, out answerEntryCount);
|
||||
//FromBytes(new byte[] { bytes[index++], bytes[index++] }, out authorityEntryCount);
|
||||
//FromBytes(new byte[] { bytes[index++], bytes[index++] }, out additionalEntryCount);
|
||||
for (int i = 0; i < questionEntryCount; i++)
|
||||
m.Questions.Add(Question.Get(reader));
|
||||
for (int i = 0; i < answerEntryCount; i++)
|
||||
m.Answers.Add(Answer.Get(reader));
|
||||
for (int i = 0; i < authorityEntryCount; i++)
|
||||
m.Authorities.Add(Answer.Get(reader));
|
||||
for (int i = 0; i < additionalEntryCount; i++)
|
||||
m.Additionals.Add(Answer.Get(reader));
|
||||
return m;
|
||||
}
|
||||
|
||||
public Message GetRequest(byte[] requestBytes)
|
||||
{
|
||||
using (MemoryStream ms=new MemoryStream(requestBytes))
|
||||
{
|
||||
ms.Position = 0;
|
||||
return GetRequest(new BinaryReader(ms));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Message Clone()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
WriteTo(new BinaryWriter(ms));
|
||||
ms.Position = 0;
|
||||
return GetRequest(new BinaryReader(ms));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>DnsResolver</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -46,6 +50,10 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Answer.cs" />
|
||||
<Compile Include="BackReferenceBinaryReader.cs" />
|
||||
<Compile Include="DnsServer.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="DomainName.cs" />
|
||||
<Compile Include="EndPoint.cs" />
|
||||
<Compile Include="Message.cs" />
|
||||
|
@ -54,6 +62,12 @@
|
|||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ResponseData.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -3,10 +3,11 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
|
||||
namespace Network.Dns
|
||||
{
|
||||
public class Question
|
||||
public class Question : IResponse
|
||||
{
|
||||
private Question()
|
||||
{
|
||||
|
@ -39,6 +40,8 @@ namespace Network.Dns
|
|||
public QType Type { get; set; }
|
||||
public QClass Class { get; set; }
|
||||
|
||||
public bool CacheFlush { get; set; }
|
||||
|
||||
public byte[] ToBytes()
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
|
@ -71,5 +74,34 @@ namespace Network.Dns
|
|||
sb.AppendFormat(" QClass : {0}", Class);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
#region IResponse Members
|
||||
|
||||
public void WriteTo(BinaryWriter writer)
|
||||
{
|
||||
DomainName.WriteTo(writer);
|
||||
writer.Write(Message.ToBytes((ushort)Type));
|
||||
writer.Write(Message.ToBytes((ushort)Class));
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
return BinaryHelper.GetBytes(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static Question Get(BinaryReader reader)
|
||||
{
|
||||
Question q = new Question();
|
||||
q.DomainName = DomainName.Get(reader);
|
||||
ushort s;
|
||||
Message.FromBytes(reader.ReadBytes(2), out s);
|
||||
q.Type = (QType)s;
|
||||
Message.FromBytes(reader.ReadBytes(2), out s);
|
||||
q.Class = (QClass)((ushort)(s << 1) >> 1);
|
||||
q.CacheFlush = ((ushort)q.Class) != s;
|
||||
return q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,20 +3,21 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
namespace Network.Dns
|
||||
{
|
||||
public abstract class ResponseData
|
||||
{
|
||||
public abstract byte[] ToBytes();
|
||||
public abstract void WriteTo(System.IO.BinaryWriter writer);
|
||||
|
||||
internal static ResponseData FromBytes(Type type, byte[] bytes, ref int index)
|
||||
internal static ResponseData Get(Type type, System.IO.BinaryReader reader)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Type.A:
|
||||
case Type.AAAA:
|
||||
return HostAddress.FromBytes(bytes, ref index);
|
||||
return HostAddress.Get(reader);
|
||||
break;
|
||||
case Type.NS:
|
||||
break;
|
||||
|
@ -25,7 +26,7 @@ namespace Network.Dns
|
|||
case Type.MF:
|
||||
break;
|
||||
case Type.CNAME:
|
||||
return CName.FromBytes(bytes, ref index);
|
||||
return CName.Get(reader);
|
||||
break;
|
||||
case Type.SOA:
|
||||
break;
|
||||
|
@ -40,7 +41,7 @@ namespace Network.Dns
|
|||
case Type.WKS:
|
||||
break;
|
||||
case Type.PTR:
|
||||
return Ptr.FromBytes(bytes, ref index);
|
||||
return Ptr.Get(reader);
|
||||
break;
|
||||
case Type.HINFO:
|
||||
break;
|
||||
|
@ -49,15 +50,16 @@ namespace Network.Dns
|
|||
case Type.MX:
|
||||
break;
|
||||
case Type.TXT:
|
||||
return Txt.FromBytes(bytes, ref index);
|
||||
return Txt.Get(reader);
|
||||
break;
|
||||
case Type.SRV:
|
||||
return Srv.FromBytes(bytes, ref index);
|
||||
return Srv.Get(reader);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw new NotImplementedException(string.Format("Cannot read {0} response", type));
|
||||
//throw new NotImplementedException(string.Format("Cannot read {0} response", type));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,22 +67,18 @@ namespace Network.Dns
|
|||
{
|
||||
public string CNAME { get; set; }
|
||||
|
||||
public override byte[] ToBytes()
|
||||
public override void WriteTo(System.IO.BinaryWriter writer)
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
bytes.AddRange(Message.ToBytes((ushort)Encoding.UTF8.GetByteCount(CNAME)));
|
||||
bytes.AddRange(Encoding.UTF8.GetBytes(CNAME));
|
||||
return bytes.ToArray();
|
||||
writer.Write(Message.ToBytes((ushort)Encoding.UTF8.GetByteCount(CNAME)));
|
||||
writer.Write(Encoding.UTF8.GetBytes(CNAME));
|
||||
}
|
||||
|
||||
internal static CName FromBytes(byte[] bytes, ref int index)
|
||||
internal static CName Get(BinaryReader reader)
|
||||
{
|
||||
ushort byteCount;
|
||||
Message.FromBytes(bytes, index, out byteCount);
|
||||
index += 2;
|
||||
Message.FromBytes(reader.ReadBytes(2), out byteCount);
|
||||
CName cName = new CName();
|
||||
cName.CNAME = Encoding.UTF8.GetString(bytes, index + 2, byteCount);
|
||||
index += byteCount;
|
||||
cName.CNAME = Encoding.UTF8.GetString(reader.ReadBytes(byteCount), 0, byteCount);
|
||||
return cName;
|
||||
}
|
||||
}
|
||||
|
@ -89,24 +87,20 @@ namespace Network.Dns
|
|||
{
|
||||
public IPAddress Address { get; set; }
|
||||
|
||||
internal static HostAddress FromBytes(byte[] bytes, ref int index)
|
||||
internal static HostAddress Get(BinaryReader reader)
|
||||
{
|
||||
ushort byteCount;
|
||||
Message.FromBytes(bytes, index, out byteCount);
|
||||
index += 2;
|
||||
Message.FromBytes(reader.ReadBytes(2), out byteCount);
|
||||
HostAddress ha = new HostAddress();
|
||||
ha.Address = new IPAddress(bytes.Skip(index).Take(byteCount).ToArray());
|
||||
index += byteCount;
|
||||
ha.Address = new IPAddress(reader.ReadBytes(byteCount));
|
||||
return ha;
|
||||
}
|
||||
|
||||
public override byte[] ToBytes()
|
||||
public override void WriteTo(System.IO.BinaryWriter writer)
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
byte[] address = Address.GetAddressBytes();
|
||||
bytes.AddRange(Message.ToBytes((ushort)address.Length));
|
||||
bytes.AddRange(address);
|
||||
return bytes.ToArray();
|
||||
writer.Write(Message.ToBytes((ushort)address.Length));
|
||||
writer.Write(address);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
@ -118,21 +112,20 @@ namespace Network.Dns
|
|||
{
|
||||
public DomainName DomainName { get; set; }
|
||||
|
||||
public override byte[] ToBytes()
|
||||
public override void WriteTo(System.IO.BinaryWriter writer)
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
bytes.AddRange(DomainName.ToBytes());
|
||||
bytes.InsertRange(0, Message.ToBytes((ushort)bytes.Count));
|
||||
return bytes.ToArray();
|
||||
writer.Write(Message.ToBytes(DomainName.GetByteCount()));
|
||||
DomainName.WriteTo(writer);
|
||||
}
|
||||
|
||||
internal static Ptr FromBytes(byte[] bytes, ref int index)
|
||||
internal static Ptr Get(BinaryReader reader)
|
||||
{
|
||||
Ptr p = new Ptr();
|
||||
ushort byteCount;
|
||||
Message.FromBytes(bytes, index, out byteCount);
|
||||
index += 2;
|
||||
p.DomainName = DomainName.FromBytes(bytes, ref index);
|
||||
//useless datalength
|
||||
Message.FromBytes(reader.ReadBytes(2), out byteCount);
|
||||
|
||||
p.DomainName = DomainName.Get(reader);
|
||||
//index += byteCount;
|
||||
return p;
|
||||
}
|
||||
|
@ -140,15 +133,12 @@ namespace Network.Dns
|
|||
|
||||
public class Srv : ResponseData
|
||||
{
|
||||
public override byte[] ToBytes()
|
||||
public override void WriteTo(System.IO.BinaryWriter writer)
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
bytes.AddRange(Message.ToBytes(Priority));
|
||||
bytes.AddRange(Message.ToBytes(Weight));
|
||||
bytes.AddRange(Message.ToBytes(Port));
|
||||
bytes.AddRange(Target.ToBytes());
|
||||
bytes.InsertRange(0, Message.ToBytes((ushort)bytes.Count));
|
||||
return bytes.ToArray();
|
||||
writer.Write(Message.ToBytes(Priority));
|
||||
writer.Write(Message.ToBytes(Weight));
|
||||
writer.Write(Message.ToBytes(Port));
|
||||
Target.WriteTo(writer);
|
||||
}
|
||||
|
||||
public ushort Priority { get; set; }
|
||||
|
@ -156,23 +146,19 @@ namespace Network.Dns
|
|||
public ushort Port { get; set; }
|
||||
public DomainName Target { get; set; }
|
||||
|
||||
internal static Srv FromBytes(byte[] bytes, ref int index)
|
||||
internal static Srv Get(BinaryReader reader)
|
||||
{
|
||||
Srv srv = new Srv();
|
||||
ushort s;
|
||||
//Useless Datalength
|
||||
Message.FromBytes(bytes, index, out s);
|
||||
index += 2;
|
||||
Message.FromBytes(bytes, index, out s);
|
||||
index += 2;
|
||||
reader.ReadBytes(2);
|
||||
Message.FromBytes(reader.ReadBytes(2), out s);
|
||||
srv.Priority = s;
|
||||
Message.FromBytes(bytes, index, out s);
|
||||
index += 2;
|
||||
Message.FromBytes(reader.ReadBytes(2), out s);
|
||||
srv.Weight = s;
|
||||
Message.FromBytes(bytes, index, out s);
|
||||
index += 2;
|
||||
Message.FromBytes(reader.ReadBytes(2), out s);
|
||||
srv.Port = s;
|
||||
srv.Target = DomainName.FromBytes(bytes, ref index);
|
||||
srv.Target = DomainName.Get(reader);
|
||||
return srv;
|
||||
}
|
||||
}
|
||||
|
@ -184,20 +170,25 @@ namespace Network.Dns
|
|||
Properties = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public override byte[] ToBytes()
|
||||
public override void WriteTo(System.IO.BinaryWriter writer)
|
||||
{
|
||||
ushort length = 0;
|
||||
List<byte> bytes = new List<byte>();
|
||||
List<KeyValuePair<byte[], byte>> bytes = new List<KeyValuePair<byte[], byte>>();
|
||||
foreach (KeyValuePair<string, string> kvp in Properties)
|
||||
{
|
||||
byte[] kvpBytes = Encoding.UTF8.GetBytes(kvp.Key + "=" + kvp.Value);
|
||||
bytes.Add((byte)kvpBytes.Length);
|
||||
bytes.AddRange(kvpBytes);
|
||||
bytes.Add(new KeyValuePair<byte[], byte>(kvpBytes, (byte)kvpBytes.Length));
|
||||
//writer.Write((byte)kvpBytes.Length);
|
||||
//writer.Write(kvpBytes);
|
||||
length += (ushort)kvpBytes.Length;
|
||||
length++;
|
||||
}
|
||||
bytes.InsertRange(0, Message.ToBytes(length));
|
||||
return bytes.ToArray();
|
||||
writer.Write(Message.ToBytes(length));
|
||||
foreach (var properties in bytes)
|
||||
{
|
||||
writer.Write(properties.Value);
|
||||
writer.Write(properties.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public const string True = "true";
|
||||
|
@ -226,18 +217,17 @@ namespace Network.Dns
|
|||
|
||||
public IDictionary<string, string> Properties { get; set; }
|
||||
|
||||
internal static Txt FromBytes(byte[] bytes, ref int index)
|
||||
internal static Txt Get(BinaryReader reader)
|
||||
{
|
||||
Txt txt = new Txt();
|
||||
ushort byteCount;
|
||||
ushort byteCount, byteRead = 0;
|
||||
//Useless Datalength
|
||||
Message.FromBytes(bytes, index, out byteCount);
|
||||
index += 2;
|
||||
int stop = index + byteCount;
|
||||
while (index < stop)
|
||||
Message.FromBytes(reader.ReadBytes(2), out byteCount);
|
||||
while (byteRead < byteCount)
|
||||
{
|
||||
txt.AddProperty(Encoding.UTF8.GetString(bytes, index + 1, bytes[index]));
|
||||
index += bytes[index] + 1;
|
||||
byte propertyLength = reader.ReadByte();
|
||||
byteRead += (ushort)(propertyLength + 1);
|
||||
txt.AddProperty(Encoding.UTF8.GetString(reader.ReadBytes(propertyLength), 0, propertyLength));
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<StartupObject>MEF.Bonjour.Tests.Program</StartupObject>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>MEF.Bonjour</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -13,6 +13,10 @@
|
|||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<StartupObject>Network.Bonjour.Services.Pear.AirDiskService</StartupObject>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -63,6 +67,10 @@
|
|||
<Project>{36528547-53DC-46CD-8C97-1BAE69262B00}</Project>
|
||||
<Name>Network.Dns</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SD\Network.ZeroConf.csproj">
|
||||
<Project>{2B2D41E0-DBC7-4075-873C-394D02448281}</Project>
|
||||
<Name>Network.ZeroConf</Name>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>Network.Rest.MEF</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -53,13 +57,17 @@
|
|||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Rest\Network.Rest.csproj">
|
||||
<Project>{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}</Project>
|
||||
<Name>Network.Rest</Name>
|
||||
</ProjectReference>
|
||||
<WCFMetadata Include="Service References\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WCFMetadata Include="Service References\" />
|
||||
<ProjectReference Include="..\Network.Rest\Network.Rest.csproj">
|
||||
<Project>{13A68F9C-F095-409E-A97D-A05FFCDCE210}</Project>
|
||||
<Name>Network.Rest</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -30,7 +30,7 @@ namespace Network.Rest.MEF
|
|||
public RestServer(ushort port)
|
||||
: base(port)
|
||||
{
|
||||
this.RequestReceived += new EventHandler<RequestEventArgs>(RestServer_RequestReceived);
|
||||
this.HttpRequestReceived += new EventHandler<HttpRequestEventArgs>(RestServer_RequestReceived);
|
||||
batch = new CompositionBatch();
|
||||
batch.AddPart(this);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace Network.Rest.MEF
|
|||
base.OnStart();
|
||||
}
|
||||
|
||||
void RestServer_RequestReceived(object sender, RequestEventArgs e)
|
||||
void RestServer_RequestReceived(object sender, HttpRequestEventArgs e)
|
||||
{
|
||||
Command c = commands.Where(command => command.Metadata["Method"].ToString() == e.Request.Method && command.Metadata.ContainsKey("UriConstraint") ? Regex.IsMatch(e.Request.Uri, command.Metadata["UriConstraint"].ToString()) : true).Single().GetExportedObject();
|
||||
c.Execute(e);
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
|
||||
|
||||
public abstract class Command : Command<HttpRequestEventArgs, HttpRequest, HttpResponse>
|
||||
{
|
||||
public Command(string connectionString)
|
||||
{
|
||||
Uri = new Uri(connectionString);
|
||||
}
|
||||
|
||||
public Command()
|
||||
{
|
||||
}
|
||||
|
||||
public Uri Uri { get; protected set; }
|
||||
|
||||
protected string Method { get; set; }
|
||||
|
||||
protected override HttpRequest BuildRequest()
|
||||
{
|
||||
HttpRequest request = new HttpRequest(Uri);
|
||||
request.KeepAlive = true;
|
||||
request.ContentType = "text/xml";
|
||||
request.Method = Method;
|
||||
return request;
|
||||
}
|
||||
|
||||
protected abstract HttpRequest GetRequest();
|
||||
|
||||
public override HttpResponse GetResponse(bool responseExpected)
|
||||
{
|
||||
HttpRequest request = GetRequest();
|
||||
return (HttpResponse)request.GetResponse(responseExpected);
|
||||
}
|
||||
|
||||
XmlDocument doc = new XmlDocument();
|
||||
bool docLoaded = false;
|
||||
|
||||
public XmlDocument GetXmlResponse()
|
||||
{
|
||||
if (!docLoaded)
|
||||
{
|
||||
HttpResponse response = GetResponse();
|
||||
docLoaded = true;
|
||||
doc.Load(response.Body);
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class CommandFactory : CommandFactory<HttpRequestEventArgs, HttpRequest, HttpResponse>
|
||||
{
|
||||
protected override Command<HttpRequestEventArgs, HttpRequest, HttpResponse> GetCommandInternal(HttpRequest request)
|
||||
{
|
||||
IDictionary<Regex, Type> possibleCommands = registeredCommands[request.Method];
|
||||
foreach (KeyValuePair<Regex, Type> command in possibleCommands)
|
||||
{
|
||||
if (command.Key.IsMatch(request.Uri))
|
||||
return (Command<HttpRequestEventArgs, HttpRequest, HttpResponse>)Activator.CreateInstance(command.Value);
|
||||
}
|
||||
throw new NotSupportedException("No command have been registered for this kind of request");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class HttpMessage
|
||||
{
|
||||
public HttpMessage()
|
||||
{
|
||||
Headers = new Dictionary<string, string>();
|
||||
Encoding = Encoding.UTF8;
|
||||
Uri = "*";
|
||||
Body = new MemoryStream();
|
||||
}
|
||||
|
||||
public HttpMessage(string uriString) : this(new Uri(uriString)) { }
|
||||
public HttpMessage(Uri uri)
|
||||
: this()
|
||||
{
|
||||
Uri = uri.PathAndQuery;
|
||||
if (uri.Port > 0)
|
||||
Host = uri.Host + ":" + uri.Port;
|
||||
else
|
||||
Host = uri.Host;
|
||||
}
|
||||
|
||||
public MemoryStream Body { get; protected set; }
|
||||
|
||||
public string Uri { get; set; }
|
||||
|
||||
public IDictionary<string, string> Headers { get; set; }
|
||||
|
||||
public Encoding Encoding { get; set; }
|
||||
|
||||
public virtual int ContentLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Headers.ContainsKey("Content-Length"))
|
||||
return int.Parse(Headers["Content-Length"]);
|
||||
return 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Headers["Content-Length"] = value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string Host
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Headers.ContainsKey("Host"))
|
||||
return Headers["Host"];
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (Headers.ContainsKey("Host"))
|
||||
Headers["Host"] = value;
|
||||
else
|
||||
Headers.Add("Host", value);
|
||||
}
|
||||
}
|
||||
|
||||
public HttpVersion HttpVersion { get; set; }
|
||||
|
||||
public virtual byte[] GetBytes()
|
||||
{
|
||||
return Encoding.GetBytes(this.ToString());
|
||||
}
|
||||
|
||||
protected const char SPACE = ' ';
|
||||
|
||||
|
||||
|
||||
protected void ReadHeaders(TextReader reader)
|
||||
{
|
||||
string line;
|
||||
while (!string.IsNullOrEmpty(line = reader.ReadLine()))
|
||||
{
|
||||
string[] header = line.Split(':');
|
||||
Headers.Add(header[0], line.Substring(header[0].Length + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum HttpVersion
|
||||
{
|
||||
HTTP11
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class HttpRequest : HttpMessage, IRequest<HttpRequest>
|
||||
{
|
||||
public HttpRequest() { }
|
||||
|
||||
public HttpRequest(string uriString) : base(uriString) { }
|
||||
public HttpRequest(Uri uri) : base(uri) { }
|
||||
|
||||
public string Method { get; set; }
|
||||
|
||||
public override int ContentLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Body.Length > 0 && Headers.ContainsKey("Content-Length"))
|
||||
return (int)Body.Length;
|
||||
return base.ContentLength;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.ContentLength = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool KeepAlive
|
||||
{
|
||||
get { return Headers["KeepAlive"] == "true"; }
|
||||
set { Headers["KeepAlive"] = value.ToString(); }
|
||||
}
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get { return (string)Headers["Content-Type"]; }
|
||||
set { Headers["Content-Type"] = value; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(Method);
|
||||
sb.Append(SPACE);
|
||||
sb.Append(Uri);
|
||||
sb.Append(SPACE);
|
||||
switch (HttpVersion)
|
||||
{
|
||||
case HttpVersion.HTTP11:
|
||||
sb.Append("HTTP/1.1");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sb.AppendLine();
|
||||
if (Host != null)
|
||||
sb.AppendLine(string.Format("Host: {0}", Host));
|
||||
if (Body.Length > 0)
|
||||
Headers["Content-Length"] = Body.Length.ToString();
|
||||
foreach (KeyValuePair<string, string> header in Headers)
|
||||
{
|
||||
if (header.Key != "Host")
|
||||
sb.AppendLine(string.Format("{0}: {1}", header.Key, header.Value));
|
||||
}
|
||||
sb.AppendLine();
|
||||
if (Body.Length > 0)
|
||||
{
|
||||
Body.Seek(0, SeekOrigin.Begin);
|
||||
StreamReader reader = new StreamReader(Body);
|
||||
sb.Append(reader.ReadToEnd());
|
||||
//reader.Close();
|
||||
sb.AppendLine();
|
||||
sb.AppendLine();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public TransportProtocol Protocol { get; set; }
|
||||
|
||||
public HttpResponse GetResponse(bool expectResponse)
|
||||
{
|
||||
Uri uri = new Uri("http://" + Host + Uri);
|
||||
if (Protocol == TransportProtocol.TCP)
|
||||
{
|
||||
TcpClient client = new TcpClient();
|
||||
client.Connect(uri.Host, uri.Port != 0 ? uri.Port : 80);
|
||||
//Uri = Uri.Substring(Uri.IndexOf('/', Uri.IndexOf(uri.Host)));
|
||||
byte[] requestBytes = GetBytes();
|
||||
Uri = uri.ToString();
|
||||
client.GetStream().Write(requestBytes, 0, requestBytes.Length);
|
||||
if (!expectResponse)
|
||||
return null;
|
||||
MemoryStream stream = new MemoryStream();
|
||||
NetworkStream clientStream = client.GetStream();
|
||||
do
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int lengthRead = clientStream.Read(buffer, 0, 1024);
|
||||
stream.Write(buffer, 0, lengthRead);
|
||||
} while (clientStream.DataAvailable);
|
||||
return HttpResponse.FromBytes(stream.ToArray());
|
||||
}
|
||||
if (Protocol == TransportProtocol.UDP)
|
||||
{
|
||||
UdpClient client = new UdpClient();
|
||||
client.Connect(uri.Host, uri.Port != 0 ? uri.Port : 80);
|
||||
byte[] requestBytes = GetBytes();
|
||||
client.Send(requestBytes, requestBytes.Length);
|
||||
if (!expectResponse)
|
||||
return null;
|
||||
System.Net.IPEndPoint ep = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0);
|
||||
return HttpResponse.FromBytes(client.Receive(ref ep));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static HttpRequest Parse(TextReader reader)
|
||||
{
|
||||
HttpRequest request = new HttpRequest();
|
||||
//METHOD URI VERSION
|
||||
string line = reader.ReadLine();
|
||||
string[] firstLine = line.Split(SPACE);
|
||||
request.Method = firstLine[0];
|
||||
request.Uri = firstLine[1];
|
||||
request.HttpVersion = HttpVersion.HTTP11;
|
||||
request.ReadHeaders(reader);
|
||||
request.Host = request.Host.Trim();
|
||||
return request;
|
||||
}
|
||||
|
||||
#region IRequest<HttpRequest> Members
|
||||
|
||||
|
||||
|
||||
public HttpRequest GetRequest(BinaryReader stream)
|
||||
{
|
||||
TextReader reader = new StreamReader(stream.BaseStream);
|
||||
return Parse(reader);
|
||||
|
||||
}
|
||||
|
||||
public HttpRequest GetRequest(byte[] bytes)
|
||||
{
|
||||
return Parse(Encoding.UTF8.GetString(bytes));
|
||||
}
|
||||
|
||||
public static HttpRequest Parse(string requestString)
|
||||
{
|
||||
StringReader reader = new StringReader(requestString);
|
||||
return Parse(reader);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum TransportProtocol
|
||||
{
|
||||
TCP,
|
||||
UDP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class HttpRequestEventArgs : RequestEventArgs<HttpRequest, HttpResponse>
|
||||
{
|
||||
public HttpRequestEventArgs()
|
||||
{
|
||||
Response = new HttpResponse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class HttpResponse : HttpMessage, IResponse
|
||||
{
|
||||
public HttpResponse()
|
||||
{
|
||||
ResponseCode = HttpStatusCode.OK;
|
||||
}
|
||||
|
||||
public static HttpResponse FromBytes(byte[] bytes)
|
||||
{
|
||||
return Parse(Encoding.UTF8.GetString(bytes));
|
||||
}
|
||||
|
||||
public HttpStatusCode ResponseCode { get; set; }
|
||||
public string ResponseMessage { get; set; }
|
||||
|
||||
protected XmlDocument document = null;
|
||||
|
||||
public XmlDocument Document
|
||||
{
|
||||
get
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
document = new XmlDocument();
|
||||
if (Body.Length > 0)
|
||||
document.Load(Body);
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static HttpResponse Parse(string responseString)
|
||||
{
|
||||
HttpResponse response = new HttpResponse();
|
||||
StringReader reader = new StringReader(responseString);
|
||||
string line = reader.ReadLine();
|
||||
string[] firstLine = line.Split(' ');
|
||||
//VERSION RESPONSECODE RESPONSEMESSAGE
|
||||
response.HttpVersion = HttpVersion.HTTP11;
|
||||
response.ResponseCode = (HttpStatusCode)int.Parse(firstLine[1]);
|
||||
response.ResponseMessage = string.Join(" ", firstLine, 2, firstLine.Length - 2);
|
||||
response.ReadHeaders(reader);
|
||||
StreamWriter sw = new StreamWriter(response.Body);
|
||||
sw.Write(reader.ReadToEnd());
|
||||
response.Body.Seek(0, SeekOrigin.Begin);
|
||||
return response;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
WriteTo(new BinaryWriter(ms));
|
||||
ms.Position = 0;
|
||||
using (StreamReader reader = new StreamReader(ms))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IResponse Members
|
||||
|
||||
public void WriteTo(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(string.Format("HTTP/1.1 {0} {1}\n", (int)ResponseCode, ResponseMessage));
|
||||
foreach (KeyValuePair<string, string> header in Headers)
|
||||
{
|
||||
if (header.Key != "Host")
|
||||
writer.Write(string.Format("{0}:{1}\n", header.Key, header.Value));
|
||||
}
|
||||
writer.Write("\n");
|
||||
Body.Seek(0, SeekOrigin.Begin);
|
||||
Body.WriteTo(writer.BaseStream);
|
||||
writer.Write("\n");
|
||||
writer.Write("\n");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{13A68F9C-F095-409E-A97D-A05FFCDCE210}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Network.Rest</RootNamespace>
|
||||
<AssemblyName>Network.Rest</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>rest.snk</AssemblyOriginatorKeyFile>
|
||||
<TargetFrameworkSubset>
|
||||
</TargetFrameworkSubset>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Command.cs" />
|
||||
<Compile Include="CommandFactory.cs" />
|
||||
<Compile Include="HttpRequestEventArgs.cs" />
|
||||
<Compile Include="RestServer.cs" />
|
||||
<Compile Include="HttpMessage.cs" />
|
||||
<Compile Include="HttpRequest.cs" />
|
||||
<Compile Include="HttpResponse.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="rest.snk" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Network.Rest")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Network.Rest")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("7bf45d0c-5b81-4d07-9655-68383357cfb1")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class RestServer : Server<HttpRequest, HttpResponse>
|
||||
{
|
||||
public RestServer()
|
||||
: this(80)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public RestServer(ushort port)
|
||||
: base(port)
|
||||
{
|
||||
}
|
||||
|
||||
public RestServer(IPAddress host, ushort port)
|
||||
: base(host, port)
|
||||
{
|
||||
}
|
||||
|
||||
public RestServer(IPEndPoint host)
|
||||
: base(host)
|
||||
{
|
||||
}
|
||||
|
||||
public event EventHandler<HttpRequestEventArgs> HttpRequestReceived;
|
||||
|
||||
protected override void OnRequestReceived(RequestEventArgs<HttpRequest, HttpResponse> rea)
|
||||
{
|
||||
base.OnRequestReceived(rea);
|
||||
if (HttpRequestReceived != null)
|
||||
HttpRequestReceived(this, (HttpRequestEventArgs)rea);
|
||||
}
|
||||
|
||||
protected override RequestEventArgs<HttpRequest, HttpResponse> GetEventArgs(HttpRequest request)
|
||||
{
|
||||
return new HttpRequestEventArgs() { Request = request };
|
||||
}
|
||||
|
||||
protected override void TreatTcp(RequestEventArgs<HttpRequest, HttpResponse> rea, System.Net.Sockets.TcpClient tcpClient)
|
||||
{
|
||||
try
|
||||
{
|
||||
base.TreatTcp(rea, tcpClient);
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
ReplyError(tcpClient, e, HttpStatusCode.NotImplemented);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ReplyError(tcpClient, e, HttpStatusCode.BadRequest);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void TreatUdp(RequestEventArgs<HttpRequest, HttpResponse> rea, System.Net.IPEndPoint client)
|
||||
{
|
||||
try
|
||||
{
|
||||
base.TreatUdp(rea, client);
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
ReplyError(client, e, HttpStatusCode.NotImplemented);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ReplyError(client, e, HttpStatusCode.BadRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReplyError(TcpClient ep, Exception e, HttpStatusCode code)
|
||||
{
|
||||
HttpResponse response = new HttpResponse();
|
||||
StreamWriter sw = new StreamWriter(response.Body);
|
||||
sw.Write(e.ToString());
|
||||
response.ResponseCode = HttpStatusCode.NotImplemented;
|
||||
response.ResponseMessage = e.Message;
|
||||
Send(response, ep);
|
||||
}
|
||||
|
||||
private void ReplyError(IPEndPoint ep, Exception e, HttpStatusCode code)
|
||||
{
|
||||
HttpResponse response = new HttpResponse();
|
||||
StreamWriter sw = new StreamWriter(response.Body);
|
||||
sw.Write(e.ToString());
|
||||
response.ResponseCode = HttpStatusCode.NotImplemented;
|
||||
response.ResponseMessage = e.Message;
|
||||
Send(response, ep);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
|
Binary file not shown.
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{61DB9D8D-F2EA-40DC-8F37-58092891A6A5}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Network.Tests</RootNamespace>
|
||||
<AssemblyName>Network.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Network.Rest\Network.Rest.csproj">
|
||||
<Project>{13A68F9C-F095-409E-A97D-A05FFCDCE210}</Project>
|
||||
<Name>Network.Rest</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Network.Rest;
|
||||
using System.Threading;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.Tests
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
RestServer server = new RestServer(IPAddress.Parse("224.0.0.224"), 53186);
|
||||
server.RequestReceived += new EventHandler<RequestEventArgs<HttpRequest, HttpResponse>>(server_RequestReceived);
|
||||
server.HttpRequestReceived += new EventHandler<HttpRequestEventArgs>(server_HttpRequestReceived);
|
||||
server.StartUdp();
|
||||
Console.WriteLine("Server Started");
|
||||
//HttpRequest request = new HttpRequest("http://224.0.0.224:53186/Lucene/");
|
||||
//request.Protocol = TransportProtocol.UDP;
|
||||
//request.GetResponse(false);
|
||||
//Thread.Sleep(1000);
|
||||
//request = new HttpRequest("http://224.0.0.224:53186/Lucene/");
|
||||
//request.Protocol = TransportProtocol.UDP;
|
||||
//request.GetResponse(false);
|
||||
//Thread.Sleep(10000);
|
||||
//request = new HttpRequest("http://224.0.0.224:53186/Lucene/");
|
||||
//request.Protocol = TransportProtocol.UDP;
|
||||
//request.GetResponse(false);
|
||||
//Thread.Sleep(30000);
|
||||
//request = new HttpRequest("http://224.0.0.224:53186/Lucene/");
|
||||
//request.Protocol = TransportProtocol.UDP;
|
||||
//request.GetResponse(false);
|
||||
Console.Read();
|
||||
server.Stop();
|
||||
Console.WriteLine("Server Stopped");
|
||||
}
|
||||
|
||||
static void server_HttpRequestReceived(object sender, HttpRequestEventArgs e)
|
||||
{
|
||||
server_RequestReceived(sender, e);
|
||||
Console.WriteLine(e.Request.ToString());
|
||||
}
|
||||
|
||||
static void server_RequestReceived(object sender, RequestEventArgs<HttpRequest, HttpResponse> e)
|
||||
{
|
||||
Console.WriteLine("Request received from " + e.Host);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Network.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Network.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("152caa80-1b00-422a-b3d0-a9fa4767c124")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
public class BinaryRequest : IRequest<BinaryRequest>
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
|
||||
#region IRequest<BinaryRequest> Members
|
||||
|
||||
public BinaryRequest GetRequest(BinaryReader stream)
|
||||
{
|
||||
BinaryRequest request = new BinaryRequest();
|
||||
byte[] buffer = new byte[1024];
|
||||
int length = buffer.Length;
|
||||
while (length > 0)
|
||||
{
|
||||
length = stream.Read(buffer, 0, buffer.Length);
|
||||
request.stream.Write(buffer, 0, length);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
public void WriteTo(System.IO.Stream stream)
|
||||
{
|
||||
this.stream.WriteTo(stream);
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IRequest<BinaryRequest> Members
|
||||
|
||||
|
||||
public BinaryRequest GetRequest(byte[] requestBytes)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream(requestBytes))
|
||||
{
|
||||
return GetRequest(new BinaryReader(stream));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
public class BinaryResponse : IResponse
|
||||
{
|
||||
private MemoryStream stream;
|
||||
|
||||
public BinaryResponse()
|
||||
{
|
||||
stream = new MemoryStream();
|
||||
}
|
||||
|
||||
#region IResponse Members
|
||||
|
||||
public void WriteTo(BinaryWriter target)
|
||||
{
|
||||
this.stream.Position = 0;
|
||||
this.stream.WriteTo(target.BaseStream);
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class BinaryHelper
|
||||
{
|
||||
public static byte[] GetBytes(IResponse response)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
response.WriteTo(new BinaryWriter(stream));
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
public abstract class Command<RequestEventArgsType, RequestType, ResponseType>
|
||||
where RequestEventArgsType : RequestEventArgs<RequestType, ResponseType>
|
||||
where ResponseType : IResponse
|
||||
{
|
||||
public Command()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public abstract Command<RequestEventArgsType, RequestType, ResponseType> Initialize(RequestType request, IServiceProvider server);
|
||||
|
||||
protected abstract RequestType BuildRequest();
|
||||
|
||||
public virtual ResponseType GetResponse()
|
||||
{
|
||||
return GetResponse(true);
|
||||
}
|
||||
|
||||
public abstract ResponseType GetResponse(bool expectResponse);
|
||||
|
||||
public abstract void Execute(RequestEventArgsType e);
|
||||
}
|
||||
|
||||
public abstract class Command<RequestType, ResponseType> :
|
||||
Command<RequestEventArgs<RequestType, ResponseType>, RequestType, ResponseType>
|
||||
where ResponseType : IResponse
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class CommandDescriptorAttribute : Attribute
|
||||
{
|
||||
public string Method { get; set; }
|
||||
public string UriRegex { get; set; }
|
||||
|
||||
public CommandDescriptorAttribute(string method)
|
||||
: base()
|
||||
{
|
||||
Method = method;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public abstract class CommandFactory<EventArgs, RequestType, ResponseType>
|
||||
where EventArgs : RequestEventArgs<RequestType, ResponseType>
|
||||
where ResponseType : IResponse
|
||||
where RequestType : IRequest<RequestType>, new()
|
||||
{
|
||||
protected IDictionary<string, IDictionary<Regex, Type>> registeredCommands = new Dictionary<string, IDictionary<Regex, Type>>();
|
||||
|
||||
public void RegisterCommand<T>()
|
||||
where T : Command<EventArgs, RequestType, ResponseType>
|
||||
{
|
||||
foreach (CommandDescriptorAttribute attribute in typeof(T).GetCustomAttributes(typeof(CommandDescriptorAttribute), true))
|
||||
{
|
||||
IDictionary<Regex, Type> dict;
|
||||
if (!registeredCommands.ContainsKey(attribute.Method))
|
||||
{
|
||||
dict = new Dictionary<Regex, Type>();
|
||||
registeredCommands.Add(attribute.Method, dict);
|
||||
}
|
||||
else
|
||||
dict = registeredCommands[attribute.Method];
|
||||
if (string.IsNullOrEmpty(attribute.UriRegex))
|
||||
dict.Add(new Regex("^/.*"), typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
public Command<EventArgs, RequestType, ResponseType> GetCommand(RequestType request, IServiceProvider server)
|
||||
{
|
||||
Command<EventArgs, RequestType, ResponseType> cmd = GetCommandInternal(request);
|
||||
return cmd.Initialize(request, server);
|
||||
//return cmd;
|
||||
}
|
||||
|
||||
protected internal abstract Command<EventArgs, RequestType, ResponseType> GetCommandInternal(RequestType request);
|
||||
|
||||
public T GetCommand<T>(RequestType request, IServiceProvider server)
|
||||
where T : Command<RequestEventArgs<RequestType, ResponseType>, RequestType, ResponseType>
|
||||
{
|
||||
return GetCommand(request, server) as T;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
public interface IRequest<RequestType>
|
||||
{
|
||||
RequestType GetRequest(BinaryReader stream);
|
||||
RequestType GetRequest(byte[] requestBytes);
|
||||
//void WriteTo(Stream stream);
|
||||
byte[] GetBytes();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
public interface IResponse
|
||||
{
|
||||
void WriteTo(BinaryWriter writer);
|
||||
byte[] GetBytes();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Network</RootNamespace>
|
||||
<AssemblyName>Network</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\Network.Rest\rest.snk</AssemblyOriginatorKeyFile>
|
||||
<TargetFrameworkSubset>
|
||||
</TargetFrameworkSubset>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BinaryRequest.cs" />
|
||||
<Compile Include="BinaryResponse.cs" />
|
||||
<Compile Include="Command.cs" />
|
||||
<Compile Include="CommandDescriptor.cs" />
|
||||
<Compile Include="CommandFactory.cs" />
|
||||
<Compile Include="IRequest.cs" />
|
||||
<Compile Include="IResponse.cs" />
|
||||
<Compile Include="RequestEventArgs.cs" />
|
||||
<Compile Include="Server.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\Network.Rest\rest.snk">
|
||||
<Link>rest.snk</Link>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Network")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Network")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("1b8150fa-dc0c-4962-a6a5-1e6ebe19847f")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
public class RequestEventArgs : RequestEventArgs<BinaryRequest, BinaryResponse>
|
||||
{
|
||||
}
|
||||
|
||||
public class RequestEventArgs<RequestType, ResponseType> : EventArgs
|
||||
where ResponseType : IResponse
|
||||
{
|
||||
public RequestEventArgs()
|
||||
{
|
||||
//Response = new HttpResponse();
|
||||
}
|
||||
|
||||
public RequestType Request { get; set; }
|
||||
public ResponseType Response { get; set; }
|
||||
|
||||
public virtual IPEndPoint Host { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Collections;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
public abstract class Server<TRequest, TResponse> : IServiceProvider
|
||||
where TResponse : IResponse
|
||||
where TRequest : IRequest<TRequest>, new()
|
||||
{
|
||||
public Server(ushort port)
|
||||
: this(IPAddress.Any, port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Server(IPAddress address, ushort port)
|
||||
: this(new IPEndPoint(address, port))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Server(IPEndPoint host)
|
||||
{
|
||||
Host = host;
|
||||
}
|
||||
|
||||
public IPEndPoint Host { get; protected set; }
|
||||
|
||||
protected TcpListener tcp;
|
||||
protected UdpClient udp;
|
||||
|
||||
public bool IsTcp { get; set; }
|
||||
public bool IsUdp { get; set; }
|
||||
public bool IsStarted { get; set; }
|
||||
|
||||
#region Start
|
||||
|
||||
public void StartTcp()
|
||||
{
|
||||
tcp = new TcpListener(Host);
|
||||
tcp.Start();
|
||||
tcp.BeginAcceptTcpClient(ReceiveTcpRequest, null);
|
||||
OnStart();
|
||||
IsStarted = true;
|
||||
}
|
||||
|
||||
public void StartUdp()
|
||||
{
|
||||
if (IsStarted)
|
||||
throw new NotSupportedException("You cannot start the server twice");
|
||||
if (!IsMulticast(Host.Address))
|
||||
udp = new UdpClient(Host);
|
||||
else
|
||||
{
|
||||
udp = new UdpClient(Host.Port);
|
||||
udp.JoinMulticastGroup(Host.Address, 5);
|
||||
udp.BeginReceive(ReceiveUdpRequest, null);
|
||||
OnStart();
|
||||
IsStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public event EventHandler Started;
|
||||
public event EventHandler Stopped;
|
||||
public event EventHandler<RequestEventArgs<TRequest, TResponse>> RequestReceived;
|
||||
|
||||
protected abstract RequestEventArgs<TRequest, TResponse> GetEventArgs(TRequest request);
|
||||
|
||||
private void ReceiveTcpRequest(IAsyncResult result)
|
||||
{
|
||||
|
||||
TcpClient tcpClient = tcp.EndAcceptTcpClient(result);
|
||||
if (IsStarted)
|
||||
tcp.BeginAcceptTcpClient(ReceiveTcpRequest, null);
|
||||
RequestEventArgs<TRequest, TResponse> rea = GetEventArgs(new TRequest().GetRequest(new BinaryReader(tcpClient.GetStream())));
|
||||
rea.Host = (IPEndPoint)tcpClient.Client.RemoteEndPoint;
|
||||
TreatTcp(rea, tcpClient);
|
||||
}
|
||||
|
||||
protected virtual void TreatTcp(RequestEventArgs<TRequest, TResponse> rea, TcpClient tcpClient)
|
||||
{
|
||||
OnRequestReceived(rea);
|
||||
if (rea.Response != null)
|
||||
Send(rea.Response, tcpClient);
|
||||
}
|
||||
|
||||
protected virtual void TreatUdp(RequestEventArgs<TRequest, TResponse> rea, IPEndPoint client)
|
||||
{
|
||||
OnRequestReceived(rea);
|
||||
if (rea.Response != null)
|
||||
Send(rea.Response, client);
|
||||
}
|
||||
|
||||
private void ReceiveUdpRequest(IAsyncResult result)
|
||||
{
|
||||
IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
|
||||
byte[] requestBytes;
|
||||
try
|
||||
{
|
||||
requestBytes = udp.EndReceive(result, ref remote);
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (e.ErrorCode == (int)SocketError.ConnectionAborted || e.ErrorCode == (int)SocketError.ConnectionReset)
|
||||
return;
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (IsStarted)
|
||||
udp.BeginReceive(ReceiveUdpRequest, null);
|
||||
}
|
||||
if (requestBytes == null)
|
||||
return;
|
||||
RequestEventArgs<TRequest, TResponse> rea = GetEventArgs(new TRequest().GetRequest(requestBytes));
|
||||
rea.Host = remote;
|
||||
TreatUdp(rea, remote);
|
||||
}
|
||||
|
||||
protected void Send(TResponse response, TcpClient tcpClient)
|
||||
{
|
||||
response.WriteTo(new BinaryWriter(tcpClient.GetStream()));
|
||||
}
|
||||
|
||||
protected void Send(TResponse response, IPEndPoint remote)
|
||||
{
|
||||
byte[] responseBytes = response.GetBytes();
|
||||
udp.Send(responseBytes, responseBytes.Length, remote);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (IsStarted)
|
||||
{
|
||||
if (IsTcp)
|
||||
tcp.Stop();
|
||||
if (IsUdp)
|
||||
udp.Close();
|
||||
OnStop();
|
||||
IsStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
Stop();
|
||||
if (IsTcp)
|
||||
StartTcp();
|
||||
if (IsUdp)
|
||||
StartUdp();
|
||||
}
|
||||
|
||||
protected virtual void OnStart()
|
||||
{
|
||||
if (Started != null)
|
||||
Started(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnStop()
|
||||
{
|
||||
if (Stopped != null)
|
||||
Stopped(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnRequestReceived(RequestEventArgs<TRequest, TResponse> rea)
|
||||
{
|
||||
if (RequestReceived != null)
|
||||
RequestReceived(this, rea);
|
||||
}
|
||||
|
||||
protected bool IsMulticast(IPAddress hostAddress)
|
||||
{
|
||||
if (hostAddress.IsIPv6Multicast)
|
||||
return true;
|
||||
byte[] addressBytes = hostAddress.GetAddressBytes();
|
||||
if (addressBytes[0] >= 224 && addressBytes[0] <= 239)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected IDictionary<Type, object> services = new Dictionary<Type, object>();
|
||||
|
||||
#region IServiceProvider Members
|
||||
|
||||
public object GetService(Type serviceType)
|
||||
{
|
||||
return services[serviceType];
|
||||
}
|
||||
|
||||
public T GetService<T>()
|
||||
{
|
||||
return (T)GetService(typeof(T));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>Services.NET</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -52,6 +56,10 @@
|
|||
<Project>{36528547-53DC-46CD-8C97-1BAE69262B00}</Project>
|
||||
<Name>Network.Dns</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>UPnP</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -56,10 +60,14 @@
|
|||
<Project>{36528547-53DC-46CD-8C97-1BAE69262B00}</Project>
|
||||
<Name>Network.Dns</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Rest\Network.Rest.csproj">
|
||||
<Project>{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}</Project>
|
||||
<ProjectReference Include="..\Network.Rest\Network.Rest.csproj">
|
||||
<Project>{13A68F9C-F095-409E-A97D-A05FFCDCE210}</Project>
|
||||
<Name>Network.Rest</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SD\Network.ZeroConf.csproj">
|
||||
<Project>{2B2D41E0-DBC7-4075-873C-394D02448281}</Project>
|
||||
<Name>Network.ZeroConf</Name>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -83,7 +83,7 @@ namespace Network.UPnP
|
|||
|
||||
protected void TreatQuery(byte[] bytes)
|
||||
{
|
||||
HttpRequest request = HttpRequest.FromBytes(bytes);
|
||||
HttpRequest request = new HttpRequest().GetRequest(bytes);
|
||||
if (QueryReceived != null)
|
||||
QueryReceived(request);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>UPnPReader</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -49,10 +53,14 @@
|
|||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Rest\Network.Rest.csproj">
|
||||
<Project>{3FFE9D8C-3914-4DD1-BB7C-8D4359216806}</Project>
|
||||
<ProjectReference Include="..\Network.Rest\Network.Rest.csproj">
|
||||
<Project>{13A68F9C-F095-409E-A97D-A05FFCDCE210}</Project>
|
||||
<Name>Network.Rest</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Network\Network.csproj">
|
||||
<Project>{C05DF064-DD81-49AE-91D2-9D8BBCC76F1F}</Project>
|
||||
<Name>Network %28Network\Network%29</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SD\Network.ZeroConf.csproj">
|
||||
<Project>{2B2D41E0-DBC7-4075-873C-394D02448281}</Project>
|
||||
<Name>Network.ZeroConf</Name>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
|
@ -12,6 +12,10 @@
|
|||
<AssemblyName>mDNSReader</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
Loading…
Reference in New Issue