Remove netcf
This commit is contained in:
Родитель
51eb827180
Коммит
31a5327af5
|
@ -1,6 +1,6 @@
|
|||
# AMQP.Net Lite
|
||||
|
||||
AMQP.Net Lite is a lightweight AMQP 1.0 library for the .Net Micro Framework, .Net Compact Framework, .Net Framework, .Net Core, Windows Runtime platforms, and Mono. The library includes both a client and listener to enable peer to peer and broker based messaging.
|
||||
AMQP.Net Lite is a lightweight AMQP 1.0 library for the .Net Micro Framework, .Net Framework, .Net Core, Windows Runtime platforms, and Mono. The library includes both a client and listener to enable peer to peer and broker based messaging.
|
||||
[Documentation](http://azure.github.io/amqpnetlite/)
|
||||
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/dph11pp7doubyw7t/branch/master?svg=true)](https://ci.appveyor.com/project/xinchen10/amqpnetlite/branch/master)
|
||||
|
@ -30,7 +30,6 @@ The following table shows what features are supported on each platform/framework
|
|||
|net40 |+|+|+|+<sup>3</sup>|+|+| |+|
|
||||
|net35 |+|+| | |+| | | |
|
||||
|netmf |+<sup>1</sup>|+| | | | | | |
|
||||
|netcf |+|+| | | | | | |
|
||||
|uap10|+|+| |+| | | | |
|
||||
|netcore451|+|+| |+| | | | |
|
||||
|wpa81 |+|+| |+| | | | |
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# Prerequisites
|
||||
* Visual Studio 2013. [Community Edition](https://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx) works.
|
||||
* NETMF SDK (4.2 and 4.3) and Visual Studio project system. You can build fro [sources](https://github.com/NETMF/netmf-interpreter) or download them from the old [netmf web site](https://netmf.codeplex.com).
|
||||
* Application Builder for Windows Embedded Compact 2013. To build .Net Compact Framework projects, you need to download [Application Builder for Windows Embedded Compact 2013](http://www.microsoft.com/en-us/download/details.aspx?id=38819)
|
||||
* NuGet tools if you want to build the NuGet package.
|
||||
|
||||
# Build the projects
|
||||
|
@ -13,7 +12,6 @@
|
|||
* The solution has a test broker which can be used to run tests. It can be started by running the following command. Note that the value of the "/cert" option is the subject name or the thumbprint of the service certificate that is already installed on the machine.
|
||||
`TestAmqpBroker.exe amqp://localhost:5672 amqps://localhost:5671 ws://localhost:80 /creds:guest:guest /cert:localhost`
|
||||
* NETMF tests are in project Test.Amqp.NetMF42/43. It is a NETMF application that runs in the emulator or a real device. It executes all methods whose names begin with "TestMethod_".
|
||||
* Test.Amqp.NetCF39 project can be run in a .Net Compact Framework environment. You can try it on a VirtualPC virtual machine created using Platform Builder also with the related SDK. If you have a real device, you need an SDK for it too.
|
||||
|
||||
# Start building applications
|
||||
* First take a look at the example projects under the Examples directory. The examples are working code against the Azure Service Bus service or other AMQP 1.0 compliant brokers.
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
// ------------------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ""License""); you may not use this
|
||||
// file except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR
|
||||
// CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
|
||||
// NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
||||
namespace Amqp
|
||||
{
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// Provides framework specific routines.
|
||||
/// </summary>
|
||||
public static class Fx
|
||||
{
|
||||
/// <summary>
|
||||
/// Asserts a condition is true.
|
||||
/// </summary>
|
||||
/// <param name="condition">A boolean value indicating the condition.</param>
|
||||
/// <param name="message">The error message if condition is not met.</param>
|
||||
[Conditional("DEBUG")]
|
||||
public static void Assert(bool condition, string message)
|
||||
{
|
||||
Debug.Assert(condition, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a string from a format and an array of arguments.
|
||||
/// </summary>
|
||||
/// <param name="format">The format string.</param>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns></returns>
|
||||
public static string Format(string format, params object[] args)
|
||||
{
|
||||
return string.Format(format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new thread.
|
||||
/// </summary>
|
||||
/// <param name="threadStart">The thread start callback.</param>
|
||||
public static void StartThread(ThreadStart threadStart)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(
|
||||
o => { ((ThreadStart)o)(); },
|
||||
threadStart);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,245 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34003
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Amqp {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class SRAmqp {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal SRAmqp() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Amqp.SRAmqp", typeof(SRAmqp).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The session channel '{0}' cannot be found..
|
||||
/// </summary>
|
||||
internal static string AmqpChannelNotFound {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpChannelNotFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cannot allocate more handles. The maximum number of handles is {0}..
|
||||
/// </summary>
|
||||
internal static string AmqpHandleExceeded {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpHandleExceeded", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The handle '{0}' is already allocated for '{1}'..
|
||||
/// </summary>
|
||||
internal static string AmqpHandleInUse
|
||||
{
|
||||
get
|
||||
{
|
||||
return ResourceManager.GetString("AmqpHandleInUse", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The link handle '{0}' cannot be found in session '{1}'..
|
||||
/// </summary>
|
||||
internal static string AmqpHandleNotFound {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpHandleNotFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Operation '{0}' is not valid under state: {1}..
|
||||
/// </summary>
|
||||
internal static string AmqpIllegalOperationState {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpIllegalOperationState", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The format code '{0}' at frame buffer offset '{1}' is invalid (expected: {2})..
|
||||
/// </summary>
|
||||
internal static string AmqpInvalidFormatCode {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpInvalidFormatCode", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} is not supported over AMQP..
|
||||
/// </summary>
|
||||
internal static string AmqpOperationNotSupported {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpOperationNotSupported", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The operation {0} did not complete within the allocated time {1} for object {2}..
|
||||
/// </summary>
|
||||
internal static string AmqpTimeout {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpTimeout", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The descriptor {0} is unknown..
|
||||
/// </summary>
|
||||
internal static string AmqpUnknownDescriptor {
|
||||
get {
|
||||
return ResourceManager.GetString("AmqpUnknownDescriptor", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to There is no credit to accept a new delivery (id={0}) on the link..
|
||||
/// </summary>
|
||||
internal static string DeliveryLimitExceeded {
|
||||
get {
|
||||
return ResourceManager.GetString("DeliveryLimitExceeded", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The type '{0}' is not a valid AMQP type and cannot be encoded..
|
||||
/// </summary>
|
||||
internal static string EncodingTypeNotSupported {
|
||||
get {
|
||||
return ResourceManager.GetString("EncodingTypeNotSupported", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The address is not correctly formatted..
|
||||
/// </summary>
|
||||
internal static string InvalidAddressFormat {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidAddressFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to transfer.delivery-id {0} is invalid (expect: {1}).
|
||||
/// </summary>
|
||||
internal static string InvalidDeliveryIdOnTransfer {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidDeliveryIdOnTransfer", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid frame size:{0}, maximum frame size:{1}..
|
||||
/// </summary>
|
||||
internal static string InvalidFrameSize {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidFrameSize", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The map count {0} is invalid. It must be an even number..
|
||||
/// </summary>
|
||||
internal static string InvalidMapCount {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidMapCount", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The key type {0} is invalid. The map key is restricted to {1}..
|
||||
/// </summary>
|
||||
internal static string InvalidMapKeyType {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidMapKeyType", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Comparison of {0} and {1} is invalid because the result is undefined..
|
||||
/// </summary>
|
||||
internal static string InvalidSequenceNumberComparison {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidSequenceNumberComparison", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The link name {0} in the received attach cannot be found..
|
||||
/// </summary>
|
||||
internal static string LinkNotFound {
|
||||
get {
|
||||
return ResourceManager.GetString("LinkNotFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Sasl negotiation failed with code {0}..
|
||||
/// </summary>
|
||||
internal static string SaslNegoFailed {
|
||||
get {
|
||||
return ResourceManager.GetString("SaslNegoFailed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to There is no window to accept an incoming transfer (incoming-id={0})..
|
||||
/// </summary>
|
||||
internal static string WindowViolation {
|
||||
get {
|
||||
return ResourceManager.GetString("WindowViolation", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,413 +0,0 @@
|
|||
// ------------------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ""License""); you may not use this
|
||||
// file except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR
|
||||
// CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
|
||||
// NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amqp
|
||||
{
|
||||
/// <summary>
|
||||
/// Delagate for user certificate validatin callback
|
||||
/// </summary>
|
||||
/// <param name="sender">Object sender (SslSocket instance)</param>
|
||||
/// <param name="certificate">X509 certificate</param>
|
||||
/// <param name="sslPolicyErrors">Internal validation error</param>
|
||||
/// <returns>Certificate status (valid or not)</returns>
|
||||
public delegate bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, SslPolicyErrors sslPolicyErrors);
|
||||
|
||||
class SslSocket : ITransport, IDisposable
|
||||
{
|
||||
#region P/Invoke constants define ...
|
||||
|
||||
// reference : winsock2.h in the SDK
|
||||
|
||||
// in/out parameter for ioctlsocket() -> WSAIoctl() in winsock
|
||||
private const uint IOC_VOID = 0x20000000; // no parameters
|
||||
private const uint IOC_OUT = 0x40000000; // copy out parameters
|
||||
private const uint IOC_IN = 0x80000000; // copy in parameters
|
||||
private const uint IOC_INOUT = (IOC_IN | IOC_OUT);
|
||||
|
||||
// reference : sslsock.h in the SDK
|
||||
|
||||
// options and option values for creating a secure socket
|
||||
private const ushort SO_SECURE = 0x2001; // add security to socket
|
||||
private const ushort SO_SEC_NONE = 0x2002; // security not used on socket
|
||||
private const ushort SO_SEC_SSL = 0x2004; // use unified SSL/PCT for security
|
||||
|
||||
// SSL WSAIoctl control code tags
|
||||
// NOTE : in managed code we have related Socket.IOControl() method
|
||||
|
||||
private const int SO_SSL_FAMILY = 0x00730000;
|
||||
private const int SO_SSL_FAMILY_MASK = 0x07ff0000;
|
||||
|
||||
private const long _SO_SSL = ((2L << 27) | SO_SSL_FAMILY);
|
||||
|
||||
// base SSL WSAIoctl tags
|
||||
private const int _SO_SSL_CAPABILITIES = 0x01;
|
||||
private const int _SO_SSL_FLAGS = 0x02;
|
||||
private const int _SO_SSL_PROTOCOLS = 0x03;
|
||||
private const int _SO_SSL_CIPHERS = 0x04;
|
||||
private const int _SO_SSL_CLIENT_OPTS = 0x05;
|
||||
private const int _SO_SSL_SERVER_OPTS = 0x06;
|
||||
private const int _SO_SSL_CLIENT_AUTH_OPTS = 0x07;
|
||||
private const int _SO_SSL_VALIDATE_CERT_HOOK = 0x08;
|
||||
private const int _SO_SSL_AUTH_REQUEST_HOOK = 0x09;
|
||||
private const int _SO_SSL_KEY_EXCH_HOOK = 0x0a;
|
||||
private const int _SO_SSL_SIGNATURE_HOOK = 0x0b;
|
||||
private const int _SO_SSL_PERFORM_HANDSHAKE = 0x0d;
|
||||
private const int _SO_SSL_CONNECTION_INFO = 0x0e;
|
||||
private const int _SO_SSL_PEERNAME = 0x0f;
|
||||
|
||||
// actual SSL WSAIoctl commands
|
||||
private const long SO_SSL_GET_CAPABILITIES = (IOC_OUT | _SO_SSL | _SO_SSL_CAPABILITIES);
|
||||
private const long SO_SSL_SET_FLAGS = (IOC_IN | _SO_SSL | _SO_SSL_FLAGS);
|
||||
private const long SO_SSL_GET_FLAGS = (IOC_OUT | _SO_SSL | _SO_SSL_FLAGS);
|
||||
private const long SO_SSL_SET_PROTOCOLS = (IOC_IN | _SO_SSL | _SO_SSL_PROTOCOLS);
|
||||
private const long SO_SSL_GET_PROTOCOLS = (IOC_OUT | _SO_SSL | _SO_SSL_PROTOCOLS);
|
||||
private const long SO_SSL_SET_CIPHERS = (IOC_IN | _SO_SSL | _SO_SSL_CIPHERS);
|
||||
private const long SO_SSL_GET_CIPHERS = (IOC_OUT | IOC_IN | _SO_SSL | _SO_SSL_CIPHERS);
|
||||
private const long SO_SSL_SET_CLIENT_OPTS = (IOC_IN | _SO_SSL | _SO_SSL_CLIENT_OPTS);
|
||||
private const long SO_SSL_GET_CLIENT_OPTS = (IOC_OUT | _SO_SSL | _SO_SSL_CLIENT_OPTS);
|
||||
private const long SO_SSL_SET_SERVER_OPTS = (IOC_IN | _SO_SSL | _SO_SSL_SERVER_OPTS);
|
||||
private const long SO_SSL_GET_SERVER_OPTS = (IOC_OUT | _SO_SSL | _SO_SSL_SERVER_OPTS);
|
||||
private const long SO_SSL_SET_CLIENT_AUTH_OPTS = (IOC_IN | _SO_SSL | _SO_SSL_CLIENT_AUTH_OPTS);
|
||||
private const long SO_SSL_GET_CLIENT_AUTH_OPTS = (IOC_OUT | _SO_SSL | _SO_SSL_CLIENT_AUTH_OPTS);
|
||||
private const long SO_SSL_SET_VALIDATE_CERT_HOOK = (IOC_IN | _SO_SSL | _SO_SSL_VALIDATE_CERT_HOOK);
|
||||
private const long SO_SSL_GET_VALIDATE_CERT_HOOK = (IOC_OUT | _SO_SSL | _SO_SSL_VALIDATE_CERT_HOOK);
|
||||
private const long SO_SSL_SET_AUTH_REQUEST_HOOK = (IOC_IN | _SO_SSL | _SO_SSL_AUTH_REQUEST_HOOK);
|
||||
private const long SO_SSL_GET_AUTH_REQUEST_HOOK = (IOC_OUT | _SO_SSL | _SO_SSL_AUTH_REQUEST_HOOK);
|
||||
private const long SO_SSL_SET_KEY_EXCH_HOOK = (IOC_IN | _SO_SSL | _SO_SSL_KEY_EXCH_HOOK);
|
||||
private const long SO_SSL_GET_KEY_EXCH_HOOK = (IOC_OUT | _SO_SSL | _SO_SSL_KEY_EXCH_HOOK);
|
||||
private const long SO_SSL_SET_SIGNATURE_HOOK = (IOC_IN | _SO_SSL | _SO_SSL_SIGNATURE_HOOK);
|
||||
private const long SO_SSL_GET_SIGNATURE_HOOK = (IOC_OUT | _SO_SSL | _SO_SSL_SIGNATURE_HOOK);
|
||||
private const long SO_SSL_PERFORM_HANDSHAKE = ( _SO_SSL | _SO_SSL_PERFORM_HANDSHAKE);
|
||||
private const long SO_SSL_GET_CONNECTION_INFO = (IOC_OUT | _SO_SSL | _SO_SSL_CONNECTION_INFO);
|
||||
private const long SO_SSL_SET_PEERNAME = (IOC_OUT | _SO_SSL | _SO_SSL_PEERNAME);
|
||||
|
||||
// error codes to be returned by the hook functions.
|
||||
private const int SSL_ERR_OKAY = 0;
|
||||
private const int SSL_ERR_FAILED = 2;
|
||||
private const int SSL_ERR_BAD_LEN = 3;
|
||||
private const int SSL_ERR_BAD_TYPE = 4;
|
||||
private const int SSL_ERR_BAD_DATA = 5;
|
||||
private const int SSL_ERR_NO_CERT = 6;
|
||||
private const int SSL_ERR_BAD_SIG = 7;
|
||||
private const int SSL_ERR_CERT_EXPIRED = 8;
|
||||
private const int SSL_ERR_CERT_REVOKED = 9;
|
||||
private const int SSL_ERR_CERT_UNKNOWN = 10;
|
||||
private const int SSL_ERR_SIGNATURE = 11;
|
||||
|
||||
// declarations for _SO_SSL_VALIDATE_CERT_HOOK
|
||||
private const int SSL_CERT_X509 = 0x0001;
|
||||
private const int SSL_CERT_FLAG_ISSUER_UNKNOWN = 0x0001;
|
||||
|
||||
#endregion
|
||||
|
||||
#region P/Invoke declarations ...
|
||||
|
||||
// sslsock.h : callback (function pointer) for validate certificate
|
||||
private delegate int SSLVALIDATECERTFUNC(uint dwType, IntPtr pvArg, uint dwChainLen, IntPtr pCertChain, uint dwFlags);
|
||||
|
||||
// pointer to host name for certificate validation
|
||||
private IntPtr ptrHost;
|
||||
// pointer to hook function for certificate validation
|
||||
private IntPtr ptrValidateCertHook;
|
||||
|
||||
#endregion
|
||||
|
||||
// reference to underlying socket;
|
||||
private Socket socket;
|
||||
// callback to user certificate validation
|
||||
private RemoteCertificateValidationCallback userCertificateValidationCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="socket">Underlying socket</param>
|
||||
/// <param name="host">Remote host name</param>
|
||||
/// <param name="userCertificateValidationCallback">Callback to user certificate validation</param>
|
||||
public SslSocket(Socket socket, string host, RemoteCertificateValidationCallback userCertificateValidationCallback)
|
||||
{
|
||||
this.socket = socket;
|
||||
|
||||
// allocate buffer for the host name a copy string
|
||||
this.ptrHost = Marshal.StringToBSTR(host);
|
||||
|
||||
this.userCertificateValidationCallback = userCertificateValidationCallback;
|
||||
|
||||
// set SSL (security) as option at socket level
|
||||
// NOTE : the SocketOptionName enum doesn't contain an option for security but we can cast SO_SECURE
|
||||
this.socket.SetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)SO_SECURE, SO_SEC_SSL);
|
||||
|
||||
// need to execute IOControl on socket (WSAIoctl in native) to seet the hook to validate function
|
||||
// IOCTL command = SO_SSL_SET_VALIDATE_CERT_HOOK;
|
||||
// IOCTL in = pointer to hook function and parameters
|
||||
// IOCTL out = nothing (null);
|
||||
|
||||
// get a pointer to delegate for validate certificate function
|
||||
this.ptrValidateCertHook = Marshal.GetFunctionPointerForDelegate(new SSLVALIDATECERTFUNC(ValidateCertificate));
|
||||
|
||||
// prepare buffer IOCTL in
|
||||
// 4 bytes : pointer to hook function
|
||||
// 4 bytes : pointer to paramaters
|
||||
byte[] optionInValue = new byte[8];
|
||||
// copy pointer to hook function into buffer
|
||||
byte[] validateCertHookBytes = BitConverter.GetBytes(ptrValidateCertHook.ToInt32());
|
||||
byte[] hostPtrBytes = BitConverter.GetBytes(ptrHost.ToInt32());
|
||||
Array.Copy(validateCertHookBytes, optionInValue, validateCertHookBytes.Length);
|
||||
Array.Copy(hostPtrBytes, 0, optionInValue, validateCertHookBytes.Length, hostPtrBytes.Length);
|
||||
|
||||
unchecked
|
||||
{
|
||||
// set hook to validate certificate function
|
||||
this.socket.IOControl((int)SO_SSL_SET_VALIDATE_CERT_HOOK, optionInValue, null);
|
||||
}
|
||||
}
|
||||
|
||||
void ITransport.Send(ByteBuffer buffer)
|
||||
{
|
||||
// SSL socket on WEC aren't full duplex : send/receive operations must be exclusive
|
||||
lock (this)
|
||||
{
|
||||
this.socket.Send(buffer.Buffer, buffer.Offset, buffer.Length, SocketFlags.None);
|
||||
}
|
||||
}
|
||||
|
||||
int ITransport.Receive(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int read = 0;
|
||||
do
|
||||
{
|
||||
// wait for incoming data
|
||||
if (this.socket.Poll(Timeout.Infinite, SelectMode.SelectRead))
|
||||
{
|
||||
// SSL socket on WEC aren't full duplex : send/receive operations must be exclusive
|
||||
lock (this)
|
||||
{
|
||||
read = this.socket.Receive(buffer, offset, count, SocketFlags.None);
|
||||
}
|
||||
}
|
||||
} while (read == 0);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate certificate method as callback to the socket
|
||||
/// </summary>
|
||||
/// <param name="dwType">Data type pointed to by pCertChain (SSL_CERT_X.509 if X509 certs chain)</param>
|
||||
/// <param name="pvArg">Pointer to application-defined context (passed by the SSLVALIDATECERTHOOK structure)</param>
|
||||
/// <param name="dwChainLen">Number of certificates pointed to by pCertChain (It will always be equal to one)</param>
|
||||
/// <param name="pCertChain">Pointer to the root certificate</param>
|
||||
/// <param name="dwFlags">Will contain SSL_CERT_FLAG_ISSUER_UNKNOWN if the root issuer of the certificate could not be found in the CA database</param>
|
||||
/// <returns>Result</returns>
|
||||
private int ValidateCertificate(uint dwType, IntPtr pvArg, uint dwChainLen, IntPtr pCertChain, uint dwFlags)
|
||||
{
|
||||
bool userResult = false;
|
||||
X509Certificate2 certificate = null;
|
||||
|
||||
// execute internal certificate validation
|
||||
int result = ValidateCertificateInternal(dwType, pvArg, dwChainLen, pCertChain, dwFlags, out certificate);
|
||||
|
||||
// execute user validation callback if available
|
||||
if (this.userCertificateValidationCallback != null)
|
||||
userResult = this.userCertificateValidationCallback(this, certificate, (SslPolicyErrors)result);
|
||||
|
||||
result = userResult ? SSL_ERR_OKAY : SSL_ERR_FAILED;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate certificate method as callback to the socket
|
||||
/// </summary>
|
||||
/// <param name="dwType">Data type pointed to by pCertChain (SSL_CERT_X.509 if X509 certs chain)</param>
|
||||
/// <param name="pvArg">Pointer to application-defined context (passed by the SSLVALIDATECERTHOOK structure)</param>
|
||||
/// <param name="dwChainLen">Number of certificates pointed to by pCertChain (It will always be equal to one)</param>
|
||||
/// <param name="pCertChain">Pointer to the root certificate</param>
|
||||
/// <param name="dwFlags">Will contain SSL_CERT_FLAG_ISSUER_UNKNOWN if the root issuer of the certificate could not be found in the CA database</param>
|
||||
/// <param name="certificate">X509 certificate</param>
|
||||
/// <returns>Result</returns>
|
||||
private int ValidateCertificateInternal(uint dwType, IntPtr pvArg, uint dwChainLen, IntPtr pCertChain, uint dwFlags, out X509Certificate2 certificate)
|
||||
{
|
||||
certificate = null;
|
||||
|
||||
// check if it is a valid X509 certificate
|
||||
if (dwType != SSL_CERT_X509)
|
||||
return SSL_ERR_BAD_TYPE;
|
||||
|
||||
// in debug mode accept self-signed certificates
|
||||
#if !DEBUG
|
||||
// check if issuer is unknown
|
||||
if ((dwFlags & SSL_CERT_FLAG_ISSUER_UNKNOWN) != 0)
|
||||
return SSL_ERR_CERT_UNKNOWN;
|
||||
#endif
|
||||
|
||||
// sslsock.h : pCertChain is a pointer to BLOB structure
|
||||
// - first 4 bytes are the certificate size
|
||||
// - following bytes are the certificate itself
|
||||
// read certificate size
|
||||
int certSize = Marshal.ReadInt32(pCertChain);
|
||||
// pointer to start of certificate data
|
||||
IntPtr pCertData = Marshal.ReadIntPtr(new IntPtr(pCertChain.ToInt32() + sizeof(int)));
|
||||
|
||||
byte[] certData = new byte[certSize];
|
||||
// read certificate data bytes
|
||||
for (int i = 0; i < certSize; i++)
|
||||
certData[i] = Marshal.ReadByte(pCertData, (int)i);
|
||||
|
||||
// create X509 certificate from raw bytes
|
||||
try
|
||||
{
|
||||
certificate = new X509Certificate2(certData);
|
||||
}
|
||||
catch (ArgumentException) { return SSL_ERR_BAD_DATA; }
|
||||
catch (CryptographicException) { return SSL_ERR_BAD_DATA; }
|
||||
|
||||
// check expiration date
|
||||
if (DateTime.Now > DateTime.Parse(certificate.GetExpirationDateString(), CultureInfo.CurrentCulture))
|
||||
return SSL_ERR_CERT_EXPIRED;
|
||||
|
||||
// check the effective date
|
||||
if (DateTime.Now < DateTime.Parse(certificate.GetEffectiveDateString(), CultureInfo.CurrentCulture))
|
||||
return SSL_ERR_FAILED;
|
||||
|
||||
// validate the certificate CN with provided host name
|
||||
string host = Marshal.PtrToStringBSTR(pvArg);
|
||||
if (!certificate.GetName().Contains("CN=" + host))
|
||||
return SSL_ERR_FAILED;
|
||||
|
||||
return SSL_ERR_OKAY;
|
||||
}
|
||||
|
||||
#region IDisposable ...
|
||||
|
||||
/// <summary>
|
||||
/// Destructor
|
||||
/// </summary>
|
||||
~SslSocket()
|
||||
{
|
||||
// the object went out of scope and finalized is called
|
||||
// call dispose ("false" param) to release unmanaged resources
|
||||
// NOTE : the managed resources will anyways be released when GC
|
||||
// runs the next time.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// method called from user that wants to release all resources (managed and not)
|
||||
Dispose(true);
|
||||
|
||||
// we have already cleaned up so the finalizer is useless
|
||||
// (tell the GC not to call it later)
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose object resources
|
||||
/// </summary>
|
||||
/// <param name="disposing">Dispose managed resources or not</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// we want explicitily clean up resources (managed)
|
||||
this.ReleaseManagedResources();
|
||||
}
|
||||
else
|
||||
{
|
||||
// disposing "false" means that object went out of scope
|
||||
// finalizer is called and GC will release resources on next run
|
||||
}
|
||||
|
||||
// release unmanaged resource because they will not be released by GC
|
||||
this.ReleaseUnmangedResources();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release unmanaged resources
|
||||
/// </summary>
|
||||
private void ReleaseUnmangedResources()
|
||||
{
|
||||
// free memory of remote host name
|
||||
if (this.ptrHost != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeBSTR(this.ptrHost);
|
||||
this.ptrHost = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release managed resources
|
||||
/// </summary>
|
||||
private void ReleaseManagedResources()
|
||||
{
|
||||
// close underlying socket
|
||||
if (this.socket != null)
|
||||
this.socket.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Errors related to internal validation
|
||||
/// </summary>
|
||||
public enum SslPolicyErrors
|
||||
{
|
||||
/// <summary>
|
||||
/// No SSL validation error.
|
||||
/// </summary>
|
||||
SslErrOkay = 0,
|
||||
|
||||
/// <summary>
|
||||
/// SSL validation failed.
|
||||
/// </summary>
|
||||
SslErrFailed = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The remote certificate is not an X509 certificate.
|
||||
/// </summary>
|
||||
SslErrBadType = 4,
|
||||
|
||||
/// <summary>
|
||||
/// An X509 certificate cannot be created from the received data.
|
||||
/// </summary>
|
||||
SslErrBadData = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate has expired.
|
||||
/// </summary>
|
||||
SslErrCertExpired = 8,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate issuer is unknown.
|
||||
/// </summary>
|
||||
SslErrCertUnknown = 10,
|
||||
}
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
// ------------------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ""License""); you may not use this
|
||||
// file except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR
|
||||
// CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
|
||||
// NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
||||
namespace Amqp
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
sealed class TcpTransport : ITransport
|
||||
{
|
||||
ITransport socketTransport;
|
||||
|
||||
public void Connect(Connection connection, Address address, bool noVerification)
|
||||
{
|
||||
var ipHostEntry = Dns.GetHostEntry(address.Host);
|
||||
Exception exception = null;
|
||||
TcpSocket socket = null;
|
||||
// reference to SSL socket, wrapper for above TCP socket
|
||||
SslSocket sslSocket = null;
|
||||
|
||||
foreach (var ipAddress in ipHostEntry.AddressList)
|
||||
{
|
||||
if (ipAddress == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
socket = new TcpSocket();
|
||||
// SSL connection requested with an SSL host
|
||||
if (address.UseSsl)
|
||||
{
|
||||
// wrap TCP socket to SSL socket
|
||||
sslSocket = new SslSocket(socket, address.Host, ValidateCertificate);
|
||||
}
|
||||
socket.Connect(new IPEndPoint(ipAddress, address.Port));
|
||||
exception = null;
|
||||
break;
|
||||
}
|
||||
catch (SocketException socketException)
|
||||
{
|
||||
if (address.UseSsl)
|
||||
{
|
||||
if (sslSocket != null)
|
||||
{
|
||||
sslSocket.Close();
|
||||
sslSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (socket != null)
|
||||
{
|
||||
socket.Close();
|
||||
socket = null;
|
||||
}
|
||||
|
||||
exception = socketException;
|
||||
}
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
throw exception;
|
||||
}
|
||||
|
||||
if (address.UseSsl)
|
||||
{
|
||||
this.socketTransport = sslSocket;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.socketTransport = socket;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
this.socketTransport.Close();
|
||||
}
|
||||
|
||||
public void Send(ByteBuffer buffer)
|
||||
{
|
||||
this.socketTransport.Send(buffer);
|
||||
}
|
||||
|
||||
public int Receive(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return this.socketTransport.Receive(buffer, offset, count);
|
||||
}
|
||||
|
||||
class TcpSocket : Socket, ITransport
|
||||
{
|
||||
public TcpSocket()
|
||||
: base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
|
||||
{
|
||||
}
|
||||
|
||||
void ITransport.Send(ByteBuffer buffer)
|
||||
{
|
||||
base.Send(buffer.Buffer, buffer.Offset, buffer.Length, SocketFlags.None);
|
||||
}
|
||||
|
||||
int ITransport.Receive(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return base.Receive(buffer, offset, count, SocketFlags.None);
|
||||
}
|
||||
|
||||
void ITransport.Close()
|
||||
{
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateCertificate(object sender, X509Certificate certificate, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
#if DEBUG
|
||||
return true;
|
||||
#else
|
||||
// return verification result or add your logic here to validate certificate
|
||||
return (sslPolicyErrors == SslPolicyErrors.SslErrOkay);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
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("Amqp 1.0")]
|
||||
[assembly: AssemblyDescription("AMQP 1.0 .Net Library")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyProduct("Amqp")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[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("c97ceedd-db9e-42eb-800a-f2cb10071b6b")]
|
||||
|
||||
// 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")]
|
|
@ -1,80 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{187E608C-FBF4-4517-B61F-A85AFF5BCA75}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Test.Amqp.NetCF39</RootNamespace>
|
||||
<AssemblyName>Test.Amqp.NetCF39</AssemblyName>
|
||||
<ProjectTypeGuids>{6AFDAB0D-95EF-424D-8A49-099ECD40B0FF};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<TargetFrameworkIdentifier>WindowsEmbeddedCompact</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v3.9</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<IntermediateOutputPath>..\..\obj\$(Configuration)\$(MSBuildProjectName)\</IntermediateOutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\..\bin\$(Configuration)\$(MSBuildProjectName)\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;COMPACT_FRAMEWORK</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\bin\$(Configuration)\$(MSBuildProjectName)\</OutputPath>
|
||||
<DefineConstants>TRACE;COMPACT_FRAMEWORK</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Common\Assert.cs">
|
||||
<Link>Assert.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Common\LinkTests.cs">
|
||||
<Link>LinkTests.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Common\TestRunner.cs">
|
||||
<Link>TestRunner.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Common\TestTarget.cs">
|
||||
<Link>TestTarget.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Common\UtilityTests.cs">
|
||||
<Link>UtilityTests.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Test.Amqp.NetMF\Program.cs">
|
||||
<Link>Program.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Amqp.NetCF39.csproj">
|
||||
<Project>{994D25B3-A2C4-4A27-A0E8-3203E954BF58}</Project>
|
||||
<Name>Amqp.NetCF39</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\v8.0\Microsoft.$(TargetFrameworkIdentifier).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>
|
Загрузка…
Ссылка в новой задаче