- signed the Network.Rest Assembly
- corrected bugs on Bonjour - added a MEF Bonjour catalog (not found yet how a service could import someting, so a service can only be imported) - added a resolve with timeout in the service resolver interfacemaster
parent
d71c0b856d
commit
6e72f8a9c3
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><ItemProperties xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Properties><Property><Name>svn:mime-type</Name><Value>application/octet-stream</Value></Property></Properties></ItemProperties>
|
|
@ -17,6 +17,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network.Rest", "Rest\Networ
|
|||
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}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MEF.Bonjour.Tests", "MEF.Bonjour.Tests\MEF.Bonjour.Tests.csproj", "{770EE8FF-624F-445F-A6ED-B29E2DAFA591}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -55,6 +59,14 @@ Global
|
|||
{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
|
||||
{8BF16D75-B05B-48AF-A72D-5CDDC861DFD6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{94D114DE-DA48-4060-9B7A-3059BF75E87D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94D114DE-DA48-4060-9B7A-3059BF75E87D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94D114DE-DA48-4060-9B7A-3059BF75E87D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94D114DE-DA48-4060-9B7A-3059BF75E87D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{770EE8FF-624F-445F-A6ED-B29E2DAFA591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{770EE8FF-624F-445F-A6ED-B29E2DAFA591}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{770EE8FF-624F-445F-A6ED-B29E2DAFA591}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{770EE8FF-624F-445F-A6ED-B29E2DAFA591}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -18,7 +18,20 @@ namespace Network.Bonjour
|
|||
addresses = new List<Network.Dns.EndPoint>();
|
||||
}
|
||||
|
||||
public DomainName HostName { get; set; }
|
||||
private DomainName hostName;
|
||||
public DomainName HostName
|
||||
{
|
||||
get
|
||||
{
|
||||
return hostName;
|
||||
}
|
||||
set
|
||||
{
|
||||
hostName = value;
|
||||
if (value != null && needsToBeResolvedLater)
|
||||
Resolve();
|
||||
}
|
||||
}
|
||||
protected DateTime expiration;
|
||||
public State State { get; set; }
|
||||
public bool IsOutDated { get { return DateTime.Now > expiration; } }
|
||||
|
@ -32,12 +45,19 @@ namespace Network.Bonjour
|
|||
MDnsClient resolver;
|
||||
MDnsClient publisher;
|
||||
AutoResetEvent resolved = new AutoResetEvent(false);
|
||||
bool needsToBeResolvedLater = false;
|
||||
|
||||
public void Resolve()
|
||||
{
|
||||
if (resolver != null)
|
||||
resolver.Stop();
|
||||
|
||||
if (HostName == null)
|
||||
{
|
||||
needsToBeResolvedLater = true;
|
||||
return;
|
||||
}
|
||||
needsToBeResolvedLater = false;
|
||||
resolver = MDnsClient.CreateAndResolve(HostName);
|
||||
resolver.AnswerReceived += client_AnswerReceived;
|
||||
resolver.Start();
|
||||
|
@ -169,10 +189,10 @@ namespace Network.Bonjour
|
|||
foreach (Network.Dns.EndPoint ep in Addresses)
|
||||
{
|
||||
foreach (var address in ep.Addresses)
|
||||
m.Additionals.Add(new Answer() { Class = Class.IN, DomainName = HostName, Ttl = 120, 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 = 120, 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 = 120, Type = Network.Dns.Type.TXT, ResponseData = new Txt() { Properties = properties } });
|
||||
m.Authorities.Add(new Answer() { Class = Class.IN, DomainName = Protocol, Ttl = 120, Type = Network.Dns.Type.PTR, ResponseData = new Ptr() { DomainName = Name + "." + Protocol } });
|
||||
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);
|
||||
|
@ -299,5 +319,17 @@ namespace Network.Bonjour
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<KeyValuePair<string,string>> Members
|
||||
|
||||
public IEnumerable<KeyValuePair<string, string>> Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,10 +48,16 @@ namespace Network.Bonjour
|
|||
{
|
||||
client = MDnsClient.CreateAndResolve(protocol);
|
||||
client.AnswerReceived += client_AnswerReceived;
|
||||
client.Start();
|
||||
}
|
||||
else
|
||||
client.Resolve(protocol);
|
||||
if (!client.IsStarted)
|
||||
client.Start();
|
||||
}
|
||||
|
||||
public IList<IService> Resolve(string protocol, TimeSpan timeout, int minCountServices, int maxCountServices)
|
||||
{
|
||||
return new ResolverHelper().Resolve(this, protocol, timeout, minCountServices, maxCountServices);
|
||||
}
|
||||
|
||||
void client_AnswerReceived(Message m)
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using Network.Rest;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.UPnP.DLNA
|
||||
{
|
||||
|
@ -10,11 +11,11 @@ namespace Network.UPnP.DLNA
|
|||
{
|
||||
public Command(string connectionString) : base(connectionString) { }
|
||||
|
||||
protected override Network.Rest.HttpRequest BuildRequest()
|
||||
protected override HttpRequest BuildRequest()
|
||||
{
|
||||
HttpRequest request = base.BuildRequest();
|
||||
request.Headers["User-Agent"] = "Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)";
|
||||
request.Headers["Content-Type"] = "text/xml; charset=\"utf-8\"";
|
||||
request.ContentType = "text/xml; charset=\"utf-8\"";
|
||||
request.Headers["Connection"] = "Close";
|
||||
request.Headers["Cache-Control"] = "no-cache";
|
||||
request.Headers["Pragma"] = "no-cache";
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Text;
|
|||
using Network.Rest;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace DLNA.ContentDirectory
|
||||
{
|
||||
|
@ -12,6 +13,11 @@ namespace DLNA.ContentDirectory
|
|||
{
|
||||
public Browse(string connectionString) : base(connectionString) { }
|
||||
|
||||
public override void Initialize(HttpRequest request)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override HttpRequest GetRequest()
|
||||
{
|
||||
HttpRequest request = BuildRequest();
|
||||
|
@ -31,7 +37,7 @@ namespace DLNA.ContentDirectory
|
|||
new XElement(contentDirectory + "StartingIndex", new XAttribute(dt + "dt", "ui4"), "0"),
|
||||
new XElement(contentDirectory + "RequestedCount", new XAttribute(dt + "dt", "ui4"), "200"),
|
||||
new XElement(contentDirectory + "SortCriteria", new XAttribute(dt + "dt", "string"), "")))));
|
||||
request.Headers["Content-Length"] = (request.Body.Length).ToString();
|
||||
//request.Headers["Content-Length"] = (request.ContentType.Length).ToString();
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace Network.Dns
|
|||
bytes.AddRange(DomainName.ToBytes());
|
||||
bytes.AddRange(Message.ToBytes((ushort)Type));
|
||||
bytes.AddRange(Message.ToBytes((ushort)Class));
|
||||
//bytes.AddRange(Message.ToBytes((ushort)(((ushort)(ushort.MaxValue >> 15 << 15)) + (ushort)Class)));
|
||||
return bytes.ToArray();
|
||||
}
|
||||
|
||||
|
|
|
@ -103,8 +103,9 @@ namespace Network.Dns
|
|||
public override byte[] ToBytes()
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
bytes.AddRange(Message.ToBytes((ushort)4));
|
||||
bytes.AddRange(Address.GetAddressBytes());
|
||||
byte[] address = Address.GetAddressBytes();
|
||||
bytes.AddRange(Message.ToBytes((ushort)address.Length));
|
||||
bytes.AddRange(address);
|
||||
return bytes.ToArray();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<?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>{770EE8FF-624F-445F-A6ED-B29E2DAFA591}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MEF.Bonjour.Tests</RootNamespace>
|
||||
<AssemblyName>MEF.Bonjour.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<StartupObject>MEF.Bonjour.Tests.Program</StartupObject>
|
||||
</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.ComponentModel.Composition, Version=2009.1.23.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\bin\System.ComponentModel.Composition.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core">
|
||||
<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="..\Bonjour.NET\Network.Bonjour.csproj">
|
||||
<Project>{CA2E95A3-CF9D-4524-85FC-12CAD9D81479}</Project>
|
||||
<Name>Network.Bonjour</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MEF.Bonjour\MEF.Bonjour.csproj">
|
||||
<Project>{94D114DE-DA48-4060-9B7A-3059BF75E87D}</Project>
|
||||
<Name>MEF.Bonjour</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SD\Network.ZeroConf.csproj">
|
||||
<Project>{2B2D41E0-DBC7-4075-873C-394D02448281}</Project>
|
||||
<Name>Network.ZeroConf</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Network.ZeroConf;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
|
||||
namespace MEF.Bonjour.Tests
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
new Program().Run();
|
||||
}
|
||||
|
||||
[Import("_touch-able._tcp")]
|
||||
private IService service;
|
||||
|
||||
public void Run()
|
||||
{
|
||||
using (Catalog catalog = new Catalog())
|
||||
{
|
||||
CompositionContainer container = new CompositionContainer(catalog);
|
||||
CompositionBatch batch = new CompositionBatch();
|
||||
batch.AddPart(this);
|
||||
container.Compose(batch);
|
||||
Console.WriteLine(service.Name);
|
||||
//foreach (IService service in services)
|
||||
// Console.WriteLine(service.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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("MEF.Bonjour.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("MEF.Bonjour.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 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("57230306-094c-4477-a104-d1e08436e8b7")]
|
||||
|
||||
// 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,86 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.ComponentModel.Composition.Primitives;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
using Network.Bonjour;
|
||||
using Network.ZeroConf;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace MEF.Bonjour
|
||||
{
|
||||
public class Catalog : ComposablePartCatalog
|
||||
{
|
||||
public TimeSpan TimeOut { get; set; }
|
||||
|
||||
BonjourServiceResolver resolver = new BonjourServiceResolver();
|
||||
|
||||
public Catalog(TimeSpan timeOut)
|
||||
{
|
||||
resolver.ServiceFound += new Network.ZeroConf.ObjectEvent<Network.ZeroConf.IService>(resolver_ServiceFound);
|
||||
resolver.ServiceRemoved += new Network.ZeroConf.ObjectEvent<Network.ZeroConf.IService>(resolver_ServiceRemoved);
|
||||
TimeOut = timeOut;
|
||||
}
|
||||
|
||||
public Catalog()
|
||||
: this(new TimeSpan(0, 0, 30))
|
||||
{
|
||||
}
|
||||
|
||||
private IDictionary<IService, ServicePartDefinition> parts = new Dictionary<IService, ServicePartDefinition>();
|
||||
|
||||
void resolver_ServiceRemoved(Network.ZeroConf.IService item)
|
||||
{
|
||||
if (parts.ContainsKey(item))
|
||||
parts.Remove(item);
|
||||
}
|
||||
|
||||
void resolver_ServiceFound(Network.ZeroConf.IService item)
|
||||
{
|
||||
if (!parts.ContainsKey(item))
|
||||
parts.Add(item, new ServicePartDefinition(item));
|
||||
}
|
||||
|
||||
public override IEnumerable<TempTuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
|
||||
{
|
||||
LambdaExpression lambda = definition.Constraint;
|
||||
if (lambda.Body is BinaryExpression)
|
||||
{
|
||||
BinaryExpression binaryExpression = (BinaryExpression)lambda.Body;
|
||||
if (binaryExpression.Left is MemberExpression && ((MemberExpression)binaryExpression.Left).Member.Name == "ContractName")
|
||||
{
|
||||
IList<IService> services = resolver.Resolve((string)((ConstantExpression)binaryExpression.Right).Value, TimeOut, definition.Cardinality == ImportCardinality.ZeroOrOne ? 0 : 1, definition.Cardinality == ImportCardinality.ZeroOrMore ? int.MaxValue : 1);
|
||||
foreach (IService service in services)
|
||||
resolver_ServiceFound(service);
|
||||
}
|
||||
}
|
||||
var exports = new List<TempTuple<ComposablePartDefinition, ExportDefinition>>();
|
||||
foreach (var part in this.Parts.ToArray())
|
||||
{
|
||||
foreach (var export in part.ExportDefinitions)
|
||||
{
|
||||
if (definition.Constraint.Compile().Invoke(export))
|
||||
{
|
||||
exports.Add(new TempTuple<ComposablePartDefinition, ExportDefinition>(part, export));
|
||||
}
|
||||
}
|
||||
}
|
||||
return exports;
|
||||
}
|
||||
|
||||
public override System.Linq.IQueryable<ComposablePartDefinition> Parts
|
||||
{
|
||||
get { return parts.Values.AsQueryable().OfType<ComposablePartDefinition>(); }
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
resolver.ServiceFound -= resolver_ServiceFound;
|
||||
resolver.ServiceRemoved -= resolver_ServiceRemoved;
|
||||
if (disposing)
|
||||
resolver.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?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>{94D114DE-DA48-4060-9B7A-3059BF75E87D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MEF.Bonjour</RootNamespace>
|
||||
<AssemblyName>MEF.Bonjour</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</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.ComponentModel.Composition, Version=2009.1.23.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\bin\System.ComponentModel.Composition.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Catalog.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ServicePart.cs" />
|
||||
<Compile Include="ServicePartDefinition.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Bonjour.NET\Network.Bonjour.csproj">
|
||||
<Project>{CA2E95A3-CF9D-4524-85FC-12CAD9D81479}</Project>
|
||||
<Name>Network.Bonjour</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\DnsResolver\Network.Dns.csproj">
|
||||
<Project>{36528547-53DC-46CD-8C97-1BAE69262B00}</Project>
|
||||
<Name>Network.Dns</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SD\Network.ZeroConf.csproj">
|
||||
<Project>{2B2D41E0-DBC7-4075-873C-394D02448281}</Project>
|
||||
<Name>Network.ZeroConf</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -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("MEF.Bonjour")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("MEF.Bonjour")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 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("70f443ff-2ed4-4d49-8f25-d17616114d0b")]
|
||||
|
||||
// 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,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel.Composition.Primitives;
|
||||
using Network.Bonjour;
|
||||
using Network.ZeroConf;
|
||||
|
||||
namespace MEF.Bonjour
|
||||
{
|
||||
public class ServicePart : ComposablePart
|
||||
{
|
||||
IService service;
|
||||
|
||||
public ServicePart(IService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
|
||||
public override IEnumerable<ExportDefinition> ExportDefinitions
|
||||
{
|
||||
get { return ExportDefinition(service); }
|
||||
}
|
||||
|
||||
internal static IEnumerable<ExportDefinition> ExportDefinition(IService service)
|
||||
{
|
||||
Dictionary<string, object> properties = new Dictionary<string, object>();
|
||||
foreach (KeyValuePair<string, string> property in service.Properties)
|
||||
properties.Add(property.Key, property.Value);
|
||||
|
||||
if (service.Protocol.EndsWith("."))
|
||||
service.Protocol = service.Protocol.Substring(0, service.Protocol.Length - 1);
|
||||
if (service.Protocol.EndsWith(".local"))
|
||||
service.Protocol = service.Protocol.Substring(0, service.Protocol.Length - 6);
|
||||
string[] protocols = new string[] { service.Protocol, service.Protocol + ".", service.Protocol + ".local", service.Protocol + ".local." };
|
||||
foreach (string protocol in protocols)
|
||||
{
|
||||
ExportDefinition ed = new ExportDefinition(protocol, properties);
|
||||
yield return ed;
|
||||
}
|
||||
}
|
||||
|
||||
public override object GetExportedObject(ExportDefinition definition)
|
||||
{
|
||||
return service;
|
||||
}
|
||||
|
||||
public override IEnumerable<ImportDefinition> ImportDefinitions
|
||||
{
|
||||
get { return new ImportDefinition[] { }; }
|
||||
}
|
||||
|
||||
public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel.Composition.Primitives;
|
||||
using Network.ZeroConf;
|
||||
|
||||
namespace MEF.Bonjour
|
||||
{
|
||||
public class ServicePartDefinition : ComposablePartDefinition
|
||||
{
|
||||
IService service;
|
||||
|
||||
public ServicePartDefinition(IService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public override ComposablePart CreatePart()
|
||||
{
|
||||
return new ServicePart(service);
|
||||
}
|
||||
|
||||
public override IEnumerable<ExportDefinition> ExportDefinitions
|
||||
{
|
||||
get { return ServicePart.ExportDefinition(service); }
|
||||
}
|
||||
|
||||
public override IEnumerable<ImportDefinition> ImportDefinitions
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><ItemProperties xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Properties><Property><Name>svn:mime-type</Name><Value>application/octet-stream</Value></Property></Properties></ItemProperties>
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
|
@ -12,6 +13,12 @@ namespace Network.Rest
|
|||
Uri = new Uri(connectionString);
|
||||
}
|
||||
|
||||
public Command(HttpRequest request)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract void Initialize(HttpRequest request);
|
||||
|
||||
public Uri Uri { get; protected set; }
|
||||
|
||||
protected string Method { get; set; }
|
||||
|
@ -19,6 +26,8 @@ namespace Network.Rest
|
|||
protected virtual HttpRequest BuildRequest()
|
||||
{
|
||||
HttpRequest request = new HttpRequest(Uri);
|
||||
request.KeepAlive = true;
|
||||
request.ContentType = "text/xml";
|
||||
request.Method = Method;
|
||||
return request;
|
||||
}
|
||||
|
@ -28,12 +37,21 @@ namespace Network.Rest
|
|||
public virtual HttpResponse GetHttpResponse()
|
||||
{
|
||||
HttpRequest request = GetRequest();
|
||||
return request.GetResponse();
|
||||
return (HttpResponse)request.GetResponse();
|
||||
}
|
||||
|
||||
XmlDocument doc = new XmlDocument();
|
||||
bool docLoaded = false;
|
||||
|
||||
public XmlDocument GetResponse()
|
||||
{
|
||||
return GetHttpResponse().Document;
|
||||
if (!docLoaded)
|
||||
{
|
||||
HttpResponse response = GetHttpResponse();
|
||||
docLoaded = true;
|
||||
doc.Load(response.Body);
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class CommandFactory
|
||||
{
|
||||
private IDictionary<string, IDictionary<Regex, Type>> registeredCommands = new Dictionary<string, IDictionary<Regex, Type>>();
|
||||
|
||||
public void RegisterCommand<T>()
|
||||
where T : Command
|
||||
{
|
||||
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 GetCommand(HttpRequest request)
|
||||
{
|
||||
Command cmd = GetCommandInternal(request);
|
||||
cmd.Initialize(request);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
internal Command 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)Activator.CreateInstance(command.Value, request);
|
||||
}
|
||||
throw new NotSupportedException("No command have been registered for this kind of request");
|
||||
}
|
||||
|
||||
public T GetCommand<T>(HttpRequest request)
|
||||
where T : Command
|
||||
{
|
||||
return GetCommand(request) as T;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,19 @@ namespace Network.Rest
|
|||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -32,9 +32,36 @@ namespace Network.Rest
|
|||
request.Uri = firstLine[1];
|
||||
request.HttpVersion = HttpVersion.HTTP11;
|
||||
request.ReadHeaders(reader);
|
||||
request.Host = request.Host.Trim();
|
||||
return request;
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -77,12 +104,12 @@ namespace Network.Rest
|
|||
|
||||
public HttpResponse GetResponse()
|
||||
{
|
||||
Uri uri = new Uri("http://" + Host + Uri);
|
||||
if (Protocol == TransportProtocol.TCP)
|
||||
{
|
||||
TcpClient client = new TcpClient();
|
||||
Uri uri = new Uri(Uri);
|
||||
client.Connect(uri.Host, uri.Port != 0 ? uri.Port : 80);
|
||||
Uri = Uri.Substring(Uri.IndexOf('/', Uri.IndexOf(uri.Host)));
|
||||
//Uri = Uri.Substring(Uri.IndexOf('/', Uri.IndexOf(uri.Host)));
|
||||
byte[] requestBytes = GetBytes();
|
||||
Uri = uri.ToString();
|
||||
client.GetStream().Write(requestBytes, 0, requestBytes.Length);
|
||||
|
@ -99,12 +126,9 @@ namespace Network.Rest
|
|||
if (Protocol == TransportProtocol.UDP)
|
||||
{
|
||||
UdpClient client = new UdpClient();
|
||||
Uri uri = new Uri(Uri);
|
||||
client.Connect(uri.Host, uri.Port != 0 ? uri.Port : 80);
|
||||
byte[] requestBytes = GetBytes();
|
||||
client.Send(requestBytes, requestBytes.Length);
|
||||
byte[] responseBytes = new byte[client.Available - requestBytes.Length];
|
||||
MemoryStream stream = new MemoryStream();
|
||||
System.Net.IPEndPoint ep = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0);
|
||||
return HttpResponse.FromBytes(client.Receive(ref ep));
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Network.Rest
|
|||
{
|
||||
public HttpResponse()
|
||||
{
|
||||
ResponseCode = HttpStatusCode.OK;
|
||||
}
|
||||
|
||||
public static HttpResponse FromBytes(byte[] bytes)
|
||||
|
@ -50,8 +51,7 @@ namespace Network.Rest
|
|||
response.ResponseMessage = string.Join(" ", firstLine, 2, firstLine.Length - 2);
|
||||
response.ReadHeaders(reader);
|
||||
StreamWriter sw = new StreamWriter(response.Body);
|
||||
while (!string.IsNullOrEmpty(line = reader.ReadLine()))
|
||||
sw.WriteLine(line);
|
||||
sw.Write(reader.ReadToEnd());
|
||||
response.Body.Seek(0, SeekOrigin.Begin);
|
||||
return response;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,16 @@
|
|||
</StartupObject>
|
||||
<TargetFrameworkSubset>
|
||||
</TargetFrameworkSubset>
|
||||
<SccProjectName>
|
||||
</SccProjectName>
|
||||
<SccLocalPath>
|
||||
</SccLocalPath>
|
||||
<SccAuxPath>
|
||||
</SccAuxPath>
|
||||
<SccProvider>
|
||||
</SccProvider>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>rest.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -35,16 +45,26 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Microsoft.Build.Utilities" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Command.cs" />
|
||||
<Compile Include="CommandDescriptor.cs" />
|
||||
<Compile Include="CommandFactory.cs" />
|
||||
<Compile Include="HttpMessage.cs" />
|
||||
<Compile Include="HttpResponse.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="HttpRequest.cs" />
|
||||
<Compile Include="RestServer.cs" />
|
||||
<Compile Include="RestTask.cs" />
|
||||
<Compile Include="UdpRestServer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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.
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public abstract class RestServer
|
||||
{
|
||||
public ushort Port { get; private set; }
|
||||
|
||||
public RestServer(ushort port)
|
||||
{
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public bool IsStarted { get; private set; }
|
||||
|
||||
public event EventHandler Started;
|
||||
public event EventHandler Stopped;
|
||||
public event EventHandler<RequestEventArgs> RequestReceived;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
OnStart();
|
||||
IsStarted = true;
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
OnStop();
|
||||
IsStarted = false;
|
||||
}
|
||||
|
||||
protected virtual void OnStart()
|
||||
{
|
||||
if (Started != null)
|
||||
Started(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnStop()
|
||||
{
|
||||
if (Stopped != null)
|
||||
Stopped(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void OnRequestReceived(RequestEventArgs rea)
|
||||
{
|
||||
if (RequestReceived != null)
|
||||
RequestReceived(this, rea);
|
||||
}
|
||||
}
|
||||
|
||||
public class RequestEventArgs : EventArgs
|
||||
{
|
||||
public RequestEventArgs()
|
||||
{
|
||||
Response = new HttpResponse();
|
||||
}
|
||||
|
||||
public HttpRequest Request { get; set; }
|
||||
public HttpResponse Response { get; set; }
|
||||
|
||||
public IPEndPoint Host { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Microsoft.Build.Framework;
|
||||
using System.Net;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class RestTask : Task
|
||||
{
|
||||
public RestTask() { }
|
||||
|
||||
[Required]
|
||||
public string ConnectionString { get; set; }
|
||||
|
||||
public string Command { get; set; }
|
||||
|
||||
protected HttpResponse ExecuteRequest()
|
||||
{
|
||||
Command command = (Command)Activator.CreateInstance(Type.GetType(Command), ConnectionString);
|
||||
BuildCommand(command);
|
||||
return command.GetHttpResponse();
|
||||
}
|
||||
|
||||
protected virtual void BuildCommand(Command command)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
//return ExecuteRequest().ResponseCode == System.Net.HttpStatusCode.OK;
|
||||
try
|
||||
{
|
||||
ExecuteRequest();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
namespace Network.Rest
|
||||
{
|
||||
public class UdpRestServer : RestServer
|
||||
{
|
||||
public UdpClient client;
|
||||
|
||||
public UdpRestServer(ushort port)
|
||||
: base(port)
|
||||
{
|
||||
client = new UdpClient(port);
|
||||
}
|
||||
|
||||
public UdpRestServer(IPAddress hostAddress, ushort port)
|
||||
: base(port)
|
||||
{
|
||||
if (!IsMulticast(hostAddress))
|
||||
client = new UdpClient(new IPEndPoint(hostAddress, port));
|
||||
else
|
||||
{
|
||||
client = new UdpClient(port);
|
||||
client.JoinMulticastGroup(hostAddress);
|
||||
}
|
||||
}
|
||||
|
||||
private 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 override void OnStart()
|
||||
{
|
||||
client.BeginReceive(ReceiveRequest, null);
|
||||
base.OnStart();
|
||||
}
|
||||
|
||||
private void ReceiveRequest(IAsyncResult result)
|
||||
{
|
||||
RequestEventArgs rea = new RequestEventArgs();
|
||||
IPEndPoint ep = new IPEndPoint(IPAddress.Any, Port);
|
||||
byte[] requestBytes = client.EndReceive(result, ref ep);
|
||||
if (IsStarted)
|
||||
client.BeginReceive(ReceiveRequest, null);
|
||||
HttpRequest request = HttpRequest.FromBytes(requestBytes);
|
||||
rea.Request = request;
|
||||
rea.Host = ep;
|
||||
try
|
||||
{
|
||||
OnRequestReceived(rea);
|
||||
Reply(ep, rea.Response);
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
ReplyError(ep, e, HttpStatusCode.NotImplemented);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ReplyError(ep, e, HttpStatusCode.BadRequest);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
Reply(ep, response);
|
||||
}
|
||||
|
||||
private void Reply(IPEndPoint ep, HttpResponse response)
|
||||
{
|
||||
byte[] responseBytes = response.GetBytes();
|
||||
client.Send(responseBytes, responseBytes.Length, ep);
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Network.ZeroConf
|
||||
{
|
||||
|
@ -46,6 +47,11 @@ namespace Network.ZeroConf
|
|||
resolvers.ForEach(delegate(IServiceResolver resolver) { resolver.Resolve(protocol); });
|
||||
}
|
||||
|
||||
public IList<IService> Resolve(string protocol, TimeSpan timeout, int minCountServices, int maxCountServices)
|
||||
{
|
||||
return new ResolverHelper().Resolve(this, protocol, timeout, 0, 10);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
|
|
@ -7,11 +7,13 @@ namespace Network.ZeroConf
|
|||
{
|
||||
public interface IService : IExpirable
|
||||
{
|
||||
DomainName HostName { get; }
|
||||
DomainName HostName { get; set; }
|
||||
IList<EndPoint> Addresses { get; }
|
||||
void AddAddress(EndPoint ep);
|
||||
string Protocol { get; set; }
|
||||
string Name { get; set; }
|
||||
string this[string key] { get; set; }
|
||||
IEnumerable<KeyValuePair<string, string>> Properties { get; }
|
||||
State State { get; }
|
||||
bool IsOutDated { get; }
|
||||
void Publish();
|
||||
|
|
|
@ -12,5 +12,6 @@ namespace Network.ZeroConf
|
|||
event ObjectEvent<IService> ServiceFound;
|
||||
event ObjectEvent<IService> ServiceRemoved;
|
||||
void Resolve(string protocol);
|
||||
IList<IService> Resolve(string protocol, TimeSpan timeout, int minCountServices, int maxCountServices);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<Compile Include="IService.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="IServiceResolver.cs" />
|
||||
<Compile Include="ResolverHelper.cs" />
|
||||
<Compile Include="TtlCollection.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Network.ZeroConf
|
||||
{
|
||||
public class ResolverHelper
|
||||
{
|
||||
private ManualResetEvent syncLock = new ManualResetEvent(false);
|
||||
private IList<IService> services = new List<IService>();
|
||||
|
||||
public IList<IService> Resolve(IServiceResolver resolver, string protocol, TimeSpan timeout, int minServiceCountFound, int maxServiceCountFound)
|
||||
{
|
||||
resolver.ServiceFound += new ObjectEvent<IService>(resolver_ServiceFound);
|
||||
resolver.ServiceRemoved += new ObjectEvent<IService>(resolver_ServiceRemoved);
|
||||
resolver.Resolve(protocol);
|
||||
for (int i = minServiceCountFound; i <= maxServiceCountFound; i++)
|
||||
syncLock.WaitOne(timeout);
|
||||
resolver.ServiceFound -= resolver_ServiceFound;
|
||||
resolver.ServiceRemoved -= resolver_ServiceRemoved;
|
||||
return services;
|
||||
}
|
||||
|
||||
void resolver_ServiceRemoved(IService item)
|
||||
{
|
||||
services.Remove(item);
|
||||
}
|
||||
|
||||
void resolver_ServiceFound(IService item)
|
||||
{
|
||||
services.Add(item);
|
||||
syncLock.Set();
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -20,7 +20,9 @@ namespace Network.UPnP
|
|||
|
||||
public Network.Dns.DomainName HostName { get; set; }
|
||||
|
||||
public IList<Network.Dns.EndPoint> Addresses { get; set; }
|
||||
public IList<Network.Dns.EndPoint> Addresses { get; private set; }
|
||||
|
||||
public void AddAddress(Network.Dns.EndPoint ep) { Addresses.Add(ep); }
|
||||
|
||||
public string Protocol
|
||||
{
|
||||
|
@ -39,7 +41,7 @@ namespace Network.UPnP
|
|||
get
|
||||
{
|
||||
//if (properties.ContainsKey(key))
|
||||
return properties[key];
|
||||
return properties[key];
|
||||
//return Txt.False;
|
||||
}
|
||||
set
|
||||
|
@ -193,5 +195,17 @@ namespace Network.UPnP
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<KeyValuePair<string,string>> Members
|
||||
|
||||
public IEnumerable<KeyValuePair<string, string>> Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,5 +94,15 @@ namespace Network.UPnP
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IServiceResolver Members
|
||||
|
||||
|
||||
public IList<IService> Resolve(string protocol, TimeSpan timeout, int minCountServices, int maxCountServices)
|
||||
{
|
||||
return new ResolverHelper().Resolve(this, protocol, timeout, minCountServices, maxCountServices);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,24 +13,24 @@ namespace mDNSReader
|
|||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
//BonjourServiceResolver bsr = new BonjourServiceResolver();
|
||||
//bsr.ServiceFound += new Network.ZeroConf.ObjectEvent<Network.ZeroConf.IService>(bsr_ServiceFound);
|
||||
//bsr.Resolve("_http._tcp.");
|
||||
|
||||
Service s = new Service();
|
||||
s.AddAddress(new Network.Dns.EndPoint() { DomainName = "ASPERGE.local.", Port = 50508, Addresses = new List<IPAddress>() { IPAddress.Parse("192.168.1.19") } });
|
||||
s.Protocol = "_touch-remote._tcp.local.";
|
||||
s.Name = "MyName";
|
||||
s.HostName = "ASPERGE.local.";
|
||||
s["DvNm"] = "PC Remote";
|
||||
s["RemV"] = "10000";
|
||||
s["DvTy"] = "iPod";
|
||||
s["RemN"] = "Remote";
|
||||
s["txtvers"] = "1";
|
||||
s["Pair"] = "0000000000000001";
|
||||
s.Publish();
|
||||
Thread.Sleep(3600000);
|
||||
s.Stop();
|
||||
BonjourServiceResolver bsr = new BonjourServiceResolver();
|
||||
bsr.ServiceFound += new Network.ZeroConf.ObjectEvent<Network.ZeroConf.IService>(bsr_ServiceFound);
|
||||
bsr.Resolve("_touch-able._tcp.");
|
||||
Console.ReadLine();
|
||||
//Service s = new Service();
|
||||
//s.AddAddress(new Network.Dns.EndPoint() { DomainName = "ASPERGE.local.", Port = 50508, Addresses = new List<IPAddress>() { IPAddress.Parse("192.168.1.19") } });
|
||||
//s.Protocol = "_touch-remote._tcp.local.";
|
||||
//s.Name = "MyName";
|
||||
//s.HostName = "ASPERGE.local.";
|
||||
//s["DvNm"] = "PC Remote";
|
||||
//s["RemV"] = "10000";
|
||||
//s["DvTy"] = "iPod";
|
||||
//s["RemN"] = "Remote";
|
||||
//s["txtvers"] = "1";
|
||||
//s["Pair"] = "0000000000000001";
|
||||
//s.Publish();
|
||||
//Thread.Sleep(3600000);
|
||||
//s.Stop();
|
||||
}
|
||||
|
||||
static void bsr_ServiceFound(Network.ZeroConf.IService item)
|
||||
|
|
Loading…
Reference in New Issue