Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch '81-restricted-extraction-paths'

Fix #81
  • Loading branch information...
commit e8b9dd4ff02048dd22eefe3015579048d35889b7 2 parents ca8e6e3 + 11f99b7
@jgoz jgoz authored
View
47 README.md
@@ -88,6 +88,50 @@ namespace ZMQGuide
More C# examples can be found in the [0MQ Guide][zmq-guide] or in the [examples repository][zmq-example-repo]. Tutorials and API documentation specific to clrzmq are on the way.
+## Deployment Notes
+
+When using a packaged (NuGet/zip) release on Windows, clrzmq comes bundled with 32- and 64-bit versions of libzmq.dll that have been fully tested with the binding package.
+The DLLs are embedded as manifest resources in the assembly and are extracted when initially loading the assembly.
+To accommodate different deployment needs, several output paths may be used.
+
+The libzmq.dll search/extract order is as follows:
+
+1. libzmq.dll on System Path
+ - Allows loading a custom libzmq.dll into system32, %PATH%, etc. (see [LoadLibrary][load-library] for search order)
+2. Extract to assembly path
+ - Full path to the currently executing clrzmq.dll
+3. Extract to execution path
+ - Full path to the executable calling clrzmq
+4. Extract to temporary path
+ - Current user's `%TEMP%\clrzmq-x.x.x.x`
+ - Last ditch fallback: only severly restricted accounts will fail to extract to this path
+
+### Tracing
+
+If you run into problems related to loading the native library, you can enable tracing in your application as follows:
+
+1. Add a trace listener to your application (see [TraceListener](http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx) for an example)
+2. Configure the `clrzmq` trace switch to use the `Info` level (3):
+
+```xml
+<configuration>
+ <system.diagnostics>
+ <switches>
+ <add name="clrzmq" value="3" /><!-- Info -->
+ </switches>
+ </system.diagnostics>
+</configuration>
+```
+
+### IIS Deployments
+
+IIS deployments can be complicated due to the many possible identities and privilege levels that may be executing your application.
+There are a few steps you can take to ensure the bundled native libraries can be properly extracted and used:
+
+1. At the bare minimum, ensure the Application Pool identity has write access to its `%TEMP%` folder
+2. Allow write access to your application's `bin` directory (i.e., the directory containing clrzmq.dll and your application assemblies)
+3. If none of those options are suitable, you will need to obtain a compiled version of libzmq.dll for your platform and extract it to a system path (see [LoadLibrary][load-library] for candidates)
+
## Development Environment
On Windows/.NET, clrzmq is developed with Visual Studio 2010. Mono development is done with MonoDevelop 2.8+.
@@ -177,9 +221,10 @@ This project is released under the [LGPL][lgpl] license, as is the native libzmq
[clrzmq-old]: https://github.com/zeromq/clrzmq-old
[clrzmq-nuget]: http://packages.nuget.org/Packages/clrzmq
[libzmq]: https://github.com/zeromq/libzmq
+[load-library]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
[zmq-guide]: http://zguide.zeromq.org/page:all
[zmq-example-repo]: https://github.com/imatix/zguide/tree/master/examples/C%23
[zmq-dl]: http://www.zeromq.org/intro:get-the-software
[zmq-license]: http://www.zeromq.org/area:licensing
[issues]: https://github.com/zeromq/clrzmq/issues
-[lgpl]: http://www.gnu.org/licenses/lgpl.html
+[lgpl]: http://www.gnu.org/licenses/lgpl.html
View
73 src/ZeroMQ/Interop/Tracer.cs
@@ -0,0 +1,73 @@
+namespace ZeroMQ.Interop
+{
+ using System.Diagnostics;
+
+ internal class Tracer
+ {
+ private static readonly TraceSwitch AssemblySwitch = new TraceSwitch("clrzmq", "ZeroMQ C# Binding");
+
+ public static void Verbose(string message, string category)
+ {
+ if (AssemblySwitch.TraceVerbose)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+
+ public static void Info(string message, string category)
+ {
+ if (AssemblySwitch.TraceInfo)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+
+ public static void Warning(string message, string category)
+ {
+ if (AssemblySwitch.TraceWarning)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+
+ public static void Error(string message, string category)
+ {
+ if (AssemblySwitch.TraceError)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+
+ public static void VerboseIf(bool condition, string message, string category)
+ {
+ if (AssemblySwitch.TraceVerbose && condition)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+
+ public static void InfoIf(bool condition, string message, string category)
+ {
+ if (AssemblySwitch.TraceInfo && condition)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+
+ public static void WarningIf(bool condition, string message, string category)
+ {
+ if (AssemblySwitch.TraceWarning && condition)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+
+ public static void ErrorIf(bool condition, string message, string category)
+ {
+ if (AssemblySwitch.TraceError && condition)
+ {
+ Trace.WriteLine(message, category);
+ }
+ }
+ }
+}
View
30 src/ZeroMQ/Interop/UnmanagedLibrary.cs
@@ -14,6 +14,8 @@
/// </remarks>
internal sealed class UnmanagedLibrary : IDisposable
{
+ private const string TraceCategory = "clrzmq[UnmanagedLibrary]";
+
private static readonly string CurrentArch = Environment.Is64BitProcess ? "x64" : "x86";
private readonly string _systemFileName;
@@ -40,19 +42,21 @@ public UnmanagedLibrary(string fileName)
_systemFileName = fileName + Platform.LibSuffix;
_handle = LoadFromSystemPath();
-
+
+ Tracer.InfoIf(_handle != null, "Loading " + _systemFileName + " from LoadLibrary system path.", TraceCategory);
+
if (_handle == null)
{
// Ensure the correct manifest resource will always be used, even if it has already been extracted
_extractedFileName = fileName + "-" + CurrentArch + "-" + Assembly.GetExecutingAssembly().GetName().Version + Platform.LibSuffix;
- _handle = LoadFromLocalBinPath() ?? LoadFromExecutingPath() ?? LoadFromTempPath();
+ _handle = LoadFromAssemblyPath() ?? LoadFromExecutingPath() ?? LoadFromTempPath();
}
if (_handle == null || _handle.IsInvalid)
{
throw new FileNotFoundException(
- "Unable to find " + _systemFileName + " on system path or the file found was not the expected file.",
+ "Unable to find " + _systemFileName + " on system path or extract it from assembly manifest resources. Inspect Trace output for more details.",
_systemFileName,
Platform.GetLastLibraryError());
}
@@ -101,14 +105,25 @@ private static SafeLibraryHandle NullifyInvalidHandle(SafeLibraryHandle handle)
return handle.IsInvalid ? null : handle;
}
+ private static string GetFullAssemblyPath()
+ {
+ var dir = new Uri(Assembly.GetExecutingAssembly().CodeBase);
+ var fi = new FileInfo(Uri.UnescapeDataString(dir.AbsolutePath));
+ return fi.Directory != null ? fi.Directory.FullName : null;
+ }
+
private SafeLibraryHandle LoadFromSystemPath()
{
return NullifyInvalidHandle(Platform.OpenHandle(_systemFileName));
}
- private SafeLibraryHandle LoadFromLocalBinPath()
+ private SafeLibraryHandle LoadFromAssemblyPath()
{
- return Directory.Exists("bin") ? ExtractAndLoadFromPath("bin") : null;
+ var assemblyPath = GetFullAssemblyPath();
+
+ Tracer.WarningIf(assemblyPath == null, "Unable to determine full assembly path.", TraceCategory);
+
+ return assemblyPath != null ? ExtractAndLoadFromPath(assemblyPath) : null;
}
private SafeLibraryHandle LoadFromExecutingPath()
@@ -118,7 +133,8 @@ private SafeLibraryHandle LoadFromExecutingPath()
private SafeLibraryHandle LoadFromTempPath()
{
- string dir = Path.Combine(Path.GetTempPath(), Assembly.GetExecutingAssembly().FullName, CurrentArch);
+ var assemblyName = Assembly.GetExecutingAssembly().GetName();
+ string dir = Path.Combine(Path.GetTempPath(), assemblyName.Name + "-" + assemblyName.Version);
Directory.CreateDirectory(dir);
return ExtractAndLoadFromPath(dir);
@@ -131,9 +147,11 @@ private SafeLibraryHandle ExtractAndLoadFromPath(string dir)
if (!ManifestResource.Extract(_systemFileName + platformSuffix, libPath))
{
+ Tracer.Warning("Unable to extract native library to " + libPath, TraceCategory);
return null;
}
+ Tracer.Info("Extracted and loading " + libPath, TraceCategory);
return NullifyInvalidHandle(Platform.OpenHandle(libPath));
}
}
View
3  src/ZeroMQ/ZeroMQ.csproj
@@ -65,6 +65,7 @@
<Compile Include="Interop\PollItem.cs" />
<Compile Include="Interop\ManifestResource.cs" />
<Compile Include="Interop\SafeLibraryHandle.cs" />
+ <Compile Include="Interop\Tracer.cs" />
<Compile Include="Interop\UnmanagedLibrary.cs" />
<Compile Include="Interop\ZmqMsgT.cs" />
<Compile Include="Monitoring\MonitorEvent.cs" />
@@ -122,4 +123,4 @@
</ItemGroup>
<Copy Condition="'$(UseCustomLibzmq)' != 'true'" SourceFiles="@(LibzmqFiles)" DestinationFiles="@(LibFiles)" SkipUnchangedFiles="true" />
</Target>
-</Project>
+</Project>
Please sign in to comment.
Something went wrong with that request. Please try again.