summaryrefslogtreecommitdiff
path: root/csharp/src
diff options
context:
space:
mode:
Diffstat (limited to 'csharp/src')
-rw-r--r--csharp/src/Glacier2/.depend.mak29
-rw-r--r--csharp/src/Glacier2/Application.cs477
-rw-r--r--csharp/src/Glacier2/AssemblyInfo.cs28
-rw-r--r--csharp/src/Glacier2/Makefile54
-rwxr-xr-xcsharp/src/Glacier2/Makefile.mak61
-rw-r--r--csharp/src/Glacier2/SessionCallback.cs51
-rw-r--r--csharp/src/Glacier2/SessionFactoryHelper.cs420
-rw-r--r--csharp/src/Glacier2/SessionHelper.cs526
-rw-r--r--csharp/src/Glacier2/generated/.gitignore1
-rw-r--r--csharp/src/Ice/.depend.mak144
-rw-r--r--csharp/src/Ice/ACM.cs356
-rw-r--r--csharp/src/Ice/AMDCallback.cs26
-rw-r--r--csharp/src/Ice/Acceptor.cs28
-rw-r--r--csharp/src/Ice/Application.cs936
-rw-r--r--csharp/src/Ice/Arrays.cs122
-rw-r--r--csharp/src/Ice/AssemblyInfo.cs28
-rw-r--r--csharp/src/Ice/AssemblyUtil.cs288
-rw-r--r--csharp/src/Ice/AsyncIOThread.cs208
-rw-r--r--csharp/src/Ice/AsyncResult.cs698
-rw-r--r--csharp/src/Ice/Base64.cs276
-rw-r--r--csharp/src/Ice/BasicStream.cs5409
-rw-r--r--csharp/src/Ice/BatchRequestInterceptor.cs57
-rw-r--r--csharp/src/Ice/BatchRequestQueue.cs244
-rw-r--r--csharp/src/Ice/Buffer.cs195
-rw-r--r--csharp/src/Ice/ByteBuffer.cs999
-rw-r--r--csharp/src/Ice/CollectionBase.cs450
-rw-r--r--csharp/src/Ice/Collections.cs239
-rw-r--r--csharp/src/Ice/CollocatedRequestHandler.cs346
-rw-r--r--csharp/src/Ice/CommunicatorI.cs294
-rw-r--r--csharp/src/Ice/Compare.cs185
-rw-r--r--csharp/src/Ice/ConnectRequestHandler.cs343
-rw-r--r--csharp/src/Ice/ConnectionFactory.cs1758
-rw-r--r--csharp/src/Ice/ConnectionI.cs2990
-rw-r--r--csharp/src/Ice/ConnectionRequestHandler.cs77
-rw-r--r--csharp/src/Ice/Connector.cs27
-rw-r--r--csharp/src/Ice/DefaultsAndOverrides.cs229
-rw-r--r--csharp/src/Ice/DictionaryBase.cs355
-rw-r--r--csharp/src/Ice/DispatchInterceptor.cs68
-rw-r--r--csharp/src/Ice/EndpointFactory.cs25
-rw-r--r--csharp/src/Ice/EndpointFactoryManager.cs203
-rw-r--r--csharp/src/Ice/EndpointHostResolver.cs292
-rw-r--r--csharp/src/Ice/EndpointI.cs209
-rw-r--r--csharp/src/Ice/EventHandler.cs43
-rw-r--r--csharp/src/Ice/Exception.cs274
-rw-r--r--csharp/src/Ice/FormatType.cs21
-rw-r--r--csharp/src/Ice/HashSet.cs114
-rw-r--r--csharp/src/Ice/HttpParser.cs774
-rw-r--r--csharp/src/Ice/IPEndpointI.cs407
-rw-r--r--csharp/src/Ice/Ice.dll.config3
-rw-r--r--csharp/src/Ice/ImplicitContextI.cs409
-rw-r--r--csharp/src/Ice/Incoming.cs936
-rw-r--r--csharp/src/Ice/IncomingAsync.cs247
-rw-r--r--csharp/src/Ice/Instance.cs1581
-rw-r--r--csharp/src/Ice/InstrumentationI.cs1222
-rw-r--r--csharp/src/Ice/LocatorInfo.cs1009
-rw-r--r--csharp/src/Ice/LoggerAdminI.cs483
-rw-r--r--csharp/src/Ice/LoggerAdminLoggerI.cs241
-rw-r--r--csharp/src/Ice/LoggerI.cs264
-rw-r--r--csharp/src/Ice/LoggerPlugin.cs65
-rw-r--r--csharp/src/Ice/Makefile201
-rw-r--r--csharp/src/Ice/Makefile.mak199
-rw-r--r--csharp/src/Ice/MetricsAdminI.cs1048
-rw-r--r--csharp/src/Ice/MetricsObserverI.cs454
-rw-r--r--csharp/src/Ice/Network.cs1452
-rw-r--r--csharp/src/Ice/NetworkProxy.cs311
-rw-r--r--csharp/src/Ice/Object.cs548
-rw-r--r--csharp/src/Ice/ObjectAdapterFactory.cs246
-rw-r--r--csharp/src/Ice/ObjectAdapterI.cs1579
-rw-r--r--csharp/src/Ice/ObjectFactoryManager.cs86
-rw-r--r--csharp/src/Ice/ObserverHelper.cs63
-rw-r--r--csharp/src/Ice/OpaqueEndpointI.cs428
-rw-r--r--csharp/src/Ice/Optional.cs262
-rw-r--r--csharp/src/Ice/Options.cs406
-rw-r--r--csharp/src/Ice/OutgoingAsync.cs1267
-rw-r--r--csharp/src/Ice/OutputBase.cs193
-rw-r--r--csharp/src/Ice/Patcher.cs302
-rw-r--r--csharp/src/Ice/PluginManagerI.cs530
-rw-r--r--csharp/src/Ice/ProcessI.cs43
-rw-r--r--csharp/src/Ice/PropertiesAdminI.cs240
-rw-r--r--csharp/src/Ice/PropertiesI.cs692
-rw-r--r--csharp/src/Ice/Property.cs43
-rw-r--r--csharp/src/Ice/PropertyNames.cs1249
-rw-r--r--csharp/src/Ice/Protocol.cs184
-rw-r--r--csharp/src/Ice/ProtocolInstance.cs149
-rw-r--r--csharp/src/Ice/ProtocolPluginFacade.cs80
-rw-r--r--csharp/src/Ice/Proxy.cs2611
-rw-r--r--csharp/src/Ice/ProxyFactory.cs299
-rw-r--r--csharp/src/Ice/ProxyIdentityKey.cs135
-rw-r--r--csharp/src/Ice/Reference.cs1685
-rw-r--r--csharp/src/Ice/ReferenceFactory.cs926
-rw-r--r--csharp/src/Ice/ReplyStatus.cs27
-rw-r--r--csharp/src/Ice/RequestHandler.cs30
-rw-r--r--csharp/src/Ice/RequestHandlerFactory.cs81
-rw-r--r--csharp/src/Ice/ResponseHandler.cs22
-rw-r--r--csharp/src/Ice/RetryQueue.cs154
-rw-r--r--csharp/src/Ice/RouterInfo.cs369
-rw-r--r--csharp/src/Ice/ServantManager.cs375
-rw-r--r--csharp/src/Ice/SliceChecksums.cs39
-rw-r--r--csharp/src/Ice/SlicedData.cs63
-rw-r--r--csharp/src/Ice/SocketOperation.cs19
-rw-r--r--csharp/src/Ice/Stream.cs705
-rw-r--r--csharp/src/Ice/StreamI.cs570
-rw-r--r--csharp/src/Ice/StreamSocket.cs644
-rw-r--r--csharp/src/Ice/StreamWrapper.cs311
-rw-r--r--csharp/src/Ice/StringUtil.cs515
-rw-r--r--csharp/src/Ice/SysLoggerI.cs234
-rw-r--r--csharp/src/Ice/TcpAcceptor.cs176
-rw-r--r--csharp/src/Ice/TcpConnector.cs101
-rw-r--r--csharp/src/Ice/TcpEndpointI.cs338
-rw-r--r--csharp/src/Ice/TcpTransceiver.cs136
-rw-r--r--csharp/src/Ice/ThreadHookPlugin.cs59
-rw-r--r--csharp/src/Ice/ThreadPool.cs876
-rw-r--r--csharp/src/Ice/TieBase.cs30
-rw-r--r--csharp/src/Ice/Time.cs103
-rw-r--r--csharp/src/Ice/Timer.cs413
-rw-r--r--csharp/src/Ice/TraceLevels.cs48
-rw-r--r--csharp/src/Ice/TraceUtil.cs504
-rw-r--r--csharp/src/Ice/Transceiver.cs59
-rw-r--r--csharp/src/Ice/UdpConnector.cs107
-rw-r--r--csharp/src/Ice/UdpEndpointI.cs449
-rw-r--r--csharp/src/Ice/UdpTransceiver.cs1120
-rw-r--r--csharp/src/Ice/UnknownSlicedObject.cs50
-rw-r--r--csharp/src/Ice/UserExceptionFactory.cs19
-rw-r--r--csharp/src/Ice/Util.cs816
-rw-r--r--csharp/src/Ice/ValueWriter.cs154
-rw-r--r--csharp/src/Ice/WSAcceptor.cs73
-rw-r--r--csharp/src/Ice/WSConnector.cs75
-rw-r--r--csharp/src/Ice/WSEndpoint.cs372
-rw-r--r--csharp/src/Ice/WSTransceiver.cs1693
-rw-r--r--csharp/src/Ice/generated/.gitignore1
-rw-r--r--csharp/src/IceBox/.depend.mak7
-rw-r--r--csharp/src/IceBox/AssemblyInfo.cs28
-rw-r--r--csharp/src/IceBox/AssemblyInfoExe.cs28
-rw-r--r--csharp/src/IceBox/Makefile58
-rw-r--r--csharp/src/IceBox/Makefile.mak117
-rw-r--r--csharp/src/IceBox/Server.cs77
-rw-r--r--csharp/src/IceBox/ServiceManagerI.cs1072
-rw-r--r--csharp/src/IceBox/generated/.gitignore1
-rw-r--r--csharp/src/IceDiscovery/.depend.mak4
-rw-r--r--csharp/src/IceDiscovery/AssemblyInfo.cs28
-rw-r--r--csharp/src/IceDiscovery/LocatorI.cs210
-rw-r--r--csharp/src/IceDiscovery/LookupI.cs385
-rw-r--r--csharp/src/IceDiscovery/Makefile49
-rw-r--r--csharp/src/IceDiscovery/Makefile.mak54
-rw-r--r--csharp/src/IceDiscovery/PluginI.cs149
-rw-r--r--csharp/src/IceDiscovery/generated/.gitignore1
-rw-r--r--csharp/src/IceGrid/.depend.mak92
-rw-r--r--csharp/src/IceGrid/AssemblyInfo.cs28
-rw-r--r--csharp/src/IceGrid/Makefile55
-rw-r--r--csharp/src/IceGrid/Makefile.mak60
-rw-r--r--csharp/src/IceGrid/generated/.gitignore1
-rw-r--r--csharp/src/IceLocatorDiscovery/AssemblyInfo.cs28
-rw-r--r--csharp/src/IceLocatorDiscovery/Makefile47
-rw-r--r--csharp/src/IceLocatorDiscovery/Makefile.mak52
-rw-r--r--csharp/src/IceLocatorDiscovery/PluginI.cs422
-rw-r--r--csharp/src/IceLocatorDiscovery/generated/.gitignore1
-rw-r--r--csharp/src/IcePatch2/.depend.mak9
-rw-r--r--csharp/src/IcePatch2/AssemblyInfo.cs28
-rw-r--r--csharp/src/IcePatch2/Makefile47
-rw-r--r--csharp/src/IcePatch2/Makefile.mak52
-rw-r--r--csharp/src/IcePatch2/generated/.gitignore1
-rw-r--r--csharp/src/IceSSL/.depend.mak17
-rw-r--r--csharp/src/IceSSL/AcceptorI.cs201
-rw-r--r--csharp/src/IceSSL/AssemblyInfo.cs28
-rw-r--r--csharp/src/IceSSL/ConnectorI.cs115
-rw-r--r--csharp/src/IceSSL/EndpointI.cs370
-rw-r--r--csharp/src/IceSSL/Instance.cs78
-rw-r--r--csharp/src/IceSSL/Makefile59
-rw-r--r--csharp/src/IceSSL/Makefile.mak64
-rw-r--r--csharp/src/IceSSL/Plugin.cs114
-rw-r--r--csharp/src/IceSSL/PluginI.cs93
-rw-r--r--csharp/src/IceSSL/RFC2253.cs504
-rw-r--r--csharp/src/IceSSL/SSLEngine.cs1226
-rw-r--r--csharp/src/IceSSL/TransceiverI.cs754
-rw-r--r--csharp/src/IceSSL/TrustManager.cs343
-rw-r--r--csharp/src/IceSSL/Util.cs44
-rw-r--r--csharp/src/IceSSL/generated/.gitignore1
-rw-r--r--csharp/src/IceStorm/.depend.mak13
-rw-r--r--csharp/src/IceStorm/AssemblyInfo.cs28
-rw-r--r--csharp/src/IceStorm/Makefile47
-rw-r--r--csharp/src/IceStorm/Makefile.mak52
-rw-r--r--csharp/src/IceStorm/generated/.gitignore1
-rw-r--r--csharp/src/Makefile21
-rw-r--r--csharp/src/Makefile.mak26
-rw-r--r--csharp/src/PolicyServer/AssemblyInfo.cs28
-rw-r--r--csharp/src/PolicyServer/Makefile26
-rw-r--r--csharp/src/PolicyServer/Makefile.mak44
-rw-r--r--csharp/src/PolicyServer/PolicyServer.cs127
188 files changed, 65300 insertions, 0 deletions
diff --git a/csharp/src/Glacier2/.depend.mak b/csharp/src/Glacier2/.depend.mak
new file mode 100644
index 00000000000..a29c2fa8ecb
--- /dev/null
+++ b/csharp/src/Glacier2/.depend.mak
@@ -0,0 +1,29 @@
+
+Metrics.cs: \
+ "$(slicedir)\Glacier2\Metrics.ice" \
+ "$(slicedir)/Ice/Metrics.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+PermissionsVerifier.cs: \
+ "$(slicedir)\Glacier2\PermissionsVerifier.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+Router.cs: \
+ "$(slicedir)\Glacier2\Router.ice" \
+ "$(slicedir)/Ice/Router.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Glacier2/Session.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice" \
+ "$(slicedir)/Glacier2/PermissionsVerifier.ice"
+
+Session.cs: \
+ "$(slicedir)\Glacier2\Session.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice"
+
+SSLInfo.cs: \
+ "$(slicedir)\Glacier2\SSLInfo.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
diff --git a/csharp/src/Glacier2/Application.cs b/csharp/src/Glacier2/Application.cs
new file mode 100644
index 00000000000..b5d4aa604c2
--- /dev/null
+++ b/csharp/src/Glacier2/Application.cs
@@ -0,0 +1,477 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Threading;
+
+#if !SILVERLIGHT
+
+namespace Glacier2
+{
+
+/// <summary>
+/// Utility base class that makes it easy to correctly initialize and finalize
+/// the Ice run time, as well as handle signals. Unless the application specifies
+/// a logger, Application installs a per-process logger that logs to the standard
+/// error output.
+///
+/// Applications must create a derived class that implements the {@link #run} method.
+///
+/// A program can contain only one instance of this class.
+/// </summary>
+public abstract class Application : Ice.Application
+{
+ /// <summary>
+ /// This exception is raised if the session should be restarted.
+ /// </summary>
+ public class RestartSessionException : System.Exception
+ {
+ }
+
+ /// <summary>
+ /// Initializes an instance that calls Communicator.shutdown if
+ /// a signal is received.
+ /// </summary>
+ public
+ Application()
+ {
+ }
+
+ /// <summary>
+ /// Initializes an instance that handles signals according to the signal
+ /// policy.
+ /// </summary>
+ /// <param name="signalPolicy">@param signalPolicy Determines how to
+ /// respond to signals.</param>
+ public
+ Application(Ice.SignalPolicy signalPolicy) : base(signalPolicy)
+ {
+ }
+
+ /// <summary>
+ /// Called once the communicator has been initialized and the Glacier2 session
+ /// has been established. A derived class must implement <code>runWithSession</code>,
+ /// which is the application's starting method.
+ /// </summary>
+ /// <param name="args"> The argument vector for the application. Application
+ /// scans the argument vector passed to <code>main</code> for options that are
+ /// specific to the Ice run time and removes them; therefore, the vector passed
+ /// to <code>runWithSession</code> is free from Ice-related options and contains
+ /// only options and arguments that are application-specific.</param>
+ ///
+ /// <returns> The runWithSession method should return zero for successful
+ /// termination, and non-zero otherwise. Application.main returns the
+ /// value returned by runWithSession.</returns>
+ ///
+ public abstract int
+ runWithSession(string[] args);
+
+ /// <summary>
+ /// Run should not be overridden for Glacier2.Application. Instead
+ /// runWithSession should be used.
+ /// </summary>
+ public override int
+ run(string[] args)
+ {
+ //
+ // This shouldn't be called.
+ //
+ Debug.Assert(false);
+ return 0;
+ }
+
+ /// <summary>
+ /// Called to restart the application's Glacier2 session. This
+ /// method never returns. The exception produce an application restart
+ /// when called from the Application main thread.
+ /// </summary>
+ /// <returns>throws RestartSessionException This exception is
+ /// always thrown.</returns>
+ ///
+ public void
+ restart()
+ {
+ throw new RestartSessionException();
+ }
+
+ /// <summary>
+ /// Creates a new Glacier2 session. A call to createSession always
+ /// precedes a call to runWithSession. If Ice.LocalException is thrown
+ /// from this method, the application is terminated.
+ /// </summary>
+ /// <returns> The Glacier2 session.</returns>
+ public abstract Glacier2.SessionPrx
+ createSession();
+
+ /// <summary>
+ /// Called when the session refresh thread detects that the session has been
+ /// destroyed. A subclass can override this method to take action after the
+ /// loss of connectivity with the Glacier2 router. This method is called
+ /// according to the Ice invocation dipsatch rules (in other words, it
+ /// uses the same rules as an servant upcall or AMI callback).
+ /// </summary>
+ public virtual void
+ sessionDestroyed()
+ {
+ }
+
+ /// <summary>
+ /// Returns the Glacier2 router proxy.
+ /// </summary>
+ /// <returns>The router proxy.</returns>
+ public static Glacier2.RouterPrx
+ router()
+ {
+ return _router;
+ }
+
+ /// <summary>
+ /// Returns the Glacier2 session proxy.
+ /// </summary>
+ /// <returns>The session proxy.</returns>
+ public static Glacier2.SessionPrx
+ session()
+ {
+ return _session;
+ }
+
+ /// <summary>
+ /// Returns the category to be used in the identities of all of the client's
+ /// callback objects. Clients must use this category for the router to
+ /// forward callback requests to the intended client.
+ /// Throws SessionNotExistException if no session exists.
+ /// </summary>
+ /// <returns>The category.</returns>
+ public string
+ categoryForClient()
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+ return _category;
+ }
+
+ /// <summary>
+ /// Create a new Ice identity for callback objects with the given
+ /// identity name field.
+ /// </summary>
+ /// <returns>The identity.</returns>
+ public Ice.Identity
+ createCallbackIdentity(string name)
+ {
+ return new Ice.Identity(name, categoryForClient());
+ }
+
+ /// <summary>
+ /// Adds a servant to the callback object adapter's Active Servant Map with a UUID.
+ /// </summary>
+ /// <param name="servant">The servant to add.</param>
+ /// <returns>The proxy for the servant.</returns>
+ public Ice.ObjectPrx
+ addWithUUID(Ice.Object servant)
+ {
+ return objectAdapter().add(servant, createCallbackIdentity(Guid.NewGuid().ToString()));
+ }
+
+ /// <summary>
+ /// Returns an object adapter for callback objects, creating it if necessary.
+ /// </summary>
+ /// <returns>The object adapter.</returns>
+ public Ice.ObjectAdapter
+ objectAdapter()
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+
+ lock(mutex__)
+ {
+ if(_adapter == null)
+ {
+ _adapter = communicator().createObjectAdapterWithRouter("", _router);
+ _adapter.activate();
+ }
+ }
+ return _adapter;
+ }
+
+ private class ConnectionCallbackI : Ice.ConnectionCallback
+ {
+ internal ConnectionCallbackI(Application application)
+ {
+ _application = application;
+ }
+
+ public void heartbeat(Ice.Connection con)
+ {
+
+ }
+
+ public void closed(Ice.Connection con)
+ {
+ _application.sessionDestroyed();
+ }
+
+ private readonly Application _application;
+ }
+
+ protected override int
+ doMain(string[] originArgs, Ice.InitializationData initData)
+ {
+ //
+ // Set the default properties for all Glacier2 applications.
+ //
+ initData.properties.setProperty("Ice.RetryIntervals", "-1");
+
+ bool restart;
+ int ret = 0;
+ do
+ {
+ //
+ // A copy of the initialization data and the string array
+ // needs to be passed to doMainInternal, as these can be
+ // changed by the application.
+ //
+ Ice.InitializationData id = (Ice.InitializationData)initData.Clone();
+ id.properties = id.properties.ice_clone_();
+ string[] args = (string[]) originArgs.Clone();
+
+ restart = doMain(args, id, out ret);
+ }
+ while(restart);
+ return ret;
+ }
+
+ private bool
+ doMain(string[] args, Ice.InitializationData initData, out int status)
+ {
+ //
+ // Reset internal state variables from Ice.Application. The
+ // remainder are reset at the end of this method.
+ //
+ callbackInProgress__ = false;
+ destroyed__ = false;
+ interrupted__ = false;
+
+ bool restart = false;
+ status = 0;
+
+ try
+ {
+ communicator__ = Ice.Util.initialize(ref args, initData);
+
+ _router = Glacier2.RouterPrxHelper.uncheckedCast(communicator().getDefaultRouter());
+ if(_router == null)
+ {
+ Ice.Util.getProcessLogger().error(appName__ + ": no Glacier2 router configured");
+ status = 1;
+ }
+ else
+ {
+ //
+ // The default is to destroy when a signal is received.
+ //
+ if(signalPolicy__ == Ice.SignalPolicy.HandleSignals)
+ {
+ destroyOnInterrupt();
+ }
+
+ //
+ // If createSession throws, we're done.
+ //
+ try
+ {
+ _session = createSession();
+ _createdSession = true;
+ }
+ catch(Ice.LocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ status = 1;
+ }
+
+ if(_createdSession)
+ {
+ int acmTimeout = 0;
+ try
+ {
+ acmTimeout = _router.getACMTimeout();
+ }
+ catch(Ice.OperationNotExistException)
+ {
+ }
+ if(acmTimeout <= 0)
+ {
+ acmTimeout = (int)_router.getSessionTimeout();
+ }
+ if(acmTimeout > 0)
+ {
+ Ice.Connection connection = _router.ice_getCachedConnection();
+ Debug.Assert(connection != null);
+ connection.setACM((int)acmTimeout, Ice.Util.None, Ice.ACMHeartbeat.HeartbeatAlways);
+ connection.setCallback(new ConnectionCallbackI(this));
+ }
+ _category = _router.getCategoryForClient();
+ status = runWithSession(args);
+ }
+ }
+ }
+ //
+ // We want to restart on those exceptions that indicate a
+ // break down in communications, but not those exceptions that
+ // indicate a programming logic error (i.e., marshal, protocol
+ // failure, etc).
+ //
+ catch(RestartSessionException)
+ {
+ restart = true;
+ }
+ catch(Ice.ConnectionRefusedException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ restart = true;
+ }
+ catch(Ice.ConnectionLostException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ restart = true;
+ }
+ catch(Ice.UnknownLocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ restart = true;
+ }
+ catch(Ice.RequestFailedException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ restart = true;
+ }
+ catch(Ice.TimeoutException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ restart = true;
+ }
+ catch(Ice.LocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ status = 1;
+ }
+ catch(System.Exception ex)
+ {
+ Ice.Util.getProcessLogger().error("unknown exception:\n" + ex.ToString());
+ status = 1;
+ }
+
+ //
+ // Don't want any new interrupt. And at this point
+ // (post-run), it would not make sense to release a held
+ // signal to run shutdown or destroy.
+ //
+ if(signalPolicy__ == Ice.SignalPolicy.HandleSignals)
+ {
+ ignoreInterrupt();
+ }
+
+ lock(mutex__)
+ {
+ while(callbackInProgress__)
+ {
+ System.Threading.Monitor.Wait(mutex__);
+ }
+
+ if(destroyed__)
+ {
+ communicator__ = null;
+ }
+ else
+ {
+ destroyed__ = true;
+ //
+ // And communicator__ != null, meaning will be
+ // destroyed next, destroyed__ = true also ensures that
+ // any remaining callback won't do anything
+ //
+ }
+ }
+
+ if(_createdSession && _router != null)
+ {
+ try
+ {
+ _router.destroySession();
+ }
+ catch(Ice.ConnectionLostException)
+ {
+ //
+ // Expected if another thread invoked on an object from the session concurrently.
+ //
+ }
+ catch(Glacier2.SessionNotExistException)
+ {
+ //
+ // This can also occur.
+ //
+ }
+ catch(System.Exception ex)
+ {
+ //
+ // Not expected.
+ //
+ Ice.Util.getProcessLogger().error("unexpected exception when destroying the session:\n" +
+ ex.ToString());
+ }
+ _router = null;
+ }
+
+ if(communicator__ != null)
+ {
+ try
+ {
+ communicator__.destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(ex.ToString());
+ status = 1;
+ }
+ catch(System.Exception ex)
+ {
+ Ice.Util.getProcessLogger().error("unknown exception:\n" + ex.ToString());
+ status = 1;
+ }
+ communicator__ = null;
+ }
+
+ //
+ // Reset internal state. We cannot reset the Application state
+ // here, since destroyed__ must remain true until we re-run
+ // this method.
+ //
+ _adapter = null;
+ _router = null;
+ _session = null;
+ _createdSession = false;
+ _category = null;
+
+ return restart;
+ }
+
+ private static Ice.ObjectAdapter _adapter;
+ private static Glacier2.RouterPrx _router;
+ private static Glacier2.SessionPrx _session;
+ private static bool _createdSession = false;
+ private static string _category;
+}
+
+}
+#endif
diff --git a/csharp/src/Glacier2/AssemblyInfo.cs b/csharp/src/Glacier2/AssemblyInfo.cs
new file mode 100644
index 00000000000..661acc6d7e8
--- /dev/null
+++ b/csharp/src/Glacier2/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("Glacier2")]
+[assembly: AssemblyDescription("Glacier2 run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("Glacier2 for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/Glacier2/Makefile b/csharp/src/Glacier2/Makefile
new file mode 100644
index 00000000000..e54132c9f6f
--- /dev/null
+++ b/csharp/src/Glacier2/Makefile
@@ -0,0 +1,54 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = Glacier2
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = Application.cs \
+ AssemblyInfo.cs \
+ SessionCallback.cs \
+ SessionFactoryHelper.cs \
+ SessionHelper.cs
+
+SLICE_SRCS = $(SDIR)/Metrics.ice \
+ $(SDIR)/PermissionsVerifier.ice \
+ $(SDIR)/Router.ice \
+ $(SDIR)/Session.ice \
+ $(SDIR)/SSLInfo.ice
+
+SDIR = $(slicedir)/Glacier2
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) -I$(slicedir) --ice
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/Glacier2/Makefile.mak b/csharp/src/Glacier2/Makefile.mak
new file mode 100755
index 00000000000..950fca5125a
--- /dev/null
+++ b/csharp/src/Glacier2/Makefile.mak
@@ -0,0 +1,61 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = Glacier2
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = Application.cs \
+ AssemblyInfo.cs \
+ SessionCallback.cs \
+ SessionFactoryHelper.cs \
+ SessionHelper.cs
+
+GEN_SRCS = $(GDIR)\Metrics.cs \
+ $(GDIR)\PermissionsVerifier.cs \
+ $(GDIR)\Router.cs \
+ $(GDIR)\Session.cs \
+ $(GDIR)\SSLInfo.cs
+
+SDIR = $(slicedir)\Glacier2
+GDIR = generated
+
+!include $(top_srcdir)/config/Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+# -r:WindowsBase.dll
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) -I$(slicedir) --ice
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) /baseaddress:0x22000000 $(MCSFLAGS) -r:$(refdir)\Ice.dll $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
diff --git a/csharp/src/Glacier2/SessionCallback.cs b/csharp/src/Glacier2/SessionCallback.cs
new file mode 100644
index 00000000000..55dc238be05
--- /dev/null
+++ b/csharp/src/Glacier2/SessionCallback.cs
@@ -0,0 +1,51 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+
+namespace Glacier2
+{
+/// <summary>
+/// A callback class to get notifications of status changes in the
+/// Glacier2 session. All callbacks on the SessionCallback interface
+/// occur in the main swing thread.
+/// </summary>
+public interface SessionCallback
+{
+ /// <summary>
+ /// Notifies the application that the communicator was created.
+ /// </summary>
+ /// <param name="session">The Glacier2 session.</param>
+ void createdCommunicator(SessionHelper session);
+
+ /// <summary>
+ /// Notifies the application that the Glacier2 session has
+ /// been established.
+ /// </summary>
+ /// <param name="session">The established session.</param>
+ void connected(SessionHelper session);
+
+ /// <summary>
+ /// Notifies the application that the Glacier2 session has been
+ /// disconnected.
+ /// </summary>
+ /// <param name="session">The disconnected session.</param>
+ void disconnected(SessionHelper session);
+
+ /// <summary>
+ /// Notifies the application that the Glacier2 session
+ /// establishment failed.
+ /// </summary>
+ /// <param name="session">The session reporting the connection
+ /// failure.</param>
+ /// <param name="ex">The exception.</param>
+ void connectFailed(SessionHelper session, Exception ex);
+}
+
+}
diff --git a/csharp/src/Glacier2/SessionFactoryHelper.cs b/csharp/src/Glacier2/SessionFactoryHelper.cs
new file mode 100644
index 00000000000..c37aff27581
--- /dev/null
+++ b/csharp/src/Glacier2/SessionFactoryHelper.cs
@@ -0,0 +1,420 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Text;
+using System.Collections.Generic;
+
+namespace Glacier2
+{
+
+/// <summary>
+/// A helper class for using Glacier2 with GUI applications.
+///
+/// Applications should create a session factory for each Glacier2 router to which the application will
+/// connect. To connect with the Glacier2 router, call SessionFactory.connect. The callback object is
+/// notified of the various life cycle events. Once the session is torn down for whatever reason, the
+/// application can use the session factory to create another connection.
+/// </summary>
+public class SessionFactoryHelper
+{
+ /// <summary>
+ /// Creates a SessionFactory object.
+ /// </summary>
+ /// <param name="callback">The callback object for notifications.</param>
+ public
+ SessionFactoryHelper(SessionCallback callback)
+ {
+ _callback = callback;
+ _initData = new Ice.InitializationData();
+ _initData.properties = Ice.Util.createProperties();
+ setDefaultProperties();
+ }
+
+ /// <summary>
+ /// Creates a SessionFactory object.
+ /// </summary>
+ /// <param name="initData">The initialization data to use when creating the communicator.</param>
+ /// <param name="callback">The callback object for notifications.</param>
+ public
+ SessionFactoryHelper(Ice.InitializationData initData, SessionCallback callback)
+ {
+ _callback = callback;
+ _initData = initData;
+ if(_initData.properties == null)
+ {
+ _initData.properties = Ice.Util.createProperties();
+ }
+ setDefaultProperties();
+ }
+
+ /// <summary>
+ /// Creates a SessionFactory object.
+ /// </summary>
+ /// <param name="properties">The properties to use when creating the communicator.</param>
+ /// <param name="callback">The callback object for notifications.</param>
+ public
+ SessionFactoryHelper(Ice.Properties properties, SessionCallback callback)
+ {
+ if(properties == null)
+ {
+ throw new Ice.InitializationException(
+ "Attempt to create a SessionFactoryHelper with a null Properties argument");
+ }
+ _callback = callback;
+ _initData = new Ice.InitializationData();
+ _initData.properties = properties;
+ setDefaultProperties();
+ }
+
+ /// <summary>
+ /// Set the router object identity.
+ /// </summary>
+ /// <param name="identity">The Glacier2 router's identity.</param>
+ public void
+ setRouterIdentity(Ice.Identity identity)
+ {
+ lock(this)
+ {
+ _identity = identity;
+ }
+ }
+
+ /// <summary>
+ /// Returns the object identity of the Glacier2 router.
+ /// </summary>
+ /// <returns> The Glacier2 router's identity.</returns>
+ public Ice.Identity
+ getRouterIdentity()
+ {
+ lock(this)
+ {
+ return _identity;
+ }
+ }
+
+ /// <summary>
+ /// Sets the host on which the Glacier2 router runs.
+ /// </summary>
+ /// <param name="hostname">The host name (or IP address) of the router host.</param>
+ public void
+ setRouterHost(string hostname)
+ {
+ lock(this)
+ {
+ _routerHost = hostname;
+ }
+ }
+
+ /// <summary>
+ /// Returns the host on which the Glacier2 router runs.
+ /// </summary>
+ /// <returns>The Glacier2 router host.</returns>
+ public string
+ getRouterHost()
+ {
+ lock(this)
+ {
+ return _routerHost;
+ }
+ }
+
+ /// <summary>
+ /// Sets whether to connect with the Glacier2 router securely.
+ /// </summary>
+ /// <param name="secure">If true, the client connects to the router
+ /// via SSL; otherwise, the client connects via TCP.</param>
+ [Obsolete("This method is deprecated. Use SessionFactoryHelper.setProtocol instead.")]
+ public void
+ setSecure(bool secure)
+ {
+ setProtocol(secure ? "ssl" : "tcp");
+ }
+
+ /// <summary>
+ /// Returns whether the session factory will establish a secure connection to the Glacier2 router.
+ /// </summary>
+ /// <returns>The secure flag.</returns>
+ [Obsolete("This method is deprecated. Use SessionFactoryHelper.getProtocol instead.")]
+ public bool
+ getSecure()
+ {
+ return getProtocol().Equals("ssl");
+ }
+
+ /// <summary>
+ /// Sets the protocol that will be used by the session factory to establish the connection..
+ /// </summary>
+ /// <param name="protocol">The protocol.</param>
+ public void
+ setProtocol(String protocol)
+ {
+ lock(this)
+ {
+ if(protocol == null)
+ {
+ throw new ArgumentException("You must use a valid protocol");
+ }
+
+ if(!protocol.Equals("tcp") &&
+ !protocol.Equals("ssl") &&
+ !protocol.Equals("wss") &&
+ !protocol.Equals("ws"))
+ {
+ throw new ArgumentException("Unknown protocol `" + protocol + "'");
+ }
+ _protocol = protocol;
+ }
+ }
+
+ /// <summary>
+ /// Returns the protocol that will be used by the session factory to establish the connection.
+ /// </summary>
+ /// <returns>The protocol.</returns>
+ public String
+ getProtocol()
+ {
+ lock(this)
+ {
+ return _protocol;
+ }
+ }
+
+ /// <summary>
+ /// Sets the connect and connection timeout for the Glacier2 router.
+ /// </summary>
+ /// <param name="timeoutMillisecs">The timeout in milliseconds. A zero
+ /// or negative timeout value indicates that the router proxy has no
+ /// associated timeout.</param>
+ public void
+ setTimeout(int timeoutMillisecs)
+ {
+ lock(this)
+ {
+ _timeout = timeoutMillisecs;
+ }
+ }
+
+ /// <summary>
+ /// Returns the connect and connection timeout associated with the Glacier2 router.
+ /// </summary>
+ /// <returns>The timeout.</returns>
+ public int
+ getTimeout()
+ {
+ lock(this)
+ {
+ return _timeout;
+ }
+ }
+
+ /// <summary>
+ /// Sets the Glacier2 router port to connect to.
+ /// </summary>
+ /// <param name="port">The port. If 0, then the default port (4063 for TCP or
+ /// 4064 for SSL) is used.</param>
+ public void
+ setPort(int port)
+ {
+ lock(this)
+ {
+ _port = port;
+ }
+ }
+
+ /// <summary>
+ /// Returns the Glacier2 router port to connect to.
+ /// </summary>
+ /// <returns>The port.</returns>
+ public int
+ getPort()
+ {
+ lock(this)
+ {
+ return getPortInternal();
+ }
+ }
+
+ private int
+ getPortInternal()
+ {
+ return _port == 0 ? ((_protocol.Equals("ssl") ||
+ _protocol.Equals("wss"))? GLACIER2_SSL_PORT : GLACIER2_TCP_PORT) : _port;
+ }
+
+ /**
+ * Returns the initialization data used to initialize the communicator.
+ *
+ * @return The initialization data.
+ */
+ public Ice.InitializationData
+ getInitializationData()
+ {
+ lock(this)
+ {
+ return _initData;
+ }
+ }
+
+ /// <summary>
+ /// Sets the request context to use while establishing a connection to the Glacier2 router.
+ /// </summary>
+ /// <param name="context">The request context.</param>
+ public void
+ setConnectContext(Dictionary<string, string> context)
+ {
+ lock(this)
+ {
+ _context = context;
+ }
+ }
+
+ /// <summary>
+ /// Determines whether the session should create an object adapter that the client
+ /// can use for receiving callbacks.
+ /// </summary>
+ /// <param name="useCallbacks">True if the session should create an object adapter.</param>
+ public void
+ setUseCallbacks(bool useCallbacks)
+ {
+ lock(this)
+ {
+ _useCallbacks = useCallbacks;
+ }
+ }
+
+ /// <summary>
+ /// Indicates whether a newly-created session will also create an object adapter that
+ /// the client can use for receiving callbaks.
+ /// </summary>
+ /// <returns>True if the session will create an object adapter.</returns>
+ public bool
+ getUseCallbacks()
+ {
+ lock(this)
+ {
+ return _useCallbacks;
+ }
+ }
+
+ /// <summary>
+ /// Connects to the Glacier2 router using the associated SSL credentials.
+ ///
+ /// Once the connection is established, SesssionCallback.connected is called on
+ /// the callback object; upon failure, SessionCallback.connectFailed is called
+ /// with the exception.
+ /// </summary>
+ /// <returns>The connected session.</returns>
+ public SessionHelper
+ connect()
+ {
+ lock(this)
+ {
+ SessionHelper session = new SessionHelper(_callback, createInitData(), getRouterFinderStr(), _useCallbacks);
+ session.connect(_context);
+ return session;
+ }
+ }
+
+ /// <summary>
+ /// Connect the Glacier2 session using user name and password credentials.
+ ///
+ /// Once the connection is established, SessionCallback.connected is called on
+ /// the callback object; upon failure, SessionCallback.connectFailed is called
+ /// with the exception.
+ /// </summary>
+ /// <param name="username">The user name.</param>
+ /// <param name="password">The password.</param>
+ /// <returns>The connected session.</returns>
+ public SessionHelper
+ connect( string username, string password)
+ {
+ lock(this)
+ {
+ SessionHelper session = new SessionHelper(_callback, createInitData(), getRouterFinderStr(), _useCallbacks);
+ session.connect(username, password, _context);
+ return session;
+ }
+ }
+
+ private Ice.InitializationData
+ createInitData()
+ {
+ //
+ // Clone the initialization data and properties.
+ //
+ Ice.InitializationData initData = (Ice.InitializationData)_initData.Clone();
+ initData.properties = initData.properties.ice_clone_();
+
+ if(initData.properties.getProperty("Ice.Default.Router").Length == 0 && _identity != null)
+ {
+ initData.properties.setProperty("Ice.Default.Router", createProxyStr(_identity));
+ }
+
+ //
+ // If using a secure connection setup the IceSSL plug-in, if IceSSL
+ // plug-in has already been setup we don't want to override the
+ // configuration so it can be loaded from a custom location.
+ //
+ if((_protocol.Equals("ssl") || _protocol.Equals("wss")) &&
+ initData.properties.getProperty("Ice.Plugin.IceSSL").Length == 0)
+ {
+ initData.properties.setProperty("Ice.Plugin.IceSSL", "IceSSL:IceSSL.PluginFactory");
+ }
+
+ return initData;
+ }
+
+ private string
+ getRouterFinderStr()
+ {
+ Ice.Identity ident = new Ice.Identity("RouterFinder", "Ice");
+ return createProxyStr(ident);
+ }
+
+ private string
+ createProxyStr(Ice.Identity ident)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("\"");
+ sb.Append(Ice.Util.identityToString(ident));
+ sb.Append("\":");
+ sb.Append(_protocol + " -p ");
+ sb.Append(getPortInternal());
+ sb.Append(" -h \"");
+ sb.Append(_routerHost);
+ sb.Append("\"");
+ if(_timeout > 0)
+ {
+ sb.Append(" -t ");
+ sb.Append(_timeout);
+ }
+ return sb.ToString();
+ }
+
+ private void
+ setDefaultProperties()
+ {
+ _initData.properties.setProperty("Ice.RetryIntervals", "-1");
+ }
+
+ private SessionCallback _callback;
+ private string _routerHost = "localhost";
+ private Ice.InitializationData _initData;
+ private Ice.Identity _identity = null;
+ private string _protocol = "ssl";
+ private int _port = 0;
+ private int _timeout = 10000;
+ private Dictionary<string, string> _context;
+ private bool _useCallbacks = true;
+ private static int GLACIER2_SSL_PORT = 4064;
+ private static int GLACIER2_TCP_PORT = 4063;
+}
+
+}
diff --git a/csharp/src/Glacier2/SessionHelper.cs b/csharp/src/Glacier2/SessionHelper.cs
new file mode 100644
index 00000000000..f9432d6003f
--- /dev/null
+++ b/csharp/src/Glacier2/SessionHelper.cs
@@ -0,0 +1,526 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace Glacier2
+{
+
+/// <summary>
+/// A helper class for using Glacier2 with GUI applications.
+/// </summary>
+public class SessionHelper
+{
+ private class ConnectionCallbackI : Ice.ConnectionCallback
+ {
+ internal ConnectionCallbackI(SessionHelper sessionHelper)
+ {
+ _sessionHelper = sessionHelper;
+ }
+
+ public void heartbeat(Ice.Connection con)
+ {
+
+ }
+
+ public void closed(Ice.Connection con)
+ {
+ _sessionHelper.destroy();
+ }
+
+ private readonly SessionHelper _sessionHelper;
+ }
+
+ /// <summary>
+ /// Creates a Glacier2 session.
+ /// </summary>
+ /// <param name="callback">The callback for notifications about session
+ /// establishment.</param>
+ /// <param name="initData">The Ice.InitializationData for initializing
+ /// the communicator.</param>
+ /// <param name="finderStr">The stringified Ice.RouterFinder proxy.</param>
+ /// <param name="useCallbacks">True if the session should create an object adapter for receiving callbacks.</param>
+ public SessionHelper(SessionCallback callback, Ice.InitializationData initData, string finderStr, bool useCallbacks)
+ {
+ _callback = callback;
+ _initData = initData;
+ _finderStr = finderStr;
+ _useCallbacks = useCallbacks;
+ }
+
+ /// <summary>
+ /// Destroys the Glacier2 session.
+ ///
+ /// Once the session has been destroyed, SessionCallback.disconnected is
+ /// called on the associated callback object.
+ /// </summary>
+ public void
+ destroy()
+ {
+ lock(this)
+ {
+ if(_destroy)
+ {
+ return;
+ }
+ _destroy = true;
+ if(!_connected)
+ {
+ //
+ // In this case a connecting session is being
+ // destroyed. The communicator and session will be
+ // destroyed when the connection establishment has
+ // completed.
+ //
+ return;
+ }
+ _session = null;
+ _connected = false;
+ //
+ // Run destroyInternal in a thread because it makes remote invocations.
+ //
+ Thread t = new Thread(new ThreadStart(destroyInternal));
+ t.Start();
+ }
+ }
+
+ /// <summary>
+ /// Returns the session's communicator object.
+ /// </summary>
+ /// <returns>The communicator.</returns>
+ public Ice.Communicator
+ communicator()
+ {
+ lock(this)
+ {
+ return _communicator;
+ }
+ }
+
+ /// <summary>
+ /// Returns the category to be used in the identities of all of
+ /// the client's callback objects. Clients must use this category
+ /// for the router to forward callback requests to the intended
+ /// client.
+ /// </summary>
+ /// <returns>The category. Throws SessionNotExistException
+ /// No session exists</returns>
+ public string
+ categoryForClient()
+ {
+ lock(this)
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+
+ return _category;
+ }
+ }
+
+ /// <summary>
+ /// Adds a servant to the callback object adapter's Active Servant
+ /// Map with a UUID.
+ /// </summary>
+ /// <param name="servant">The servant to add.</param>
+ /// <returns>The proxy for the servant. Throws SessionNotExistException
+ /// if no session exists.</returns>
+ public Ice.ObjectPrx
+ addWithUUID(Ice.Object servant)
+ {
+ lock(this)
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+
+ return internalObjectAdapter().add(servant, new Ice.Identity(Guid.NewGuid().ToString(), _category));
+ }
+ }
+
+ /// <summary>
+ /// Returns the Glacier2 session proxy. If the session hasn't been
+ /// established yet, or the session has already been destroyed,
+ /// throws SessionNotExistException.
+ /// </summary>
+ /// <returns>The session proxy, or throws SessionNotExistException
+ /// if no session exists.</returns>
+ public Glacier2.SessionPrx
+ session()
+ {
+ lock(this)
+ {
+ if(_session == null)
+ {
+ throw new SessionNotExistException();
+ }
+ return _session;
+ }
+ }
+
+ /// <summary>
+ /// Returns true if there is an active session, otherwise returns false.
+ /// </summary>
+ /// <returns>true if session exists or false if no session exists.</returns>
+ public bool
+ isConnected()
+ {
+ lock(this)
+ {
+ return _connected;
+ }
+ }
+
+ /// <summary>
+ /// Returns an object adapter for callback objects, creating it if necessary.
+ /// </summary>
+ /// <return>The object adapter. Throws SessionNotExistException
+ /// if no session exists.</return>
+ public Ice.ObjectAdapter
+ objectAdapter()
+ {
+ return internalObjectAdapter();
+ }
+
+ private Ice.ObjectAdapter
+ internalObjectAdapter()
+ {
+ lock(this)
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+ if(!_useCallbacks)
+ {
+ throw new Ice.InitializationException(
+ "Object adapter not available, call SessionFactoryHelper.setUseCallbacks(true)");
+ }
+ return _adapter;
+ }
+ }
+
+ /// <summary>
+ /// Connects to the Glacier2 router using the associated SSL credentials.
+ ///
+ /// Once the connection is established, SessionCallback.connected is called on
+ /// the callback object; upon failure, SessionCallback.exception is called with
+ /// the exception.
+ /// </summary>
+ /// <param name="context">The request context to use when creating the session.</param>
+ public void
+ connect(Dictionary<string, string> context)
+ {
+ lock(this)
+ {
+ connectImpl((RouterPrx router) =>
+ {
+ return router.createSessionFromSecureConnection(context);
+ });
+ }
+ }
+
+ /// <summary>
+ /// Connects a Glacier2 session using user name and password credentials.
+ ///
+ /// Once the connection is established, SessionCallback.connected is called on the callback object;
+ /// upon failure SessionCallback.exception is called with the exception.
+ /// </summary>
+ /// <param name="username">The user name.</param>
+ /// <param name="password">The password.</param>
+ /// <param name="context">The request context to use when creating the session.</param>
+ public void
+ connect(string username, string password, Dictionary<string, string> context)
+ {
+ lock(this)
+ {
+ connectImpl((RouterPrx router) =>
+ {
+ return router.createSession(username, password, context);
+ });
+ }
+ }
+
+ private void
+ connected(RouterPrx router, SessionPrx session)
+ {
+ //
+ // Remote invocation should be done without acquiring a mutex lock.
+ //
+ Debug.Assert(router != null);
+ Ice.Connection conn = router.ice_getCachedConnection();
+ string category = router.getCategoryForClient();
+ int acmTimeout = 0;
+ try
+ {
+ acmTimeout = router.getACMTimeout();
+ }
+ catch(Ice.OperationNotExistException)
+ {
+ }
+
+ if(acmTimeout <= 0)
+ {
+ acmTimeout = (int)router.getSessionTimeout();
+ }
+
+ //
+ // We create the callback object adapter here because createObjectAdapter internally
+ // makes synchronous RPCs to the router. We can't create the OA on-demand when the
+ // client calls objectAdapter() or addWithUUID() because they can be called from the
+ // GUI thread.
+ //
+ if(_useCallbacks)
+ {
+ Debug.Assert(_adapter == null);
+ _adapter = _communicator.createObjectAdapterWithRouter("", router);
+ _adapter.activate();
+ }
+
+ lock(this)
+ {
+ _router = router;
+
+ if(_destroy)
+ {
+ //
+ // Run destroyInternal in a thread because it makes remote invocations.
+ //
+ Thread t = new Thread(new ThreadStart(destroyInternal));
+ t.Start();
+ return;
+ }
+
+ //
+ // Cache the category.
+ //
+ _category = category;
+
+ //
+ // Assign the session after _destroy is checked.
+ //
+ _session = session;
+ _connected = true;
+
+ if(acmTimeout > 0)
+ {
+ Ice.Connection connection = _router.ice_getCachedConnection();
+ Debug.Assert(connection != null);
+ connection.setACM(acmTimeout, Ice.Util.None, Ice.ACMHeartbeat.HeartbeatAlways);
+ connection.setCallback(new ConnectionCallbackI(this));
+ }
+ }
+
+ dispatchCallback(() =>
+ {
+ try
+ {
+ _callback.connected(this);
+ }
+ catch(Glacier2.SessionNotExistException)
+ {
+ destroy();
+ }
+ }, conn);
+ }
+
+ private void
+ destroyInternal()
+ {
+ Glacier2.RouterPrx router;
+ Ice.Communicator communicator;
+ lock(this)
+ {
+ Debug.Assert(_destroy);
+ if(_router == null)
+ {
+ return;
+ }
+ router = _router;
+ _router = null;
+
+ communicator = _communicator;
+
+ Debug.Assert(communicator != null);
+ }
+
+ try
+ {
+ router.destroySession();
+ }
+ catch(Ice.ConnectionLostException)
+ {
+ //
+ // Expected if another thread invoked on an object from the session concurrently.
+ //
+ }
+ catch(SessionNotExistException)
+ {
+ //
+ // This can also occur.
+ //
+ }
+ catch(Exception e)
+ {
+ //
+ // Not expected.
+ //
+ communicator.getLogger().warning("SessionHelper: unexpected exception when destroying the session:\n" + e);
+ }
+
+ try
+ {
+ communicator.destroy();
+ }
+ catch(Exception)
+ {
+ }
+
+ // Notify the callback that the session is gone.
+ dispatchCallback(() =>
+ {
+ _callback.disconnected(this);
+ }, null);
+ }
+
+ delegate Glacier2.SessionPrx ConnectStrategy(Glacier2.RouterPrx router);
+
+ private void
+ connectImpl(ConnectStrategy factory)
+ {
+ Debug.Assert(!_destroy);
+
+ try
+ {
+ _communicator = Ice.Util.initialize(_initData);
+ }
+ catch(Ice.LocalException ex)
+ {
+ _destroy = true;
+ new Thread(
+ new ThreadStart(() =>
+ {
+ dispatchCallback(() =>
+ {
+ _callback.connectFailed(this, ex);
+ },
+ null);
+ })).Start();
+ return;
+ }
+
+ Ice.RouterFinderPrx finder = Ice.RouterFinderPrxHelper.uncheckedCast(_communicator.stringToProxy(_finderStr));
+ new Thread(new ThreadStart(() =>
+ {
+ if(_communicator.getDefaultRouter() == null)
+ {
+ try
+ {
+ _communicator.setDefaultRouter(finder.getRouter());
+ }
+ catch(Exception)
+ {
+ //
+ // In case of error getting router identity from RouterFinder use default identity.
+ //
+ Ice.Identity ident = new Ice.Identity("router", "Glacier2");
+ _communicator.setDefaultRouter(Ice.RouterPrxHelper.uncheckedCast(finder.ice_identity(ident)));
+ }
+ }
+
+ try
+ {
+ dispatchCallbackAndWait(() =>
+ {
+ _callback.createdCommunicator(this);
+ });
+
+ Glacier2.RouterPrx routerPrx = Glacier2.RouterPrxHelper.uncheckedCast(_communicator.getDefaultRouter());
+ Glacier2.SessionPrx session = factory(routerPrx);
+ connected(routerPrx, session);
+ }
+ catch(Exception ex)
+ {
+ try
+ {
+ _communicator.destroy();
+ }
+ catch(Exception)
+ {
+ }
+ dispatchCallback(() =>
+ {
+ _callback.connectFailed(this, ex);
+ }, null);
+ }
+ })).Start();
+ }
+
+#if COMPACT
+ private void
+ dispatchCallback(Ice.VoidAction callback, Ice.Connection conn)
+#else
+ private void
+ dispatchCallback(System.Action callback, Ice.Connection conn)
+#endif
+ {
+ if(_initData.dispatcher != null)
+ {
+ _initData.dispatcher(callback, conn);
+ }
+ else
+ {
+ callback();
+ }
+ }
+
+#if COMPACT
+ private void
+ dispatchCallbackAndWait(Ice.VoidAction callback)
+#else
+ private void
+ dispatchCallbackAndWait(System.Action callback)
+#endif
+ {
+ if(_initData.dispatcher != null)
+ {
+ EventWaitHandle h = new ManualResetEvent(false);
+ _initData.dispatcher(() =>
+ {
+ callback();
+ h.Set();
+ }, null);
+ h.WaitOne();
+ }
+ else
+ {
+ callback();
+ }
+ }
+
+ private readonly Ice.InitializationData _initData;
+ private Ice.Communicator _communicator;
+ private Ice.ObjectAdapter _adapter;
+ private Glacier2.RouterPrx _router;
+ private Glacier2.SessionPrx _session;
+ private bool _connected = false;
+ private string _category;
+ private string _finderStr;
+ private bool _useCallbacks;
+
+ private readonly SessionCallback _callback;
+ private bool _destroy = false;
+}
+
+}
diff --git a/csharp/src/Glacier2/generated/.gitignore b/csharp/src/Glacier2/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/Glacier2/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/Ice/.depend.mak b/csharp/src/Ice/.depend.mak
new file mode 100644
index 00000000000..48e527e7f4a
--- /dev/null
+++ b/csharp/src/Ice/.depend.mak
@@ -0,0 +1,144 @@
+
+BuiltinSequences.cs: \
+ "$(slicedir)\Ice\BuiltinSequences.ice"
+
+Communicator.cs: \
+ "$(slicedir)\Ice\Communicator.ice" \
+ "$(slicedir)/Ice/LoggerF.ice" \
+ "$(slicedir)/Ice/InstrumentationF.ice" \
+ "$(slicedir)/Ice/ObjectAdapterF.ice" \
+ "$(slicedir)/Ice/ObjectFactoryF.ice" \
+ "$(slicedir)/Ice/RouterF.ice" \
+ "$(slicedir)/Ice/LocatorF.ice" \
+ "$(slicedir)/Ice/PluginF.ice" \
+ "$(slicedir)/Ice/ImplicitContextF.ice" \
+ "$(slicedir)/Ice/Current.ice" \
+ "$(slicedir)/Ice/ConnectionF.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/Properties.ice" \
+ "$(slicedir)/Ice/PropertiesAdmin.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/FacetMap.ice"
+
+Connection.cs: \
+ "$(slicedir)\Ice\Connection.ice" \
+ "$(slicedir)/Ice/ObjectAdapterF.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Endpoint.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/EndpointF.ice"
+
+Current.cs: \
+ "$(slicedir)\Ice\Current.ice" \
+ "$(slicedir)/Ice/ObjectAdapterF.ice" \
+ "$(slicedir)/Ice/ConnectionF.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Version.ice"
+
+Endpoint.cs: \
+ "$(slicedir)\Ice\Endpoint.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/EndpointF.ice"
+
+EndpointTypes.cs: \
+ "$(slicedir)\Ice\EndpointTypes.ice"
+
+FacetMap.cs: \
+ "$(slicedir)\Ice\FacetMap.ice"
+
+Identity.cs: \
+ "$(slicedir)\Ice\Identity.ice"
+
+ImplicitContext.cs: \
+ "$(slicedir)\Ice\ImplicitContext.ice" \
+ "$(slicedir)/Ice/LocalException.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/Current.ice" \
+ "$(slicedir)/Ice/ObjectAdapterF.ice" \
+ "$(slicedir)/Ice/ConnectionF.ice"
+
+Instrumentation.cs: \
+ "$(slicedir)\Ice\Instrumentation.ice" \
+ "$(slicedir)/Ice/EndpointF.ice" \
+ "$(slicedir)/Ice/ConnectionF.ice" \
+ "$(slicedir)/Ice/Current.ice" \
+ "$(slicedir)/Ice/ObjectAdapterF.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Version.ice"
+
+LocalException.cs: \
+ "$(slicedir)\Ice\LocalException.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+Locator.cs: \
+ "$(slicedir)\Ice\Locator.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/ProcessF.ice"
+
+Logger.cs: \
+ "$(slicedir)\Ice\Logger.ice"
+
+Metrics.cs: \
+ "$(slicedir)\Ice\Metrics.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+ObjectAdapter.cs: \
+ "$(slicedir)\Ice\ObjectAdapter.ice" \
+ "$(slicedir)/Ice/CommunicatorF.ice" \
+ "$(slicedir)/Ice/ServantLocatorF.ice" \
+ "$(slicedir)/Ice/LocatorF.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/FacetMap.ice" \
+ "$(slicedir)/Ice/Endpoint.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/EndpointF.ice"
+
+ObjectFactory.cs: \
+ "$(slicedir)\Ice\ObjectFactory.ice"
+
+Plugin.cs: \
+ "$(slicedir)\Ice\Plugin.ice" \
+ "$(slicedir)/Ice/LoggerF.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+Process.cs: \
+ "$(slicedir)\Ice\Process.ice"
+
+Properties.cs: \
+ "$(slicedir)\Ice\Properties.ice" \
+ "$(slicedir)/Ice/PropertiesAdmin.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+PropertiesAdmin.cs: \
+ "$(slicedir)\Ice\PropertiesAdmin.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+RemoteLogger.cs: \
+ "$(slicedir)\Ice\RemoteLogger.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+Router.cs: \
+ "$(slicedir)\Ice\Router.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+ServantLocator.cs: \
+ "$(slicedir)\Ice\ServantLocator.ice" \
+ "$(slicedir)/Ice/ObjectAdapterF.ice" \
+ "$(slicedir)/Ice/Current.ice" \
+ "$(slicedir)/Ice/ConnectionF.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Version.ice"
+
+SliceChecksumDict.cs: \
+ "$(slicedir)\Ice\SliceChecksumDict.ice"
+
+Version.cs: \
+ "$(slicedir)\Ice\Version.ice"
diff --git a/csharp/src/Ice/ACM.cs b/csharp/src/Ice/ACM.cs
new file mode 100644
index 00000000000..33936b81907
--- /dev/null
+++ b/csharp/src/Ice/ACM.cs
@@ -0,0 +1,356 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Diagnostics;
+ using System.Collections.Generic;
+
+ public sealed class ACMConfig : System.ICloneable
+ {
+ internal ACMConfig(bool server)
+ {
+ timeout = 60 * 1000;
+ heartbeat = Ice.ACMHeartbeat.HeartbeatOnInvocation;
+ close = server ? Ice.ACMClose.CloseOnInvocation : Ice.ACMClose.CloseOnInvocationAndIdle;
+ }
+
+ public ACMConfig(Ice.Properties p, Ice.Logger l, string prefix, ACMConfig dflt)
+ {
+ Debug.Assert(prefix != null);
+
+ string timeoutProperty;
+ if((prefix.Equals("Ice.ACM.Client") || prefix.Equals("Ice.ACM.Server")) &&
+ p.getProperty(prefix + ".Timeout").Length == 0)
+ {
+ timeoutProperty = prefix; // Deprecated property.
+ }
+ else
+ {
+ timeoutProperty = prefix + ".Timeout";
+ };
+
+ timeout = p.getPropertyAsIntWithDefault(timeoutProperty, dflt.timeout / 1000) * 1000;
+
+ int hb = p.getPropertyAsIntWithDefault(prefix + ".Heartbeat", (int)dflt.heartbeat);
+ if(hb >= (int)Ice.ACMHeartbeat.HeartbeatOff && hb <= (int)Ice.ACMHeartbeat.HeartbeatAlways)
+ {
+ heartbeat = (Ice.ACMHeartbeat)hb;
+ }
+ else
+ {
+ l.warning("invalid value for property `" + prefix + ".Heartbeat" +
+ "', default value will be used instead");
+ heartbeat = dflt.heartbeat;
+ }
+
+ int cl = p.getPropertyAsIntWithDefault(prefix + ".Close", (int)dflt.close);
+ if(cl >= (int)Ice.ACMClose.CloseOff && cl <= (int)Ice.ACMClose.CloseOnIdleForceful)
+ {
+ close = (Ice.ACMClose)cl;
+ }
+ else
+ {
+ l.warning("invalid value for property `" + prefix + ".Close" +
+ "', default value will be used instead");
+ close = dflt.close;
+ }
+ }
+
+ public object Clone()
+ {
+ return this.MemberwiseClone();
+ }
+
+ public int timeout;
+ public Ice.ACMHeartbeat heartbeat;
+ public Ice.ACMClose close;
+ };
+
+ public interface ACMMonitor : TimerTask
+ {
+ void add(Ice.ConnectionI con);
+ void remove(Ice.ConnectionI con);
+ void reap(Ice.ConnectionI con);
+
+ ACMMonitor acm(Ice.Optional<int> timeout, Ice.Optional<Ice.ACMClose> c, Ice.Optional<Ice.ACMHeartbeat> h);
+ Ice.ACM getACM();
+ };
+
+ class FactoryACMMonitor : ACMMonitor
+ {
+ internal class Change
+ {
+ internal Change(Ice.ConnectionI connection, bool remove)
+ {
+ this.connection = connection;
+ this.remove = remove;
+ }
+
+ public readonly Ice.ConnectionI connection;
+ public readonly bool remove;
+ };
+
+ internal FactoryACMMonitor(Instance instance, ACMConfig config)
+ {
+ _instance = instance;
+ _config = config;
+ }
+
+ internal void destroy()
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ return;
+ }
+ _instance = null;
+ _connections.Clear();
+ _changes.Clear();
+ }
+ }
+
+ public void add(Ice.ConnectionI connection)
+ {
+ if(_config.timeout == 0)
+ {
+ return;
+ }
+
+ lock(this)
+ {
+ if(_connections.Count == 0)
+ {
+ _connections.Add(connection);
+ _instance.timer().scheduleRepeated(this, _config.timeout / 2);
+ }
+ else
+ {
+ _changes.Add(new Change(connection, false));
+ }
+ }
+ }
+
+ public void remove(Ice.ConnectionI connection)
+ {
+ if(_config.timeout == 0)
+ {
+ return;
+ }
+
+ lock(this)
+ {
+ Debug.Assert(_instance != null);
+ _changes.Add(new Change(connection, true));
+ }
+ }
+
+ public void reap(Ice.ConnectionI connection)
+ {
+ lock(this)
+ {
+ _reapedConnections.Add(connection);
+ }
+ }
+
+ public ACMMonitor acm(Ice.Optional<int> timeout, Ice.Optional<Ice.ACMClose> c, Ice.Optional<Ice.ACMHeartbeat> h)
+ {
+ Debug.Assert(_instance != null);
+
+ ACMConfig config = (ACMConfig)_config.Clone();
+ if(timeout.HasValue)
+ {
+ config.timeout = timeout.Value * 1000; // To milliseconds
+ }
+ if(c.HasValue)
+ {
+ config.close = c.Value;
+ }
+ if(h.HasValue)
+ {
+ config.heartbeat = h.Value;
+ }
+ return new ConnectionACMMonitor(this, _instance.timer(), config);
+ }
+
+ public Ice.ACM getACM()
+ {
+ Ice.ACM acm = new Ice.ACM();
+ acm.timeout = _config.timeout / 1000;
+ acm.close = _config.close;
+ acm.heartbeat = _config.heartbeat;
+ return acm;
+ }
+
+ internal List<Ice.ConnectionI> swapReapedConnections()
+ {
+ lock(this)
+ {
+ if(_reapedConnections.Count == 0)
+ {
+ return null;
+ }
+ List<Ice.ConnectionI> connections = _reapedConnections;
+ _reapedConnections = new List<Ice.ConnectionI>();
+ return connections;
+ }
+ }
+
+ public void runTimerTask()
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ return;
+ }
+
+ foreach(Change change in _changes)
+ {
+ if(change.remove)
+ {
+ _connections.Remove(change.connection);
+ }
+ else
+ {
+ _connections.Add(change.connection);
+ }
+ }
+ _changes.Clear();
+
+ if(_connections.Count == 0)
+ {
+ _instance.timer().cancel(this);
+ return;
+ }
+ }
+
+
+ //
+ // Monitor connections outside the thread synchronization, so
+ // that connections can be added or removed during monitoring.
+ //
+ long now = Time.currentMonotonicTimeMillis();
+ foreach(Ice.ConnectionI connection in _connections)
+ {
+ try
+ {
+ connection.monitor(now, _config);
+ }
+ catch(System.Exception ex)
+ {
+ handleException(ex);
+ }
+ }
+ }
+
+ internal void handleException(System.Exception ex)
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ return;
+ }
+ _instance.initializationData().logger.error("exception in connection monitor:\n" + ex);
+ }
+ }
+
+ private Instance _instance;
+ readonly private ACMConfig _config;
+
+ private HashSet<Ice.ConnectionI> _connections = new HashSet<Ice.ConnectionI>();
+ private List<Change> _changes = new List<Change>();
+ private List<Ice.ConnectionI> _reapedConnections = new List<Ice.ConnectionI>();
+ };
+
+ internal class ConnectionACMMonitor : ACMMonitor
+ {
+ internal ConnectionACMMonitor(FactoryACMMonitor parent, Timer timer, ACMConfig config)
+ {
+ _parent = parent;
+ _timer = timer;
+ _config = config;
+ }
+
+ public void add(Ice.ConnectionI connection)
+ {
+ lock(this)
+ {
+ Debug.Assert(_connection == null);
+ _connection = connection;
+ if(_config.timeout > 0)
+ {
+ _timer.scheduleRepeated(this, _config.timeout / 2);
+ }
+ }
+ }
+
+ public void remove(Ice.ConnectionI connection)
+ {
+ lock(this)
+ {
+ Debug.Assert(_connection == connection);
+ _connection = null;
+ if(_config.timeout > 0)
+ {
+ _timer.cancel(this);
+ }
+ }
+ }
+
+ public void reap(Ice.ConnectionI connection)
+ {
+ _parent.reap(connection);
+ }
+
+ public ACMMonitor acm(Ice.Optional<int> timeout, Ice.Optional<Ice.ACMClose> c, Ice.Optional<Ice.ACMHeartbeat> h)
+ {
+ return _parent.acm(timeout, c, h);
+ }
+
+ public Ice.ACM getACM()
+ {
+ Ice.ACM acm = new Ice.ACM();
+ acm.timeout = _config.timeout / 1000;
+ acm.close = _config.close;
+ acm.heartbeat = _config.heartbeat;
+ return acm;
+ }
+
+ public void runTimerTask()
+ {
+ Ice.ConnectionI connection;
+ lock(this)
+ {
+ if(_connection == null)
+ {
+ return;
+ }
+ connection = _connection;
+ }
+
+ try
+ {
+ connection.monitor(Time.currentMonotonicTimeMillis(), _config);
+ }
+ catch(System.Exception ex)
+ {
+ _parent.handleException(ex);
+ }
+ }
+
+ readonly private FactoryACMMonitor _parent;
+ readonly private Timer _timer;
+ readonly private ACMConfig _config;
+
+ private Ice.ConnectionI _connection;
+ };
+} \ No newline at end of file
diff --git a/csharp/src/Ice/AMDCallback.cs b/csharp/src/Ice/AMDCallback.cs
new file mode 100644
index 00000000000..b4b9889c350
--- /dev/null
+++ b/csharp/src/Ice/AMDCallback.cs
@@ -0,0 +1,26 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ /// <summary>
+ /// AMDCallback is the interface from which all AMD callbacks are derived.
+ /// </summary>
+ public interface AMDCallback
+ {
+ /// <summary>
+ /// Indicates to the Ice run time that an operation completed
+ /// with a run-time exception.
+ /// </summary>
+ /// <param name="ex">The encoded Ice run-time exception. Note that, if ex
+ /// is a user exception, the caller receives UnknownUserException.
+ /// Use ice_response to raise user exceptions.</param>
+ void ice_exception(System.Exception ex);
+ }
+}
diff --git a/csharp/src/Ice/Acceptor.cs b/csharp/src/Ice/Acceptor.cs
new file mode 100644
index 00000000000..33cef1e1548
--- /dev/null
+++ b/csharp/src/Ice/Acceptor.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System;
+ using System.Net.Sockets;
+
+ public interface Acceptor
+ {
+ void close();
+ EndpointI listen();
+ bool startAccept(AsyncCallback callback, object state);
+ void finishAccept();
+ Transceiver accept();
+ string protocol();
+ string ToString();
+ string toDetailedString();
+ }
+
+}
diff --git a/csharp/src/Ice/Application.cs b/csharp/src/Ice/Application.cs
new file mode 100644
index 00000000000..937d5e7f801
--- /dev/null
+++ b/csharp/src/Ice/Application.cs
@@ -0,0 +1,936 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#if !SILVERLIGHT
+
+namespace Ice
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Reflection;
+ using System.Runtime.InteropServices;
+ using System.Threading;
+
+ internal static class NativeMethods
+ {
+#if !COMPACT && !UNITY
+ //
+ // Technically it's not necessary to wrap DllImport in conditional compilation because
+ // the binding occurs at run time and it will never be executed on Mono. However, it
+ // causes problems for the Compact Framework.
+ //
+ [DllImport("kernel32.dll")]
+ [return: MarshalAsAttribute(UnmanagedType.Bool)]
+ internal static extern bool
+ SetConsoleCtrlHandler(CtrlCEventHandler eh, [MarshalAsAttribute(UnmanagedType.Bool)]bool add);
+#endif
+ }
+
+ /// <summary>
+ /// The signal policy for Ice.Application signal handling.
+ /// </summary>
+ public enum SignalPolicy
+ {
+ /// <summary>
+ /// If a signal is received, Ice.Application reacts to the signal
+ /// by calling Communicator.destroy or Communicator.shutdown,
+ /// or by calling a custom shutdown hook installed by the application.
+ /// </summary>
+ HandleSignals,
+
+ /// <summary>
+ /// Any signal that is received is not intercepted and takes the default action.
+ /// </summary>
+ NoSignalHandling
+ }
+
+ /// <summary>
+ /// Utility base class that makes it easy to correctly initialize and finalize
+ /// the Ice run time, as well as handle signals. Unless the application specifies
+ /// a logger, Application installs a per-process logger that logs to the standard
+ /// error output.
+ /// Applications must create a derived class that implements the run method.
+ /// A program can contain only one instance of this class.
+ /// </summary>
+ public abstract class Application
+ {
+ /// <summary>
+ /// Called once the communicator has been initialized. The derived class must
+ /// implement run, which is the application's starting method.
+ /// </summary>
+ /// <param name="args">The argument vector for the application. Application
+ /// scans the argument vector passed to main for options that are
+ /// specific to the Ice run time and removes them; therefore, the vector passed
+ /// to run is free from Ice-related options and contains only options
+ /// and arguments that are application-specific.</param>
+ /// <returns>The run method should return zero for successful termination, and
+ /// non-zero otherwise. Application.main returns the value returned by run.</returns>
+ public abstract int run(string[] args);
+
+ /// <summary>
+ /// Override this method to provide a custom application interrupt
+ /// hook. You must call callbackOnInterrupt for this method
+ /// to be called. Note that the interruptCallback can be called
+ /// concurrently with any other thread (including main) in your
+ /// application--take appropriate concurrency precautions.
+ /// </summary>
+ /// <param name="sig">The cause of the interrupt.</param>
+ public virtual void interruptCallback(int sig)
+ {
+ }
+
+ /// <summary>
+ /// Initializes an instance that calls Communicator.shutdown if a signal is received.
+ /// </summary>
+ public Application()
+ {
+ }
+
+ /// <summary>
+ /// Initializes an instance that handles signals according to the signal policy.
+ /// </summary>
+ /// <param name="signalPolicy">Determines how to respond to signals.</param>
+ public Application(SignalPolicy signalPolicy)
+ {
+ signalPolicy__ = signalPolicy;
+ }
+
+ /// <summary>
+ /// The application must call main after it has
+ /// instantiated the derived class. main creates
+ /// a communicator, establishes the specified signal policy, and,
+ /// once run returns, destroys the communicator.
+ /// The method prints an error message for any exception that propagates
+ /// out of run and ensures that the communicator is
+ /// destroyed correctly even if run completes abnormally.
+ /// </summary>
+ /// <param name="args">The arguments for the application (as passed to Main(string[])
+ /// by the operating system.</param>
+ /// <returns>The value returned by run. If run terminates with an exception,
+ /// the return value is non-zero.</returns>
+ public int main(string[] args)
+ {
+ return main(args, new InitializationData());
+ }
+
+ /// <summary>
+ /// The application must call main after it has
+ /// instantiated the derived class. main creates
+ /// a communicator, establishes the specified signal policy, and,
+ /// once run returns, destroys the communicator.
+ /// The method prints an error message for any exception that propagates
+ /// out of run and ensures that the communicator is
+ /// destroyed correctly even if run completes abnormally.
+ /// </summary>
+ /// <param name="args">The arguments for the application (as passed to Main(string[])
+ /// by the operating system.</param>
+ /// <param name="configFile">The configuration file with which to initialize
+ /// Ice properties.</param>
+ /// <returns>The value returned by run. If run terminates with an exception,
+ /// the return value is non-zero.</returns>
+ public int main(string[] args, string configFile)
+ {
+ if(Util.getProcessLogger() is ConsoleLoggerI)
+ {
+ Util.setProcessLogger(new ConsoleLoggerI(appName__));
+ }
+
+ InitializationData initData = new InitializationData();
+ if(configFile != null)
+ {
+ try
+ {
+ initData.properties = Util.createProperties();
+ initData.properties.load(configFile);
+ }
+ catch(Ice.Exception ex)
+ {
+ Util.getProcessLogger().error(ex.ToString());
+ return 1;
+ }
+ catch(System.Exception ex)
+ {
+ Util.getProcessLogger().error("unknown exception:\n" + ex);
+ return 1;
+ }
+ }
+ return main(args, initData);
+ }
+
+ /// <summary>
+ /// The application must call main after it has
+ /// instantiated the derived class. main creates
+ /// a communicator, establishes the specified signal policy, and,
+ /// once run returns, destroys the communicator.
+ /// The method prints an error message for any exception that propagates
+ /// out of run and ensures that the communicator is
+ /// destroyed correctly even if run completes abnormally.
+ /// </summary>
+ /// <param name="args">The arguments for the application (as passed to Main(string[])
+ /// by the operating system.</param>
+ /// <param name="initializationData">Additional data used to initialize the communicator.</param>
+ /// <returns>The value returned by run. If run terminates with an exception,
+ /// the return value is non-zero.</returns>
+ public int main(string[] args, InitializationData initializationData)
+ {
+ if(Util.getProcessLogger() is ConsoleLoggerI)
+ {
+ Util.setProcessLogger(new ConsoleLoggerI(appName__));
+ }
+
+ if(communicator__ != null)
+ {
+ Util.getProcessLogger().error("only one instance of the Application class can be used");
+ return 1;
+ }
+
+ //
+ // We parse the properties here to extract Ice.ProgramName.
+ //
+ InitializationData initData;
+ if(initializationData != null)
+ {
+ initData = (InitializationData)initializationData.Clone();
+ }
+ else
+ {
+ initData = new InitializationData();
+ }
+
+ try
+ {
+ initData.properties = Util.createProperties(ref args, initData.properties);
+ }
+ catch(Ice.Exception ex)
+ {
+ Util.getProcessLogger().error(ex.ToString());
+ return 1;
+ }
+ catch(System.Exception ex)
+ {
+ Util.getProcessLogger().error("unknown exception:\n" + ex);
+ return 1;
+ }
+ appName__ = initData.properties.getPropertyWithDefault("Ice.ProgramName", appName__);
+
+ nohup__ = initData.properties.getPropertyAsInt("Ice.Nohup") > 0;
+ _application = this;
+
+ int status;
+#if COMPACT || UNITY
+ status = doMain(args, initData);
+#else
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ if(IceInternal.AssemblyUtil.platform_ == IceInternal.AssemblyUtil.Platform.Windows)
+ {
+ _signals = new WindowsSignals();
+ }
+ else
+ {
+ _signals = new MonoSignals();
+ }
+ _signals.register(_handler);
+
+ status = doMain(args, initData);
+
+ _signals.destroy();
+ _signals = null;
+ }
+ else
+ {
+ status = doMain(args, initData);
+ }
+#endif
+
+ return status;
+ }
+
+ /// <summary>
+ /// Returns the application name (which is also the value of Ice.ProgramName.
+ /// This method is useful mainly for error messages that
+ /// include the application name. Because appName is a static method, it is available from anywhere
+ /// in the program.
+ /// </summary>
+ /// <returns>The name of the application.</returns>
+ public static string appName()
+ {
+ return appName__;
+ }
+
+ /// <summary>
+ /// Returns the communicator for the application. Because communicator is a static method,
+ /// it permits access to the communicator from anywhere in the program. Note that, as a consequence,
+ /// you cannot have more than one instance of Application in a program.
+ /// </summary>
+ /// <returns>The communicator for the application.</returns>
+ public static Communicator communicator()
+ {
+ return communicator__;
+ }
+
+ /// <summary>
+ /// Instructs Application to call Communicator.destroy on receipt of a signal.
+ /// This is default signal handling policy established by the default constructor.
+ /// </summary>
+ public static void destroyOnInterrupt()
+ {
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ lock(mutex__)
+ {
+ if(_callback == _holdCallback)
+ {
+ released__ = true;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ _callback = _destroyCallback;
+ }
+ }
+ else
+ {
+ Util.getProcessLogger().warning(
+ "interrupt method called on Application configured to not handle interrupts.");
+ }
+ }
+
+ /// <summary>
+ /// Instructs Application to call Communicator.shutdown on receipt of a signal.
+ /// </summary>
+ public static void shutdownOnInterrupt()
+ {
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ lock(mutex__)
+ {
+ if(_callback == _holdCallback)
+ {
+ released__ = true;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ _callback = _shutdownCallback;
+ }
+ }
+ else
+ {
+ Util.getProcessLogger().warning(
+ "interrupt method called on Application configured to not handle interrupts.");
+ }
+ }
+
+ /// <summary>
+ /// Instructs Application to ignore signals.
+ /// </summary>
+ public static void ignoreInterrupt()
+ {
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ lock(mutex__)
+ {
+ if(_callback == _holdCallback)
+ {
+ released__ = true;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ _callback = null;
+ }
+ }
+ else
+ {
+ Util.getProcessLogger().warning(
+ "interrupt method called on Application configured to not handle interrupts.");
+ }
+ }
+
+ /// <summary>
+ /// Instructs Application to call interruptCallback on receipt of a signal.
+ /// The derived class can intercept signals by overriding interruptCallback.
+ /// </summary>
+ public static void callbackOnInterrupt()
+ {
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ lock(mutex__)
+ {
+ if(_callback == _holdCallback)
+ {
+ released__ = true;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ _callback = _userCallback;
+ }
+ }
+ else
+ {
+ Util.getProcessLogger().warning(
+ "interrupt method called on Application configured to not handle interrupts.");
+ }
+ }
+
+ /// <summary>
+ /// Instructs Application to call to hold signals.
+ /// </summary>
+ public static void holdInterrupt()
+ {
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ lock(mutex__)
+ {
+ if(_callback != _holdCallback)
+ {
+ _previousCallback = _callback;
+ released__ = false;
+ _callback = _holdCallback;
+ }
+ // else, we were already holding signals
+ }
+ }
+ else
+ {
+ Util.getProcessLogger().warning(
+ "interrupt method called on Application configured to not handle interrupts.");
+ }
+ }
+
+ /// <summary>
+ /// Instructs Application respond to signals. If a signal arrived since the last call
+ /// to holdInterrupt, it is delivered once you call releaseInterrupt.
+ /// </summary>
+ public static void releaseInterrupt()
+ {
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ lock(mutex__)
+ {
+ if(_callback == _holdCallback)
+ {
+ //
+ // Note that it's very possible no signal is held;
+ // in this case the callback is just replaced and
+ // setting released__ to true and signalling this
+ // will do no harm.
+ //
+
+ released__ = true;
+ _callback = _previousCallback;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ // Else nothing to release.
+ }
+ }
+ else
+ {
+ Util.getProcessLogger().warning(
+ "interrupt method called on Application configured to not handle interrupts.");
+ }
+ }
+
+ /// <summary>
+ /// Determines whether the application shut down intentionally or was forced to shut down due to a signal.
+ /// This is useful for logging purposes.
+ /// </summary>
+ /// <returns>True if a signal caused the communicator to shut down; false otherwise.</returns>
+ public static bool interrupted()
+ {
+ lock(mutex__)
+ {
+ return interrupted__;
+ }
+ }
+
+ protected virtual int doMain(string[] args, InitializationData initData)
+ {
+ int status = 0;
+
+ try
+ {
+ //
+ // If the process logger is the default logger, we replace it with a
+ // a logger which is using the program name for the prefix.
+ //
+ if(initData.properties.getProperty("Ice.ProgramName").Length > 0 &&
+ Util.getProcessLogger() is ConsoleLoggerI)
+ {
+ Util.setProcessLogger(new ConsoleLoggerI(initData.properties.getProperty("Ice.ProgramName")));
+ }
+
+ communicator__ = Util.initialize(ref args, initData);
+ destroyed__ = false;
+
+ //
+ // The default is to destroy when a signal is received.
+ //
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ destroyOnInterrupt();
+ }
+
+ status = run(args);
+ }
+ catch(Ice.Exception ex)
+ {
+ Util.getProcessLogger().error(ex.ToString());
+ status = 1;
+ }
+ catch(System.Exception ex)
+ {
+ Util.getProcessLogger().error("unknown exception:\n" + ex);
+ status = 1;
+ }
+
+ //
+ // Don't want any new interrupt. And at this point
+ // (post-run), it would not make sense to release a held
+ // signal to run shutdown or destroy.
+ //
+ if(signalPolicy__ == SignalPolicy.HandleSignals)
+ {
+ ignoreInterrupt();
+ }
+
+ lock(mutex__)
+ {
+ while(callbackInProgress__)
+ {
+ System.Threading.Monitor.Wait(mutex__);
+ }
+ if(destroyed__)
+ {
+ communicator__ = null;
+ }
+ else
+ {
+ destroyed__ = true;
+ //
+ // communicator__ != null means that it will be destroyed
+ // next; destroyed__ == true ensures that any
+ // remaining callback won't do anything
+ //
+ }
+ _application = null;
+ }
+
+ if(communicator__ != null)
+ {
+ try
+ {
+ communicator__.destroy();
+ }
+ catch(Ice.Exception ex)
+ {
+ Util.getProcessLogger().error(ex.ToString());
+ status = 1;
+ }
+ catch(System.Exception ex)
+ {
+ Util.getProcessLogger().error("unknown exception:\n" + ex);
+ status = 1;
+ }
+ communicator__ = null;
+ }
+
+ return status;
+ }
+
+ //
+ // First-level handler.
+ //
+ private static void signalHandler(int sig)
+ {
+ Callback callback;
+
+ lock(mutex__)
+ {
+ callback = _callback;
+ }
+
+ if(callback != null)
+ {
+ try
+ {
+ callback(sig);
+ }
+ catch(System.Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ }
+
+ //
+ // The callbacks to be invoked from the handler.
+ //
+ private static void holdInterruptCallback(int sig)
+ {
+ Callback callback = null;
+ lock(mutex__)
+ {
+ while(!released__)
+ {
+ System.Threading.Monitor.Wait(mutex__);
+ }
+
+ if(destroyed__)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+
+ callback = _callback;
+ }
+
+ if(callback != null)
+ {
+ callback(sig);
+ }
+ }
+
+ //
+ // The callbacks to be invoked from the handler.
+ //
+ private static void destroyOnInterruptCallback(int sig)
+ {
+ lock(mutex__)
+ {
+ if(destroyed__)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ if(nohup__ && sig == SIGHUP)
+ {
+ return;
+ }
+
+ Debug.Assert(!callbackInProgress__);
+ callbackInProgress__ = true;
+ interrupted__ = true;
+ destroyed__ = true;
+ }
+
+ try
+ {
+ Debug.Assert(communicator__ != null);
+ communicator__.destroy();
+ }
+ catch(System.Exception ex)
+ {
+ Util.getProcessLogger().error("(while destroying in response to signal " + sig + "):\n" + ex);
+ }
+
+ lock(mutex__)
+ {
+ callbackInProgress__ = false;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ }
+
+ private static void shutdownOnInterruptCallback(int sig)
+ {
+ lock(mutex__)
+ {
+ if(destroyed__)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ if(nohup__ && sig == SIGHUP)
+ {
+ return;
+ }
+
+ Debug.Assert(!callbackInProgress__);
+ callbackInProgress__ = true;
+ interrupted__ = true;
+ }
+
+ try
+ {
+ Debug.Assert(communicator__ != null);
+ communicator__.shutdown();
+ }
+ catch(System.Exception ex)
+ {
+ Util.getProcessLogger().error("(while shutting down in response to signal " + sig + "):\n" + ex);
+ }
+
+ lock(mutex__)
+ {
+ callbackInProgress__ = false;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ }
+
+ private static void userCallbackOnInterruptCallback(int sig)
+ {
+ lock(mutex__)
+ {
+ if(destroyed__)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ // For SIGHUP the user callback is always called. It can
+ // decide what to do.
+ Debug.Assert(!callbackInProgress__);
+ callbackInProgress__ = true;
+ interrupted__ = true;
+ }
+
+ try
+ {
+ Debug.Assert(_application != null);
+ _application.interruptCallback(sig);
+ }
+ catch(System.Exception ex)
+ {
+ Util.getProcessLogger().error("(while interrupting in response to signal " + sig + "):\n" + ex);
+ }
+
+ lock(mutex__)
+ {
+ callbackInProgress__ = false;
+ System.Threading.Monitor.Pulse(mutex__);
+ }
+ }
+
+ protected static object mutex__ = new object();
+ protected static bool callbackInProgress__ = false;
+ protected static bool destroyed__ = false;
+ protected static bool interrupted__ = false;
+ protected static bool released__ = false;
+ protected static bool nohup__ = false;
+ protected static SignalPolicy signalPolicy__ = SignalPolicy.HandleSignals;
+
+ private delegate void Callback(int sig);
+ private static readonly Callback _destroyCallback = new Callback(destroyOnInterruptCallback);
+ private static readonly Callback _shutdownCallback = new Callback(shutdownOnInterruptCallback);
+ private static readonly Callback _holdCallback = new Callback(holdInterruptCallback);
+ private static readonly Callback _userCallback = new Callback(userCallbackOnInterruptCallback);
+
+ private static Callback _callback = null; // Current callback
+ private static Callback _previousCallback; // Remembers prev. callback when signals are held
+
+ //
+ // We use FriendlyName instead of Process.GetCurrentProcess().ProcessName because the latter
+ // is terribly slow. (It takes around 1 second!)
+ //
+ protected static string appName__ = AppDomain.CurrentDomain.FriendlyName;
+ protected static Communicator communicator__;
+ private static Application _application;
+
+ private static int SIGHUP;
+ static Application()
+ {
+ if(IceInternal.AssemblyUtil.platform_ == IceInternal.AssemblyUtil.Platform.Windows)
+ {
+ SIGHUP = 5; // CTRL_LOGOFF_EVENT, from wincon.h
+ }
+ else
+ {
+ SIGHUP = 1;
+ }
+ }
+
+ private delegate void SignalHandler(int sig);
+ private static readonly SignalHandler _handler = new SignalHandler(signalHandler);
+#if !COMPACT && !UNITY
+ private Signals _signals;
+
+ private interface Signals
+ {
+ void register(SignalHandler handler);
+ void destroy();
+ }
+
+ private class MonoSignals : Signals
+ {
+ public void register(SignalHandler handler)
+ {
+ _handler = handler;
+ _destroyed = false;
+
+ try
+ {
+ //
+ // Signal handling in Mono is provided in the Mono.Unix.Native namespace.
+ // We use reflection to do the equivalent of the following:
+ //
+ // Stdlib.signal(Signum.SIGHUP, delegate);
+ // Stdlib.signal(Signum.SIGINT, delegate);
+ // Stdlib.signal(Signum.SIGTERM, delegate);
+ //
+ // We don't use conditional compilation so that the Ice assembly can be
+ // used without change on Windows and Mono.
+ //
+ Assembly a = Assembly.Load(
+ "Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756");
+ Type sigs = a.GetType("Mono.Unix.Native.Signum");
+ object SIGHUP = Enum.Parse(sigs, "SIGHUP");
+ object SIGINT = Enum.Parse(sigs, "SIGINT");
+ object SIGTERM = Enum.Parse(sigs, "SIGTERM");
+ Type stdlib = a.GetType("Mono.Unix.Native.Stdlib");
+ MethodInfo method = stdlib.GetMethod("signal", BindingFlags.Static | BindingFlags.Public);
+ Type delType = a.GetType("Mono.Unix.Native.SignalHandler");
+ Delegate del = Delegate.CreateDelegate(delType, this, "callback");
+ object[] args = new object[2];
+ args[0] = SIGHUP;
+ args[1] = del;
+ method.Invoke(null, args);
+ args[0] = SIGINT;
+ args[1] = del;
+ method.Invoke(null, args);
+ args[0] = SIGTERM;
+ args[1] = del;
+ method.Invoke(null, args);
+
+ //
+ // Doing certain activities within Mono's signal dispatch thread
+ // can cause the VM to crash, so we use a separate thread to invoke
+ // the handler.
+ //
+ _thread = new Thread(new ThreadStart(run));
+ _thread.IsBackground = true;
+ _thread.Name = "Ice.Application.SignalThread";
+ _thread.Start();
+ }
+ catch(System.DllNotFoundException)
+ {
+ //
+ // The class Mono.Unix.Native.Stdlib requires libMonoPosixHelper.so. Mono raises
+ // DllNotFoundException if it cannot be found in the shared library search path.
+ //
+ Util.getProcessLogger().warning("unable to initialize signals");
+ }
+ }
+
+ public void destroy()
+ {
+ lock(_m)
+ {
+ _destroyed = true;
+ System.Threading.Monitor.Pulse(_m);
+ }
+
+ if(_thread != null)
+ {
+ _thread.Join();
+ _thread = null;
+ }
+ }
+
+ private void callback(int sig)
+ {
+ lock(_m)
+ {
+ _signals.Add(sig);
+ System.Threading.Monitor.Pulse(_m);
+ }
+ }
+
+ private void run()
+ {
+ while(true)
+ {
+ List<int> signals = null;
+ bool destroyed = false;
+
+ lock(_m)
+ {
+ if(!_destroyed && _signals.Count == 0)
+ {
+ System.Threading.Monitor.Wait(_m);
+ }
+
+ if(_signals.Count > 0)
+ {
+ signals = _signals;
+ _signals = new List<int>();
+ }
+
+ destroyed = _destroyed;
+ }
+
+ if(signals != null)
+ {
+ foreach(int sig in signals)
+ {
+ _handler(sig);
+ }
+ }
+
+ if(destroyed)
+ {
+ break;
+ }
+ }
+ }
+
+ private static SignalHandler _handler;
+ private static bool _destroyed;
+ private static object _m = new object();
+ private static Thread _thread;
+ private static List<int> _signals = new List<int>();
+ }
+
+ private class WindowsSignals : Signals
+ {
+#if MANAGED
+ public void register(SignalHandler handler)
+ {
+ _handler = handler;
+ Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs args)
+ {
+ args.Cancel = true;
+ _handler(0);
+ };
+ }
+
+ public void destroy()
+ {
+ }
+#else
+ public void register(SignalHandler handler)
+ {
+ _handler = handler;
+ _callback = new CtrlCEventHandler(callback);
+
+ bool rc = NativeMethods.SetConsoleCtrlHandler(_callback, true);
+ Debug.Assert(rc);
+ }
+
+ public void destroy()
+ {
+ }
+
+ private CtrlCEventHandler _callback;
+
+ private bool callback(int sig)
+ {
+ _handler(sig);
+ return true;
+ }
+#endif
+ private SignalHandler _handler;
+ }
+#endif
+ }
+
+ delegate bool CtrlCEventHandler(int sig);
+}
+#endif
diff --git a/csharp/src/Ice/Arrays.cs b/csharp/src/Ice/Arrays.cs
new file mode 100644
index 00000000000..de6485c54d9
--- /dev/null
+++ b/csharp/src/Ice/Arrays.cs
@@ -0,0 +1,122 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+
+namespace IceUtilInternal
+{
+
+ public sealed class Arrays
+ {
+ public static bool Equals(object[] arr1, object[] arr2)
+ {
+ if(object.ReferenceEquals(arr1, arr2))
+ {
+ return true;
+ }
+
+ if((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null))
+ {
+ return false;
+ }
+
+ if(arr1.Length == arr2.Length)
+ {
+ for(int i = 0; i < arr1.Length; i++)
+ {
+ if(arr1[i] == null)
+ {
+ if(arr2[i] != null)
+ {
+ return false;
+ }
+ }
+ else if(!arr1[i].Equals(arr2[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool Equals(Array arr1, Array arr2)
+ {
+ if(object.ReferenceEquals(arr1, arr2))
+ {
+ return true;
+ }
+
+ if((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null))
+ {
+ return false;
+ }
+
+ if(arr1.Length == arr2.Length)
+ {
+ IEnumerator e1 = arr1.GetEnumerator();
+ IEnumerator e2 = arr2.GetEnumerator();
+ while(e1.MoveNext())
+ {
+ e2.MoveNext();
+ if(e1.Current == null)
+ {
+ if(e2.Current != null)
+ {
+ return false;
+ }
+ }
+ else if(!e1.Current.Equals(e2.Current))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static int GetHashCode(object[] arr)
+ {
+ int h = 5381;
+
+ for(int i = 0; i < arr.Length; i++)
+ {
+ object o = arr[i];
+ if(o != null)
+ {
+ IceInternal.HashUtil.hashAdd(ref h, o);
+ }
+ }
+
+ return h;
+ }
+
+ public static int GetHashCode(Array arr)
+ {
+ int h = 0;
+
+ foreach(object o in arr)
+ {
+ if(o != null)
+ {
+ IceInternal.HashUtil.hashAdd(ref h, o);
+ }
+ }
+
+ return h;
+ }
+ }
+}
diff --git a/csharp/src/Ice/AssemblyInfo.cs b/csharp/src/Ice/AssemblyInfo.cs
new file mode 100644
index 00000000000..d3280805a75
--- /dev/null
+++ b/csharp/src/Ice/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("Ice")]
+[assembly: AssemblyDescription("Ice core run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("Ice for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/Ice/AssemblyUtil.cs b/csharp/src/Ice/AssemblyUtil.cs
new file mode 100644
index 00000000000..0d97f9a9970
--- /dev/null
+++ b/csharp/src/Ice/AssemblyUtil.cs
@@ -0,0 +1,288 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Reflection;
+ using System.Threading;
+
+ public sealed class AssemblyUtil
+ {
+ public enum Runtime { DotNET, Mono };
+ public enum Platform { Windows, NonWindows };
+
+ static AssemblyUtil()
+ {
+ PlatformID id = Environment.OSVersion.Platform;
+ if( id == PlatformID.Win32NT
+ || id == PlatformID.Win32S
+ || id == PlatformID.Win32Windows
+ || id == PlatformID.WinCE)
+ {
+ platform_ = Platform.Windows;
+ }
+ else
+ {
+ platform_ = Platform.NonWindows;
+ }
+
+ if(System.Type.GetType("Mono.Runtime") != null)
+ {
+ runtime_ = Runtime.Mono;
+ }
+ else
+ {
+ runtime_ = Runtime.DotNET;
+ }
+
+ System.Version v = System.Environment.Version;
+ runtimeMajor_ = v.Major;
+ runtimeMinor_ = v.Minor;
+ runtimeBuild_ = v.Build;
+ runtimeRevision_ = v.Revision;
+
+ v = System.Environment.OSVersion.Version;
+ xp_ = v.Major == 5 && v.Minor == 1; // Are we running on XP?
+
+ osx_ = false;
+#if COMPACT || SILVERLIGHT
+ //
+ // Populate the _iceAssemblies list with the fully-qualified names
+ // of the standard Ice assemblies. The fully-qualified name looks
+ // like this:
+ //
+ // Ice, Version=X.Y.Z.0, Culture=neutral, PublicKeyToken=...
+ //
+ string name = Assembly.GetExecutingAssembly().FullName;
+ _iceAssemblies.Add(name);
+ int pos = name.IndexOf(',');
+ if(pos >= 0 && pos < name.Length - 1)
+ {
+ //
+ // Strip off the leading assembly name and use the remainder of the
+ // string to compose the names of the other standard assemblies.
+ //
+ string suffix = name.Substring(pos + 1);
+ _iceAssemblies.Add("Glacier2," + suffix);
+ _iceAssemblies.Add("IceBox," + suffix);
+ _iceAssemblies.Add("IceGrid," + suffix);
+ _iceAssemblies.Add("IcePatch2," + suffix);
+ _iceAssemblies.Add("IceStorm," + suffix);
+ }
+#elif !UNITY
+ if (platform_ == Platform.NonWindows)
+ {
+ try
+ {
+ Assembly a = Assembly.Load(
+ "Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756");
+ Type syscall = a.GetType("Mono.Unix.Native.Syscall");
+ if(syscall != null)
+ {
+ MethodInfo method = syscall.GetMethod("uname", BindingFlags.Static | BindingFlags.Public);
+ if(method != null)
+ {
+ object[] p = new object[1];
+ method.Invoke(null, p);
+ if(p[0] != null)
+ {
+ Type utsname = a.GetType("Mono.Unix.Native.Utsname");
+ osx_ = ((string)utsname.GetField("sysname").GetValue(p[0])).Equals("Darwin");
+ }
+ }
+ }
+ }
+ catch(System.Exception)
+ {
+ }
+ }
+#endif
+ }
+
+ public static Type findType(Instance instance, string csharpId)
+ {
+ lock(_mutex)
+ {
+ Type t;
+ if (_typeTable.TryGetValue(csharpId, out t))
+ {
+ return t;
+ }
+#if COMPACT || SILVERLIGHT
+ string[] assemblies = instance.factoryAssemblies();
+ for(int i = 0; i < assemblies.Length; ++i)
+ {
+ string s = csharpId + "," + assemblies[i];
+ if((t = Type.GetType(s)) != null)
+ {
+ _typeTable[csharpId] = t;
+ return t;
+ }
+ }
+ //
+ // As a last resort, look for the type in the standard Ice assemblies.
+ // This avoids the need for a program to set a property such as:
+ //
+ // Ice.FactoryAssemblies=Ice
+ //
+ foreach(string a in _iceAssemblies)
+ {
+ string s = csharpId + "," + a;
+ if((t = Type.GetType(s)) != null)
+ {
+ _typeTable[csharpId] = t;
+ return t;
+ }
+ }
+#else
+ loadAssemblies(); // Lazy initialization
+ foreach (Assembly a in _loadedAssemblies.Values)
+ {
+ if((t = a.GetType(csharpId)) != null)
+ {
+ _typeTable[csharpId] = t;
+ return t;
+ }
+ }
+#endif
+ }
+ return null;
+ }
+
+#if !COMPACT && !SILVERLIGHT
+ public static Type[] findTypesWithPrefix(string prefix)
+ {
+ LinkedList<Type> l = new LinkedList<Type>();
+
+ lock(_mutex)
+ {
+ loadAssemblies(); // Lazy initialization
+ foreach(Assembly a in _loadedAssemblies.Values)
+ {
+ Type[] types = a.GetTypes();
+ foreach(Type t in types)
+ {
+ if(t.AssemblyQualifiedName.IndexOf(prefix, StringComparison.Ordinal) == 0)
+ {
+ l.AddLast(t);
+ }
+ }
+ }
+ }
+
+ Type[] result = new Type[l.Count];
+ if(l.Count > 0)
+ {
+ l.CopyTo(result, 0);
+ }
+ return result;
+ }
+#endif
+
+ public static object createInstance(Type t)
+ {
+ try
+ {
+ return Activator.CreateInstance(t);
+ }
+ catch(MemberAccessException)
+ {
+ return null;
+ }
+ }
+
+#if !COMPACT && !SILVERLIGHT
+ //
+ // Make sure that all assemblies that are referenced by this process
+ // are actually loaded. This is necessary so we can use reflection
+ // on any type in any assembly because the type we are after will
+ // most likely not be in the current assembly and, worse, may be
+ // in an assembly that has not been loaded yet. (Type.GetType()
+ // is no good because it looks only in the calling object's assembly
+ // and mscorlib.dll.)
+ //
+ private static void loadAssemblies()
+ {
+ Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ List<Assembly> newAssemblies = null;
+ foreach(Assembly a in assemblies)
+ {
+ if(!_loadedAssemblies.Contains(a.FullName))
+ {
+ if(newAssemblies == null)
+ {
+ newAssemblies = new List<Assembly>();
+ }
+ newAssemblies.Add(a);
+ _loadedAssemblies[a.FullName] = a;
+ }
+ }
+ if(newAssemblies != null)
+ {
+ foreach(Assembly a in newAssemblies)
+ {
+ loadReferencedAssemblies(a);
+ }
+ }
+ }
+
+ private static void loadReferencedAssemblies(Assembly a)
+ {
+ AssemblyName[] names = a.GetReferencedAssemblies();
+ foreach(AssemblyName name in names)
+ {
+ if(!_loadedAssemblies.ContainsKey(name.FullName))
+ {
+ try
+ {
+ Assembly ra = Assembly.Load(name);
+ //
+ // The value of name.FullName may not match that of ra.FullName, so
+ // we record the assembly using both keys.
+ //
+ _loadedAssemblies[name.FullName] = ra;
+ _loadedAssemblies[ra.FullName] = ra;
+ loadReferencedAssemblies(ra);
+ }
+ catch(System.Exception)
+ {
+ // Ignore assemblies that cannot be loaded.
+ }
+ }
+ }
+ }
+
+ private static Hashtable _loadedAssemblies = new Hashtable(); // <string, Assembly> pairs.
+#else
+ private static List<string> _iceAssemblies = new List<string>();
+#endif
+ private static Dictionary<string, Type> _typeTable = new Dictionary<string, Type>(); // <type name, Type> pairs.
+ private static object _mutex = new object();
+
+ public readonly static Runtime runtime_; // Either DotNET or Mono
+ //
+ // Versioning is: Major.Minor.Build.Revision. (Yes, really. It is not Major.Minor.Revision.Build, as
+ // one might expect.) If a part of a version number (such as revision) is not defined, it is -1.
+ //
+ public readonly static int runtimeMajor_;
+ public readonly static int runtimeMinor_;
+ public readonly static int runtimeBuild_;
+ public readonly static int runtimeRevision_;
+
+ public readonly static Platform platform_;
+ public readonly static bool xp_;
+ public readonly static bool osx_;
+ }
+
+}
diff --git a/csharp/src/Ice/AsyncIOThread.cs b/csharp/src/Ice/AsyncIOThread.cs
new file mode 100644
index 00000000000..4b4ae5428f2
--- /dev/null
+++ b/csharp/src/Ice/AsyncIOThread.cs
@@ -0,0 +1,208 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Threading;
+
+ public class AsyncIOThread
+ {
+ internal AsyncIOThread(Instance instance)
+ {
+ _instance = instance;
+
+ _thread = new HelperThread(this);
+ updateObserver();
+#if !SILVERLIGHT
+ if(instance.initializationData().properties.getProperty("Ice.ThreadPriority").Length > 0)
+ {
+ ThreadPriority priority = IceInternal.Util.stringToThreadPriority(
+ instance.initializationData().properties.getProperty("Ice.ThreadPriority"));
+ _thread.Start(priority);
+ }
+ else
+ {
+ _thread.Start(ThreadPriority.Normal);
+ }
+#else
+ _thread.Start();
+#endif
+ }
+
+ public void
+ updateObserver()
+ {
+ lock(this)
+ {
+ Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer;
+ if(obsv != null)
+ {
+ _observer = obsv.getThreadObserver("Communicator",
+ _thread.getName(),
+ Ice.Instrumentation.ThreadState.ThreadStateIdle,
+ _observer);
+ if(_observer != null)
+ {
+ _observer.attach();
+ }
+ }
+ }
+ }
+
+ public void queue(ThreadPoolWorkItem callback)
+ {
+ lock(this)
+ {
+ Debug.Assert(!_destroyed);
+ _queue.AddLast(callback);
+ System.Threading.Monitor.Pulse(this);
+ }
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ Debug.Assert(!_destroyed);
+ _destroyed = true;
+ System.Threading.Monitor.Pulse(this);
+ }
+ }
+
+ public void joinWithThread()
+ {
+ if(_thread != null)
+ {
+ _thread.Join();
+ }
+ }
+
+ public void run()
+ {
+ LinkedList<ThreadPoolWorkItem> queue = new LinkedList<ThreadPoolWorkItem>();
+ bool inUse = false;
+ while(true)
+ {
+ lock(this)
+ {
+ if(_observer != null && inUse)
+ {
+ _observer.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForIO,
+ Ice.Instrumentation.ThreadState.ThreadStateIdle);
+ inUse = false;
+ }
+
+ if(_destroyed && _queue.Count == 0)
+ {
+ break;
+ }
+
+ while(!_destroyed && _queue.Count == 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ LinkedList<ThreadPoolWorkItem> tmp = queue;
+ queue = _queue;
+ _queue = tmp;
+
+ if(_observer != null)
+ {
+ _observer.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle,
+ Ice.Instrumentation.ThreadState.ThreadStateInUseForIO);
+ inUse = true;
+ }
+ }
+
+ foreach(ThreadPoolWorkItem cb in queue)
+ {
+ try
+ {
+ cb();
+ }
+ catch(Ice.LocalException ex)
+ {
+ string s = "exception in asynchronous IO thread:\n" + ex;
+ _instance.initializationData().logger.error(s);
+ }
+ catch(System.Exception ex)
+ {
+ string s = "unknown exception in asynchronous IO thread:\n" + ex;
+ _instance.initializationData().logger.error(s);
+ }
+ }
+ queue.Clear();
+ }
+
+ if(_observer != null)
+ {
+ _observer.detach();
+ }
+ }
+
+ private Instance _instance;
+ private bool _destroyed;
+ private LinkedList<ThreadPoolWorkItem> _queue = new LinkedList<ThreadPoolWorkItem>();
+ private Ice.Instrumentation.ThreadObserver _observer;
+
+ private sealed class HelperThread
+ {
+ internal HelperThread(AsyncIOThread asyncIOThread)
+ {
+ _asyncIOThread = asyncIOThread;
+ _name = _asyncIOThread._instance.initializationData().properties.getProperty("Ice.ProgramName");
+ if(_name.Length > 0)
+ {
+ _name += "-";
+ }
+ _name += "Ice.AsyncIOThread";
+ }
+
+ public void Join()
+ {
+ _thread.Join();
+ }
+
+ public string getName()
+ {
+ return _name;
+ }
+
+#if !SILVERLIGHT
+ public void Start(ThreadPriority priority)
+#else
+ public void Start()
+#endif
+ {
+ _thread = new Thread(new ThreadStart(Run));
+ _thread.IsBackground = true;
+ _thread.Name = _name;
+#if !SILVERLIGHT
+ _thread.Priority = priority;
+#endif
+ _thread.Start();
+ }
+
+ public void Run()
+ {
+ _asyncIOThread.run();
+ }
+
+ private AsyncIOThread _asyncIOThread;
+ private string _name;
+ private Thread _thread;
+ }
+
+ private HelperThread _thread;
+ }
+}
diff --git a/csharp/src/Ice/AsyncResult.cs b/csharp/src/Ice/AsyncResult.cs
new file mode 100644
index 00000000000..3e48d72a418
--- /dev/null
+++ b/csharp/src/Ice/AsyncResult.cs
@@ -0,0 +1,698 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ ///
+ /// <summary>
+ /// Callback that requires the application to down-cast the proxy.
+ /// </summary>
+ ///
+ public delegate void AsyncCallback(AsyncResult r);
+
+ ///
+ /// <summary>
+ /// Callback for the successful completion of an operation
+ /// that returns no data.
+ /// </summary>
+ ///
+ public delegate void OnewayCallback();
+
+ ///
+ /// <summary>
+ /// Callback for the successful completion of an operation
+ /// that returns no data.
+ /// </summary>
+ ///
+ public delegate void SentCallback(bool sentSynchronously);
+
+ ///
+ /// <summary>
+ /// Called when an invocation raises an exception.
+ /// </summary>
+ ///
+ public delegate void ExceptionCallback(Ice.Exception ex);
+
+ ///
+ /// <summary>
+ /// <!-- TODO -->
+ /// </summary>
+ public interface AsyncResult : System.IAsyncResult
+ {
+ void cancel();
+
+ Ice.Communicator getCommunicator();
+
+ Ice.Connection getConnection();
+
+ ObjectPrx getProxy();
+
+ bool isCompleted_();
+ void waitForCompleted();
+
+ bool isSent();
+ void waitForSent();
+
+ void throwLocalException();
+
+ bool sentSynchronously();
+
+ string getOperation();
+
+ AsyncResult whenSent(Ice.AsyncCallback cb);
+ AsyncResult whenSent(Ice.SentCallback cb);
+
+ AsyncResult whenCompleted(Ice.ExceptionCallback excb);
+ }
+
+ public interface AsyncResult<T> : AsyncResult
+ {
+ AsyncResult<T> whenCompleted(T cb, Ice.ExceptionCallback excb);
+
+ new AsyncResult<T> whenCompleted(Ice.ExceptionCallback excb);
+ new AsyncResult<T> whenSent(Ice.SentCallback cb);
+ }
+}
+
+namespace IceInternal
+{
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Threading;
+
+ public delegate void ProxyTwowayCallback<T>(Ice.AsyncResult result, T cb, Ice.ExceptionCallback excb);
+ public delegate void ProxyOnewayCallback<T>(T cb);
+
+ public class AsyncResultI : Ice.AsyncResult
+ {
+ public virtual void cancel()
+ {
+ cancel(new Ice.InvocationCanceledException());
+ }
+
+ public Ice.Communicator getCommunicator()
+ {
+ return _communicator;
+ }
+
+ public virtual Ice.Connection getConnection()
+ {
+ return null;
+ }
+
+ public virtual Ice.ObjectPrx getProxy()
+ {
+ return null;
+ }
+
+ public bool isCompleted_()
+ {
+ lock(this)
+ {
+ return (state_ & StateDone) != 0;
+ }
+ }
+
+ public void waitForCompleted()
+ {
+ lock(this)
+ {
+ while((state_ & StateDone) == 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ }
+ }
+
+ public bool isSent()
+ {
+ lock(this)
+ {
+ return (state_ & StateSent) != 0;
+ }
+ }
+
+ public void waitForSent()
+ {
+ lock(this)
+ {
+ while((state_ & StateSent) == 0 && _exception == null)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ }
+ }
+
+ public void throwLocalException()
+ {
+ lock(this)
+ {
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ }
+ }
+
+ public bool sentSynchronously()
+ {
+ return sentSynchronously_; // No lock needed
+ }
+
+ //
+ // Implementation of System.IAsyncResult properties
+ //
+
+ public bool IsCompleted
+ {
+ get
+ {
+ return isCompleted_();
+ }
+ }
+
+ public bool CompletedSynchronously
+ {
+ get
+ {
+ if(getProxy() != null && getProxy().ice_isTwoway())
+ {
+ return false;
+ }
+ return sentSynchronously_;
+ }
+ }
+
+ public object AsyncState
+ {
+ get
+ {
+ return _cookie; // No lock needed, cookie is immutable.
+ }
+ }
+
+ public WaitHandle AsyncWaitHandle
+ {
+ get
+ {
+ lock(this)
+ {
+ if(_waitHandle == null)
+ {
+#if SILVERLIGHT
+ _waitHandle = new ManualResetEvent(false);
+#else
+ _waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
+#endif
+ }
+ if((state_ & StateDone) != 0)
+ {
+ _waitHandle.Set();
+ }
+ return _waitHandle;
+ }
+ }
+ }
+
+ public Ice.AsyncResult whenSent(Ice.AsyncCallback cb)
+ {
+ lock(this)
+ {
+ if(cb == null)
+ {
+ throw new System.ArgumentException("callback is null");
+ }
+ if(_sentCallback != null)
+ {
+ throw new System.ArgumentException("sent callback already set");
+ }
+ _sentCallback = cb;
+ if((state_ & StateSent) == 0)
+ {
+ return this;
+ }
+ }
+
+ if(sentSynchronously_)
+ {
+ try
+ {
+ _sentCallback(this);
+ }
+ catch(System.Exception ex)
+ {
+ warning(ex);
+ }
+ }
+ else
+ {
+ instance_.clientThreadPool().dispatch(() =>
+ {
+ try
+ {
+ _sentCallback(this);
+ }
+ catch(System.Exception ex)
+ {
+ warning(ex);
+ }
+ }, cachedConnection_);
+ }
+ return this;
+ }
+
+ public Ice.AsyncResult whenSent(Ice.SentCallback cb)
+ {
+ lock(this)
+ {
+ if(cb == null)
+ {
+ throw new System.ArgumentException("callback is null");
+ }
+ if(_sentCallback != null)
+ {
+ throw new System.ArgumentException("sent callback already set");
+ }
+ _sentCallback = (Ice.AsyncResult result) =>
+ {
+ cb(result.sentSynchronously());
+ };
+ if((state_ & StateSent) == 0)
+ {
+ return this;
+ }
+ }
+
+ if(sentSynchronously_)
+ {
+ try
+ {
+ cb(true);
+ }
+ catch(System.Exception ex)
+ {
+ warning(ex);
+ }
+ }
+ else
+ {
+ instance_.clientThreadPool().dispatch(() =>
+ {
+ try
+ {
+ cb(false);
+ }
+ catch(System.Exception ex)
+ {
+ warning(ex);
+ }
+ }, cachedConnection_);
+ }
+ return this;
+ }
+
+ public Ice.AsyncResult whenCompletedWithAsyncCallback(Ice.AsyncCallback cb)
+ {
+ setCompletedCallback(cb);
+ return this;
+ }
+
+ public Ice.AsyncResult whenCompleted(Ice.ExceptionCallback cb)
+ {
+ if(cb == null)
+ {
+ throw new System.ArgumentException("callback is null");
+ }
+ lock(this)
+ {
+ if(exceptionCallback_ != null)
+ {
+ throw new System.ArgumentException("callback already set");
+ }
+ exceptionCallback_ = cb;
+ }
+ setCompletedCallback(getCompletedCallback());
+ return this;
+ }
+
+ public string getOperation()
+ {
+ return _operation;
+ }
+
+ public void invokeSent(Ice.AsyncCallback cb)
+ {
+ Debug.Assert(cb != null);
+ try
+ {
+ cb(this);
+ }
+ catch(System.Exception ex)
+ {
+ warning(ex);
+ }
+
+ if(observer_ != null)
+ {
+ Ice.ObjectPrx proxy = getProxy();
+ if(proxy == null || !proxy.ice_isTwoway())
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ }
+ }
+
+ public void invokeSentAsync(Ice.AsyncCallback cb)
+ {
+ //
+ // This is called when it's not safe to call the exception callback synchronously
+ // from this thread. Instead the exception callback is called asynchronously from
+ // the client thread pool.
+ //
+ Debug.Assert(cb != null);
+ try
+ {
+ instance_.clientThreadPool().dispatch(() =>
+ {
+ invokeSent(cb);
+ }, cachedConnection_);
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ }
+ }
+
+ public void invokeCompleted(Ice.AsyncCallback cb)
+ {
+ Debug.Assert(cb != null);
+ try
+ {
+ cb(this);
+ }
+ catch(System.Exception ex)
+ {
+ warning(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ }
+
+ public void invokeCompletedAsync(Ice.AsyncCallback cb)
+ {
+ //
+ // This is called when it's not safe to call the exception callback synchronously
+ // from this thread. Instead the exception callback is called asynchronously from
+ // the client thread pool.
+ //
+ Debug.Assert(cb != null);
+
+ // CommunicatorDestroyedException is the only exception that can propagate directly.
+ instance_.clientThreadPool().dispatch(() =>
+ {
+ invokeCompleted(cb);
+ }, cachedConnection_);
+ }
+
+ public virtual void cancelable(CancellationHandler handler)
+ {
+ lock(this)
+ {
+ if(_cancellationException != null)
+ {
+ try
+ {
+ throw _cancellationException;
+ }
+ finally
+ {
+ _cancellationException = null;
+ }
+ }
+ _cancellationHandler = handler;
+ }
+ }
+
+ public bool wait()
+ {
+ lock(this)
+ {
+ if((state_ & StateEndCalled) != 0)
+ {
+ throw new System.ArgumentException("end_ method called more than once");
+ }
+ state_ |= StateEndCalled;
+ while((state_ & StateDone) == 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ return (state_ & StateOK) != 0;
+ }
+ }
+
+ public virtual void cacheMessageBuffers()
+ {
+ }
+
+ protected AsyncResultI(Ice.Communicator communicator, Instance instance, string op, object cookie)
+ {
+ instance_ = instance;
+ sentSynchronously_ = false;
+ state_ = 0;
+
+ _communicator = communicator;
+ _operation = op;
+ _exception = null;
+ _cookie = cookie;
+ }
+
+ protected Ice.AsyncCallback sent(bool done)
+ {
+ lock(this)
+ {
+ Debug.Assert(_exception == null);
+
+ bool alreadySent = (state_ & StateSent) != 0;
+ state_ |= StateSent;
+ if(done)
+ {
+ state_ |= StateDone | StateOK;
+ _cancellationHandler = null;
+ if(observer_ != null && _sentCallback == null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+
+ //
+ // For oneway requests after the data has been sent
+ // the buffers can be reused unless this is a
+ // collocated invocation. For collocated invocations
+ // the buffer won't be reused because it has already
+ // been marked as cached in invokeCollocated.
+ //
+ cacheMessageBuffers();
+ }
+ if(_waitHandle != null)
+ {
+ _waitHandle.Set();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ return !alreadySent ? _sentCallback : null;
+ }
+ }
+
+ protected Ice.AsyncCallback finished(bool ok)
+ {
+ lock(this)
+ {
+ state_ |= StateDone;
+ if(ok)
+ {
+ state_ |= StateOK;
+ }
+ _cancellationHandler = null;
+ if(_completedCallback == null)
+ {
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ }
+ if(_waitHandle != null)
+ {
+ _waitHandle.Set();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ return _completedCallback;
+ }
+ }
+
+ protected Ice.AsyncCallback finished(Ice.Exception ex)
+ {
+ lock(this)
+ {
+ state_ |= StateDone;
+ _exception = ex;
+ _cancellationHandler = null;
+ if(observer_ != null)
+ {
+ observer_.failed(ex.ice_name());
+ }
+ if(_completedCallback == null)
+ {
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ }
+ if(_waitHandle != null)
+ {
+ _waitHandle.Set();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ return _completedCallback;
+ }
+ }
+
+ protected void setCompletedCallback(Ice.AsyncCallback cb)
+ {
+ lock(this)
+ {
+ if(cb == null)
+ {
+ throw new System.ArgumentException("callback is null");
+ }
+ if(_completedCallback != null)
+ {
+ throw new System.ArgumentException("callback already set");
+ }
+ _completedCallback = cb;
+ if((state_ & StateDone) == 0)
+ {
+ return;
+ }
+ else if((getProxy() == null || !getProxy().ice_isTwoway()) && _exception == null)
+ {
+ return;
+ }
+ }
+
+ instance_.clientThreadPool().dispatch(() =>
+ {
+ try
+ {
+ cb(this);
+ }
+ catch(System.Exception ex)
+ {
+ warning(ex);
+ }
+ }, cachedConnection_);
+ }
+
+ protected virtual Ice.AsyncCallback getCompletedCallback()
+ {
+ return (Ice.AsyncResult result) =>
+ {
+ Debug.Assert(exceptionCallback_ != null);
+ try
+ {
+ ((AsyncResultI)result).wait();
+ }
+ catch(Ice.Exception ex)
+ {
+ exceptionCallback_(ex);
+ return;
+ }
+ };
+ }
+
+ protected void cancel(Ice.LocalException ex)
+ {
+ CancellationHandler handler;
+ lock(this)
+ {
+ _cancellationException = ex;
+ if(_cancellationHandler == null)
+ {
+ return;
+ }
+ handler = _cancellationHandler;
+ }
+ handler.asyncRequestCanceled((OutgoingAsyncBase)this, ex);
+ }
+
+ protected virtual Ice.Instrumentation.InvocationObserver getObserver()
+ {
+ return observer_;
+ }
+
+ protected static T check<T>(Ice.AsyncResult r, string operation)
+ {
+ if(r == null)
+ {
+ throw new System.ArgumentException("AsyncResult == null");
+ }
+ if(r.getOperation() != operation)
+ {
+ throw new System.ArgumentException("Incorrect operation for end_" + operation + " method: " +
+ r.getOperation());
+ }
+ if(!(r is T))
+ {
+ throw new System.ArgumentException("Incorrect AsyncResult object for end_" + operation + " method");
+ }
+ return (T)r;
+ }
+
+ protected void warning(System.Exception ex)
+ {
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0)
+ {
+ instance_.initializationData().logger.warning("exception raised by AMI callback:\n" + ex);
+ }
+ }
+
+ protected IceInternal.Instance instance_;
+ protected Ice.Instrumentation.InvocationObserver observer_;
+ protected Ice.Connection cachedConnection_;
+ protected bool sentSynchronously_;
+
+ private readonly Ice.Communicator _communicator;
+ private readonly string _operation;
+ private readonly object _cookie;
+ private Ice.Exception _exception;
+ private EventWaitHandle _waitHandle;
+
+ private CancellationHandler _cancellationHandler;
+ private Ice.LocalException _cancellationException;
+
+ private Ice.AsyncCallback _completedCallback;
+ private Ice.AsyncCallback _sentCallback;
+ protected Ice.ExceptionCallback exceptionCallback_;
+
+ protected const int StateOK = 0x1;
+ protected const int StateDone = 0x2;
+ protected const int StateSent = 0x4;
+ protected const int StateEndCalled = 0x8;
+ protected const int StateCachedBuffers = 0x10;
+ protected int state_;
+ }
+}
diff --git a/csharp/src/Ice/Base64.cs b/csharp/src/Ice/Base64.cs
new file mode 100644
index 00000000000..c60b800425a
--- /dev/null
+++ b/csharp/src/Ice/Base64.cs
@@ -0,0 +1,276 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceUtilInternal
+{
+
+public class Base64
+{
+
+public static string
+encode(byte[] plainSeq)
+{
+ if(plainSeq == null || plainSeq.Length == 0)
+ {
+ return "";
+ }
+
+ System.Text.StringBuilder retval = new System.Text.StringBuilder();
+ int base64Bytes = (((plainSeq.Length * 4) / 3) + 1);
+ int newlineBytes = (((base64Bytes * 2) / 76) + 1);
+ int totalBytes = base64Bytes + newlineBytes;
+
+ retval.Capacity = totalBytes;
+
+ byte by1;
+ byte by2;
+ byte by3;
+ byte by4;
+ byte by5;
+ byte by6;
+ byte by7;
+
+ for(int i = 0; i < plainSeq.Length; i += 3)
+ {
+ by1 = plainSeq[i];
+ by2 = 0;
+ by3 = 0;
+
+ if((i + 1) < plainSeq.Length)
+ {
+ by2 = plainSeq[i+1];
+ }
+
+ if((i + 2) < plainSeq.Length)
+ {
+ by3 = plainSeq[i+2];
+ }
+
+ by4 = (byte)(by1 >> 2);
+ by5 = (byte)(((by1 & 0x3) << 4) | (by2 >> 4));
+ by6 = (byte)(((by2 & 0xf) << 2) | (by3 >> 6));
+ by7 = (byte)(by3 & 0x3f);
+
+ retval.Append(encode(by4));
+ retval.Append(encode(by5));
+
+ if((i + 1) < plainSeq.Length)
+ {
+ retval.Append(encode(by6));
+ }
+ else
+ {
+ retval.Append('=');
+ }
+
+ if((i + 2) < plainSeq.Length)
+ {
+ retval.Append(encode(by7));
+ }
+ else
+ {
+ retval.Append('=');
+ }
+ }
+
+ System.Text.StringBuilder outString = new System.Text.StringBuilder();
+ outString.Capacity = totalBytes;
+ int iter = 0;
+
+ while((retval.Length - iter) > 76)
+ {
+ outString.Append(retval.ToString().Substring(iter, 76));
+ outString.Append("\r\n");
+ iter += 76;
+ }
+
+ outString.Append(retval.ToString().Substring(iter));
+
+ return outString.ToString();
+}
+
+public static byte[]
+decode(string str)
+{
+ System.Text.StringBuilder newStr = new System.Text.StringBuilder();
+
+ newStr.Capacity = str.Length;
+
+ for(int j = 0; j < str.Length; j++)
+ {
+ char c = str[j];
+ if(isBase64(c))
+ {
+ newStr.Append(c);
+ }
+ }
+
+ if(newStr.Length == 0)
+ {
+ return null;
+ }
+
+ // Note: This is how we were previously computing the size of the return
+ // sequence. The method below is more efficient (and correct).
+ // size_t lines = str.size() / 78;
+ // size_t totalBytes = (lines * 76) + (((str.size() - (lines * 78)) * 3) / 4);
+
+ // Figure out how long the final sequence is going to be.
+ int totalBytes = (newStr.Length * 3 / 4) + 1;
+
+ IceInternal.ByteBuffer retval = IceInternal.ByteBuffer.allocate(totalBytes);
+
+ byte by1;
+ byte by2;
+ byte by3;
+ byte by4;
+
+ char c1, c2, c3, c4;
+
+ int pos = 0;
+ for(int i = 0; i < newStr.Length; i += 4)
+ {
+ c1 = 'A';
+ c2 = 'A';
+ c3 = 'A';
+ c4 = 'A';
+
+ c1 = newStr[i];
+
+ if((i + 1) < newStr.Length)
+ {
+ c2 = newStr[i + 1];
+ }
+
+ if((i + 2) < newStr.Length)
+ {
+ c3 = newStr[i + 2];
+ }
+
+ if((i + 3) < newStr.Length)
+ {
+ c4 = newStr[i + 3];
+ }
+
+ by1 = decode(c1);
+ by2 = decode(c2);
+ by3 = decode(c3);
+ by4 = decode(c4);
+
+ retval.put((byte)((by1 << 2) | (by2 >> 4)));
+ ++pos;
+
+ if(c3 != '=')
+ {
+ retval.put((byte)(((by2 & 0xf) << 4) | (by3 >> 2)));
+ ++pos;
+ }
+
+ if(c4 != '=')
+ {
+ retval.put((byte)(((by3 & 0x3) << 6) | by4));
+ ++pos;
+ }
+ }
+
+ return retval.toArray(0, pos);
+}
+
+public static bool
+isBase64(char c)
+{
+ if(c >= 'A' && c <= 'Z')
+ {
+ return true;
+ }
+
+ if(c >= 'a' && c <= 'z')
+ {
+ return true;
+ }
+
+ if(c >= '0' && c <= '9')
+ {
+ return true;
+ }
+
+ if(c == '+')
+ {
+ return true;
+ }
+
+ if(c == '/')
+ {
+ return true;
+ }
+
+ if(c == '=')
+ {
+ return true;
+ }
+
+ return false;
+}
+
+private static char
+encode(byte uc)
+{
+ if(uc < 26)
+ {
+ return (char)('A' + uc);
+ }
+
+ if(uc < 52)
+ {
+ return (char)('a' + (uc - 26));
+ }
+
+ if(uc < 62)
+ {
+ return (char)('0' + (uc - 52));
+ }
+
+ if(uc == 62)
+ {
+ return '+';
+ }
+
+ return '/';
+}
+
+private static byte
+decode(char c)
+{
+ if(c >= 'A' && c <= 'Z')
+ {
+ return (byte)(c - 'A');
+ }
+
+ if(c >= 'a' && c <= 'z')
+ {
+ return (byte)(c - 'a' + 26);
+ }
+
+ if(c >= '0' && c <= '9')
+ {
+ return (byte)(c - '0' + 52);
+ }
+
+ if(c == '+')
+ {
+ return 62;
+ }
+
+ return 63;
+}
+
+}
+
+}
+
diff --git a/csharp/src/Ice/BasicStream.cs b/csharp/src/Ice/BasicStream.cs
new file mode 100644
index 00000000000..3160a355bab
--- /dev/null
+++ b/csharp/src/Ice/BasicStream.cs
@@ -0,0 +1,5409 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Reflection;
+#if !COMPACT && !SILVERLIGHT
+ using System.Runtime.InteropServices;
+ using System.Runtime.Serialization;
+ using System.Runtime.Serialization.Formatters.Binary;
+#endif
+ using System.Threading;
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ internal static class NativeMethods
+ {
+ [DllImport("bzip2.dll")]
+ internal static extern IntPtr BZ2_bzlibVersion();
+
+ [DllImport("bzip2.dll")]
+ internal static extern int BZ2_bzBuffToBuffCompress(byte[] dest,
+ ref int destLen,
+ byte[] source,
+ int sourceLen,
+ int blockSize100k,
+ int verbosity,
+ int workFactor);
+
+ [DllImport("bzip2.dll")]
+ internal static extern int BZ2_bzBuffToBuffDecompress(byte[] dest,
+ ref int destLen,
+ byte[] source,
+ int sourceLen,
+ int small,
+ int verbosity);
+ }
+#endif
+
+ public class BasicStream
+ {
+
+ static BasicStream()
+ {
+#if MANAGED || COMPACT || SILVERLIGHT
+ //
+ // Protocol compression is not supported when using managed code.
+ //
+ _bzlibInstalled = false;
+#else
+ //
+ // Simple trick to find out whether bzip2 is
+ // installed: Call the BZ2_bzlibVersion() function in the
+ // library. If we get an exception, the library is
+ // not available.
+ //
+ _bzlibInstalled = false;
+
+ //
+ // We are setting the library name here because, under Mono, we don't know the exact library name.
+ // In addition, the FileName member of the BadImageFormatException is the empty string, even though
+ // it should provide the name of the library.
+ //
+ string lib = AssemblyUtil.runtime_ == AssemblyUtil.Runtime.Mono ? "bzip2 library" : "bzip2.dll";
+ try
+ {
+ NativeMethods.BZ2_bzlibVersion();
+ _bzlibInstalled = true;
+ }
+ catch(DllNotFoundException)
+ {
+ // Expected -- bzip2.dll not installed or not in PATH.
+ }
+ catch(EntryPointNotFoundException)
+ {
+ Console.Error.WriteLine("warning: found " + lib + " but entry point BZ2_bzlibVersion is missing.");
+ }
+ catch(BadImageFormatException ex)
+ {
+ if(ex.FileName != null && ex.FileName.Length != 0)
+ {
+ lib = ex.FileName; // Future-proof: we'll do the right thing if the FileName member is non-empty.
+ }
+ Console.Error.Write("warning: " + lib + " could not be loaded (likely due to 32/64-bit mismatch).");
+ if(IntPtr.Size == 8)
+ {
+ Console.Error.Write(" Make sure the directory containing the 64-bit " + lib + " is in your PATH.");
+ }
+ Console.Error.WriteLine();
+ }
+#endif
+ }
+
+ public BasicStream(Instance instance, Ice.EncodingVersion encoding)
+ {
+ initialize(instance, encoding);
+ _buf = new Buffer();
+ }
+
+ public BasicStream(Instance instance, Ice.EncodingVersion encoding, byte[] data)
+ {
+ initialize(instance, encoding);
+ _buf = new Buffer(data);
+ }
+
+ private void initialize(Instance instance, Ice.EncodingVersion encoding)
+ {
+ instance_ = instance;
+ _closure = null;
+ _encoding = encoding;
+
+ _readEncapsStack = null;
+ _writeEncapsStack = null;
+ _readEncapsCache = null;
+ _writeEncapsCache = null;
+
+ _sliceObjects = true;
+
+ _startSeq = -1;
+ }
+
+ //
+ // This function allows this object to be reused, rather than
+ // reallocated.
+ //
+ public void reset()
+ {
+ _buf.reset();
+ clear();
+ }
+
+ public void clear()
+ {
+ if(_readEncapsStack != null)
+ {
+ Debug.Assert(_readEncapsStack.next == null);
+ _readEncapsStack.next = _readEncapsCache;
+ _readEncapsCache = _readEncapsStack;
+ _readEncapsStack = null;
+ _readEncapsCache.reset();
+ }
+
+ if(_writeEncapsStack != null)
+ {
+ Debug.Assert(_writeEncapsStack.next == null);
+ _writeEncapsStack.next = _writeEncapsCache;
+ _writeEncapsCache = _writeEncapsStack;
+ _writeEncapsStack = null;
+ _writeEncapsCache.reset();
+ }
+
+ _startSeq = -1;
+
+ _sliceObjects = true;
+ }
+
+ public Instance instance()
+ {
+ return instance_;
+ }
+
+ public object closure()
+ {
+ return _closure;
+ }
+
+ public object closure(object p)
+ {
+ object prev = _closure;
+ _closure = p;
+ return prev;
+ }
+
+ public void swap(BasicStream other)
+ {
+ Debug.Assert(instance_ == other.instance_);
+
+ Buffer tmpBuf = other._buf;
+ other._buf = _buf;
+ _buf = tmpBuf;
+
+ object tmpClosure = other._closure;
+ other._closure = _closure;
+ _closure = tmpClosure;
+
+ //
+ // Swap is never called for BasicStreams that have encapsulations being read/write. However,
+ // encapsulations might still be set in case marshalling or un-marshalling failed. We just
+ // reset the encapsulations if there are still some set.
+ //
+ resetEncaps();
+ other.resetEncaps();
+
+ int tmpStartSeq = other._startSeq;
+ other._startSeq = _startSeq;
+ _startSeq = tmpStartSeq;
+
+ int tmpMinSeqSize = other._minSeqSize;
+ other._minSeqSize = _minSeqSize;
+ _minSeqSize = tmpMinSeqSize;
+ }
+
+ public void resetEncaps()
+ {
+ _readEncapsStack = null;
+ _writeEncapsStack = null;
+ }
+
+ public void resize(int sz, bool reading)
+ {
+ _buf.resize(sz, reading);
+ _buf.b.position(sz);
+ }
+
+ public Buffer prepareWrite()
+ {
+ _buf.b.limit(_buf.size());
+ _buf.b.position(0);
+ return _buf;
+ }
+
+ public Buffer getBuffer()
+ {
+ return _buf;
+ }
+
+ public void startWriteObject(Ice.SlicedData data)
+ {
+ Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
+ _writeEncapsStack.encoder.startInstance(SliceType.ObjectSlice, data);
+ }
+
+ public void endWriteObject()
+ {
+ Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
+ _writeEncapsStack.encoder.endInstance();
+ }
+
+ public void startReadObject()
+ {
+ Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
+ _readEncapsStack.decoder.startInstance(SliceType.ObjectSlice);
+ }
+
+ public Ice.SlicedData endReadObject(bool preserve)
+ {
+ Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
+ return _readEncapsStack.decoder.endInstance(preserve);
+ }
+
+ public void startWriteException(Ice.SlicedData data)
+ {
+ Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
+ _writeEncapsStack.encoder.startInstance(SliceType.ExceptionSlice, data);
+ }
+
+ public void endWriteException()
+ {
+ Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
+ _writeEncapsStack.encoder.endInstance();
+ }
+
+ public void startReadException()
+ {
+ Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
+ _readEncapsStack.decoder.startInstance(SliceType.ExceptionSlice);
+ }
+
+ public Ice.SlicedData endReadException(bool preserve)
+ {
+ Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
+ return _readEncapsStack.decoder.endInstance(preserve);
+ }
+
+ public void startWriteEncaps()
+ {
+ //
+ // If no encoding version is specified, use the current write
+ // encapsulation encoding version if there's a current write
+ // encapsulation, otherwise, use the stream encoding version.
+ //
+
+ if(_writeEncapsStack != null)
+ {
+ startWriteEncaps(_writeEncapsStack.encoding, _writeEncapsStack.format);
+ }
+ else
+ {
+ startWriteEncaps(_encoding, Ice.FormatType.DefaultFormat);
+ }
+ }
+
+ public void startWriteEncaps(Ice.EncodingVersion encoding, Ice.FormatType format)
+ {
+ Protocol.checkSupportedEncoding(encoding);
+
+ WriteEncaps curr = _writeEncapsCache;
+ if(curr != null)
+ {
+ curr.reset();
+ _writeEncapsCache = _writeEncapsCache.next;
+ }
+ else
+ {
+ curr = new WriteEncaps();
+ }
+ curr.next = _writeEncapsStack;
+ _writeEncapsStack = curr;
+
+ _writeEncapsStack.format = format;
+ _writeEncapsStack.setEncoding(encoding);
+ _writeEncapsStack.start = _buf.b.position();
+
+ writeInt(0); // Placeholder for the encapsulation length.
+ _writeEncapsStack.encoding.write__(this);
+ }
+
+ public void endWriteEncaps()
+ {
+ Debug.Assert(_writeEncapsStack != null);
+
+ // Size includes size and version.
+ int start = _writeEncapsStack.start;
+ int sz = _buf.size() - start;
+ _buf.b.putInt(start, sz);
+
+ WriteEncaps curr = _writeEncapsStack;
+ _writeEncapsStack = curr.next;
+ curr.next = _writeEncapsCache;
+ _writeEncapsCache = curr;
+ _writeEncapsCache.reset();
+ }
+
+ public void endWriteEncapsChecked()
+ {
+ if(_writeEncapsStack == null)
+ {
+ throw new Ice.EncapsulationException("not in an encapsulation");
+ }
+ endWriteEncaps();
+ }
+
+ public void writeEmptyEncaps(Ice.EncodingVersion encoding)
+ {
+ Protocol.checkSupportedEncoding(encoding);
+ writeInt(6); // Size
+ encoding.write__(this);
+ }
+
+ public void writeEncaps(byte[] v)
+ {
+ if(v.Length < 6)
+ {
+ throw new Ice.EncapsulationException();
+ }
+ expand(v.Length);
+ _buf.b.put(v);
+ }
+
+ public Ice.EncodingVersion getWriteEncoding()
+ {
+ return _writeEncapsStack != null ? _writeEncapsStack.encoding : _encoding;
+ }
+
+ public Ice.EncodingVersion startReadEncaps()
+ {
+ ReadEncaps curr = _readEncapsCache;
+ if(curr != null)
+ {
+ curr.reset();
+ _readEncapsCache = _readEncapsCache.next;
+ }
+ else
+ {
+ curr = new ReadEncaps();
+ }
+ curr.next = _readEncapsStack;
+ _readEncapsStack = curr;
+
+ _readEncapsStack.start = _buf.b.position();
+
+ //
+ // I don't use readSize() and writeSize() for encapsulations,
+ // because when creating an encapsulation, I must know in advance
+ // how many bytes the size information will require in the data
+ // stream. If I use an Int, it is always 4 bytes. For
+ // readSize()/writeSize(), it could be 1 or 5 bytes.
+ //
+ int sz = readInt();
+ if(sz < 6)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ if(sz - 4 > _buf.b.remaining())
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ _readEncapsStack.sz = sz;
+
+ Ice.EncodingVersion encoding = new Ice.EncodingVersion();
+ encoding.read__(this);
+ Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported.
+ _readEncapsStack.setEncoding(encoding);
+
+ return encoding;
+ }
+
+ public void endReadEncaps()
+ {
+ Debug.Assert(_readEncapsStack != null);
+
+ if(!_readEncapsStack.encoding_1_0)
+ {
+ skipOpts();
+ if(_buf.b.position() != _readEncapsStack.start + _readEncapsStack.sz)
+ {
+ throw new Ice.EncapsulationException();
+ }
+ }
+ else if(_buf.b.position() != _readEncapsStack.start + _readEncapsStack.sz)
+ {
+ if(_buf.b.position() + 1 != _readEncapsStack.start + _readEncapsStack.sz)
+ {
+ throw new Ice.EncapsulationException();
+ }
+
+ //
+ // Ice version < 3.3 had a bug where user exceptions with
+ // class members could be encoded with a trailing byte
+ // when dispatched with AMD. So we tolerate an extra byte
+ // in the encapsulation.
+ //
+ try
+ {
+ _buf.b.get();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ ReadEncaps curr = _readEncapsStack;
+ _readEncapsStack = curr.next;
+ curr.next = _readEncapsCache;
+ _readEncapsCache = curr;
+ _readEncapsCache.reset();
+ }
+
+ public Ice.EncodingVersion skipEmptyEncaps()
+ {
+ int sz = readInt();
+ if(sz != 6)
+ {
+ throw new Ice.EncapsulationException();
+ }
+
+ Ice.EncodingVersion encoding = new Ice.EncodingVersion();
+ encoding.read__(this);
+ return encoding;
+ }
+
+ public void endReadEncapsChecked() // Used by public stream API.
+ {
+ if(_readEncapsStack == null)
+ {
+ throw new Ice.EncapsulationException("not in an encapsulation");
+ }
+ endReadEncaps();
+ }
+
+ public byte[] readEncaps(out Ice.EncodingVersion encoding)
+ {
+ int sz = readInt();
+ if(sz < 6)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ if(sz - 4 > _buf.b.remaining())
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ encoding = new Ice.EncodingVersion();
+ encoding.read__(this);
+ _buf.b.position(_buf.b.position() - 6);
+
+ byte[] v = new byte[sz];
+ try
+ {
+ _buf.b.get(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.EncodingVersion getReadEncoding()
+ {
+ return _readEncapsStack != null ? _readEncapsStack.encoding : _encoding;
+ }
+
+ public int getReadEncapsSize()
+ {
+ Debug.Assert(_readEncapsStack != null);
+ return _readEncapsStack.sz - 6;
+ }
+
+ public Ice.EncodingVersion skipEncaps()
+ {
+ int sz = readInt();
+ if(sz < 6)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ Ice.EncodingVersion encoding = new Ice.EncodingVersion();
+ encoding.read__(this);
+ try
+ {
+ _buf.b.position(_buf.b.position() + sz - 6);
+ }
+ catch(ArgumentOutOfRangeException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ return encoding;
+ }
+
+ public void startWriteSlice(string typeId, int compactId, bool last)
+ {
+ Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
+ _writeEncapsStack.encoder.startSlice(typeId, compactId, last);
+ }
+
+ public void endWriteSlice()
+ {
+ Debug.Assert(_writeEncapsStack != null && _writeEncapsStack.encoder != null);
+ _writeEncapsStack.encoder.endSlice();
+ }
+
+ public string startReadSlice() // Returns type ID of next slice
+ {
+ Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
+ return _readEncapsStack.decoder.startSlice();
+ }
+
+ public void endReadSlice()
+ {
+ Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
+ _readEncapsStack.decoder.endSlice();
+ }
+
+ public void skipSlice()
+ {
+ Debug.Assert(_readEncapsStack != null && _readEncapsStack.decoder != null);
+ _readEncapsStack.decoder.skipSlice();
+ }
+
+ public void readPendingObjects()
+ {
+ if(_readEncapsStack != null && _readEncapsStack.decoder != null)
+ {
+ _readEncapsStack.decoder.readPendingObjects();
+ }
+ else if(_readEncapsStack != null ? _readEncapsStack.encoding_1_0 : _encoding.Equals(Ice.Util.Encoding_1_0))
+ {
+ //
+ // If using the 1.0 encoding and no objects were read, we
+ // still read an empty sequence of pending objects if
+ // requested (i.e.: if this is called).
+ //
+ // This is required by the 1.0 encoding, even if no objects
+ // are written we do marshal an empty sequence if marshaled
+ // data types use classes.
+ //
+ skipSize();
+ }
+ }
+
+ public void writePendingObjects()
+ {
+ if(_writeEncapsStack != null && _writeEncapsStack.encoder != null)
+ {
+ _writeEncapsStack.encoder.writePendingObjects();
+ }
+ else if(_writeEncapsStack != null ?
+ _writeEncapsStack.encoding_1_0 : _encoding.Equals(Ice.Util.Encoding_1_0))
+ {
+ //
+ // If using the 1.0 encoding and no objects were written, we
+ // still write an empty sequence for pending objects if
+ // requested (i.e.: if this is called).
+ //
+ // This is required by the 1.0 encoding, even if no objects
+ // are written we do marshal an empty sequence if marshaled
+ // data types use classes.
+ //
+ writeSize(0);
+ }
+ }
+
+ public void writeSize(int v)
+ {
+ if(v > 254)
+ {
+ expand(5);
+ _buf.b.put((byte)255);
+ _buf.b.putInt(v);
+ }
+ else
+ {
+ expand(1);
+ _buf.b.put((byte)v);
+ }
+ }
+
+ public int readSize()
+ {
+ try
+ {
+ //
+ // COMPILERFIX: for some reasons _buf.get() doesn't work here on OS X with Mono;
+ //
+ //byte b = _buf.b.get();
+ byte b = readByte();
+ if(b == 255)
+ {
+ int v = _buf.b.getInt();
+ if(v < 0)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ return v;
+ }
+ else
+ {
+ return b; // byte is unsigned
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public int readAndCheckSeqSize(int minSize)
+ {
+ int sz = readSize();
+
+ if(sz == 0)
+ {
+ return 0;
+ }
+
+ //
+ // The _startSeq variable points to the start of the sequence for which
+ // we expect to read at least _minSeqSize bytes from the stream.
+ //
+ // If not initialized or if we already read more data than _minSeqSize,
+ // we reset _startSeq and _minSeqSize for this sequence (possibly a
+ // top-level sequence or enclosed sequence it doesn't really matter).
+ //
+ // Otherwise, we are reading an enclosed sequence and we have to bump
+ // _minSeqSize by the minimum size that this sequence will require on
+ // the stream.
+ //
+ // The goal of this check is to ensure that when we start un-marshalling
+ // a new sequence, we check the minimal size of this new sequence against
+ // the estimated remaining buffer size. This estimatation is based on
+ // the minimum size of the enclosing sequences, it's _minSeqSize.
+ //
+ if(_startSeq == -1 || _buf.b.position() > (_startSeq + _minSeqSize))
+ {
+ _startSeq = _buf.b.position();
+ _minSeqSize = sz * minSize;
+ }
+ else
+ {
+ _minSeqSize += sz * minSize;
+ }
+
+ //
+ // If there isn't enough data to read on the stream for the sequence (and
+ // possibly enclosed sequences), something is wrong with the marshalled
+ // data: it's claiming having more data that what is possible to read.
+ //
+ if(_startSeq + _minSeqSize > _buf.size())
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ return sz;
+ }
+
+ public int startSize()
+ {
+ int pos = _buf.b.position();
+ writeInt(0); // Placeholder for 32-bit size
+ return pos;
+ }
+
+ public void endSize(int pos)
+ {
+ Debug.Assert(pos >= 0);
+ rewriteInt(_buf.b.position() - pos - 4, pos);
+ }
+
+ public void writeBlob(byte[] v)
+ {
+ if(v == null)
+ {
+ return;
+ }
+ expand(v.Length);
+ _buf.b.put(v);
+ }
+
+ public void readBlob(byte[] v)
+ {
+ try
+ {
+ _buf.b.get(v);
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public byte[] readBlob(int sz)
+ {
+ if(_buf.b.remaining() < sz)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ byte[] v = new byte[sz];
+ try
+ {
+ _buf.b.get(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ // Read/write type and tag for optionals
+ public bool writeOpt(int tag, Ice.OptionalFormat format)
+ {
+ Debug.Assert(_writeEncapsStack != null);
+ if(_writeEncapsStack.encoder != null)
+ {
+ return _writeEncapsStack.encoder.writeOpt(tag, format);
+ }
+ else
+ {
+ return writeOptImpl(tag, format);
+ }
+ }
+
+ public bool readOpt(int tag, Ice.OptionalFormat expectedFormat)
+ {
+ Debug.Assert(_readEncapsStack != null);
+ if(_readEncapsStack.decoder != null)
+ {
+ return _readEncapsStack.decoder.readOpt(tag, expectedFormat);
+ }
+ else
+ {
+ return readOptImpl(tag, expectedFormat);
+ }
+ }
+
+ public void writeByte(byte v)
+ {
+ expand(1);
+ _buf.b.put(v);
+ }
+
+ public void writeByte(int tag, Ice.Optional<byte> v)
+ {
+ if(v.HasValue)
+ {
+ writeByte(tag, v.Value);
+ }
+ }
+
+ public void writeByte(int tag, byte v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.F1))
+ {
+ writeByte(v);
+ }
+ }
+
+ public void rewriteByte(byte v, int dest)
+ {
+ _buf.b.put(dest, v);
+ }
+
+ public void writeByteSeq(byte[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ expand(v.Length);
+ _buf.b.put(v);
+ }
+ }
+
+ public void writeByteSeq(int count, IEnumerable<byte> v)
+ {
+ if(count == 0)
+ {
+ writeSize(0);
+ return;
+ }
+
+ {
+ List<byte> value = v as List<byte>;
+ if(value != null)
+ {
+ writeByteSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ LinkedList<byte> value = v as LinkedList<byte>;
+ if(value != null)
+ {
+ writeSize(count);
+ expand(count);
+ IEnumerator<byte> i = v.GetEnumerator();
+ while(i.MoveNext())
+ {
+ _buf.b.put(i.Current);
+ }
+ return;
+ }
+ }
+
+ {
+ Queue<byte> value = v as Queue<byte>;
+ if(value != null)
+ {
+ writeByteSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ Stack<byte> value = v as Stack<byte>;
+ if(value != null)
+ {
+ writeByteSeq(value.ToArray());
+ return;
+ }
+ }
+
+ writeSize(count);
+ expand(count);
+ foreach(byte b in v)
+ {
+ _buf.b.put(b);
+ }
+ }
+
+ public void writeByteSeq(int tag, Ice.Optional<byte[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeByteSeq(tag, v.Value);
+ }
+ }
+
+ public void writeByteSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<byte>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeByteSeq(count, v.Value);
+ }
+ }
+
+ public void writeByteSeq(int tag, byte[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeByteSeq(v);
+ }
+ }
+
+ public void writeByteSeq(int tag, int count, IEnumerable<byte> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeByteSeq(count, v);
+ }
+ }
+
+ public void writeSerializable(object o)
+ {
+#if !COMPACT && !SILVERLIGHT
+ if(o == null)
+ {
+ writeSize(0);
+ return;
+ }
+ try
+ {
+ StreamWrapper w = new StreamWrapper(this);
+ IFormatter f = new BinaryFormatter();
+ f.Serialize(w, o);
+ w.Close();
+ }
+ catch(System.Exception ex)
+ {
+ throw new Ice.MarshalException("cannot serialize object:", ex);
+ }
+#else
+ throw new Ice.MarshalException("serialization not supported");
+#endif
+ }
+
+ public byte readByte()
+ {
+ try
+ {
+ return _buf.b.get();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.Optional<byte> readByte(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.F1))
+ {
+ return new Ice.Optional<byte>(readByte());
+ }
+ else
+ {
+ return new Ice.Optional<byte>();
+ }
+ }
+
+ public void readByte(int tag, out bool isset, out byte v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.F1))
+ {
+ v = readByte();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ public byte[] readByteSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(1);
+ byte[] v = new byte[sz];
+ _buf.b.get(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readByteSeq(out List<byte> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new List<byte>(readByteSeq());
+ }
+
+ public void readByteSeq(out LinkedList<byte> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new LinkedList<byte>(readByteSeq());
+ }
+
+ public void readByteSeq(out Queue<byte> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue is faster than constructing the queue
+ // and adding to it one element at a time.
+ //
+ l = new Queue<byte>(readByteSeq());
+ }
+
+ public void readByteSeq(out Stack<byte> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ byte[] array = readByteSeq();
+ Array.Reverse(array);
+ l = new Stack<byte>(array);
+ }
+
+ public Ice.Optional<byte[]> readByteSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ return new Ice.Optional<byte[]>(readByteSeq());
+ }
+ else
+ {
+ return new Ice.Optional<byte[]>();
+ }
+ }
+
+ public void readByteSeq(int tag, out bool isset, out byte[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ v = readByteSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public object readSerializable()
+ {
+#if !COMPACT && !SILVERLIGHT
+ int sz = readAndCheckSeqSize(1);
+ if(sz == 0)
+ {
+ return null;
+ }
+ try
+ {
+ StreamWrapper w = new StreamWrapper(sz, this);
+ IFormatter f = new BinaryFormatter();
+ return f.Deserialize(w);
+ }
+ catch(System.Exception ex)
+ {
+ throw new Ice.MarshalException("cannot deserialize object:", ex);
+ }
+#else
+ throw new Ice.MarshalException("serialization not supported");
+#endif
+ }
+
+ public void writeBool(bool v)
+ {
+ expand(1);
+ _buf.b.put(v ? (byte)1 : (byte)0);
+ }
+
+ public void writeBool(int tag, Ice.Optional<bool> v)
+ {
+ if(v.HasValue)
+ {
+ writeBool(tag, v.Value);
+ }
+ }
+
+ public void writeBool(int tag, bool v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.F1))
+ {
+ writeBool(v);
+ }
+ }
+
+ public void rewriteBool(bool v, int dest)
+ {
+ _buf.b.put(dest, v ? (byte)1 : (byte)0);
+ }
+
+ public void writeBoolSeq(bool[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ expand(v.Length);
+ _buf.b.putBoolSeq(v);
+ }
+ }
+
+ public void writeBoolSeq(int count, IEnumerable<bool> v)
+ {
+ if(count == 0)
+ {
+ writeSize(0);
+ return;
+ }
+
+ {
+ List<bool> value = v as List<bool>;
+ if(value != null)
+ {
+ writeBoolSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ LinkedList<bool> value = v as LinkedList<bool>;
+ if(value != null)
+ {
+ writeSize(count);
+ expand(count);
+ IEnumerator<bool> i = v.GetEnumerator();
+ while(i.MoveNext())
+ {
+ _buf.b.putBool(i.Current);
+ }
+ return;
+ }
+ }
+
+ {
+ Queue<bool> value = v as Queue<bool>;
+ if(value != null)
+ {
+ writeBoolSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ Stack<bool> value = v as Stack<bool>;
+ if(value != null)
+ {
+ writeBoolSeq(value.ToArray());
+ return;
+ }
+ }
+
+ writeSize(count);
+ expand(count);
+ foreach(bool b in v)
+ {
+ _buf.b.putBool(b);
+ }
+ }
+
+ public void writeBoolSeq(int tag, Ice.Optional<bool[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeBoolSeq(tag, v.Value);
+ }
+ }
+
+ public void writeBoolSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<bool>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeBoolSeq(count, v.Value);
+ }
+ }
+
+ public void writeBoolSeq(int tag, bool[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeBoolSeq(v);
+ }
+ }
+
+ public void writeBoolSeq(int tag, int count, IEnumerable<bool> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeBoolSeq(count, v);
+ }
+ }
+
+ public bool readBool()
+ {
+ try
+ {
+ return _buf.b.get() == 1;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.Optional<bool> readBool(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.F1))
+ {
+ return new Ice.Optional<bool>(readBool());
+ }
+ else
+ {
+ return new Ice.Optional<bool>();
+ }
+ }
+
+ public void readBool(int tag, out bool isset, out bool v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.F1))
+ {
+ v = readBool();
+ }
+ else
+ {
+ v = false;
+ }
+ }
+
+ public bool[] readBoolSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(1);
+ bool[] v = new bool[sz];
+ _buf.b.getBoolSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readBoolSeq(out List<bool> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new List<bool>(readBoolSeq());
+ }
+
+ public void readBoolSeq(out LinkedList<bool> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new LinkedList<bool>(readBoolSeq());
+ }
+
+ public void readBoolSeq(out Queue<bool> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue is faster than constructing the queue
+ // and adding to it one element at a time.
+ //
+ l = new Queue<bool>(readBoolSeq());
+ }
+
+ public void readBoolSeq(out Stack<bool> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ bool[] array = readBoolSeq();
+ Array.Reverse(array);
+ l = new Stack<bool>(array);
+ }
+
+ public Ice.Optional<bool[]> readBoolSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ return new Ice.Optional<bool[]>(readBoolSeq());
+ }
+ else
+ {
+ return new Ice.Optional<bool[]>();
+ }
+ }
+
+ public void readBoolSeq(int tag, out bool isset, out bool[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ v = readBoolSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public void writeShort(short v)
+ {
+ expand(2);
+ _buf.b.putShort(v);
+ }
+
+ public void writeShort(int tag, Ice.Optional<short> v)
+ {
+ if(v.HasValue)
+ {
+ writeShort(tag, v.Value);
+ }
+ }
+
+ public void writeShort(int tag, short v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.F2))
+ {
+ writeShort(v);
+ }
+ }
+
+ public void writeShortSeq(short[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ expand(v.Length * 2);
+ _buf.b.putShortSeq(v);
+ }
+ }
+
+ public void writeShortSeq(int count, IEnumerable<short> v)
+ {
+ if(count == 0)
+ {
+ writeSize(0);
+ return;
+ }
+
+ {
+ List<short> value = v as List<short>;
+ if(value != null)
+ {
+ writeShortSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ LinkedList<short> value = v as LinkedList<short>;
+ if(value != null)
+ {
+ writeSize(count);
+ expand(count * 2);
+ IEnumerator<short> i = v.GetEnumerator();
+ while(i.MoveNext())
+ {
+ _buf.b.putShort(i.Current);
+ }
+ return;
+ }
+ }
+
+ {
+ Queue<short> value = v as Queue<short>;
+ if(value != null)
+ {
+ writeShortSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ Stack<short> value = v as Stack<short>;
+ if(value != null)
+ {
+ writeShortSeq(value.ToArray());
+ return;
+ }
+ }
+
+ writeSize(count);
+ expand(count * 2);
+ foreach(short s in v)
+ {
+ _buf.b.putShort(s);
+ }
+ }
+
+ public void writeShortSeq(int tag, Ice.Optional<short[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeShortSeq(tag, v.Value);
+ }
+ }
+
+ public void writeShortSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<short>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
+ writeShortSeq(count, v.Value);
+ }
+ }
+
+ public void writeShortSeq(int tag, short[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || v.Length == 0 ? 1 : v.Length * 2 + (v.Length > 254 ? 5 : 1));
+ writeShortSeq(v);
+ }
+ }
+
+ public void writeShortSeq(int tag, int count, IEnumerable<short> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
+ writeShortSeq(count, v);
+ }
+ }
+
+ public short readShort()
+ {
+ try
+ {
+ return _buf.b.getShort();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.Optional<short> readShort(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.F2))
+ {
+ return new Ice.Optional<short>(readShort());
+ }
+ else
+ {
+ return new Ice.Optional<short>();
+ }
+ }
+
+ public void readShort(int tag, out bool isset, out short v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.F2))
+ {
+ v = readShort();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ public short[] readShortSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(2);
+ short[] v = new short[sz];
+ _buf.b.getShortSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readShortSeq(out List<short> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new List<short>(readShortSeq());
+ }
+
+ public void readShortSeq(out LinkedList<short> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new LinkedList<short>(readShortSeq());
+ }
+
+ public void readShortSeq(out Queue<short> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue is faster than constructing the queue
+ // and adding to it one element at a time.
+ //
+ l = new Queue<short>(readShortSeq());
+ }
+
+ public void readShortSeq(out Stack<short> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ short[] array = readShortSeq();
+ Array.Reverse(array);
+ l = new Stack<short>(array);
+ }
+
+ public Ice.Optional<short[]> readShortSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<short[]>(readShortSeq());
+ }
+ else
+ {
+ return new Ice.Optional<short[]>();
+ }
+ }
+
+ public void readShortSeq(int tag, out bool isset, out short[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readShortSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public void writeInt(int v)
+ {
+ expand(4);
+ _buf.b.putInt(v);
+ }
+
+ public void writeInt(int tag, Ice.Optional<int> v)
+ {
+ if(v.HasValue)
+ {
+ writeInt(tag, v.Value);
+ }
+ }
+
+ public void writeInt(int tag, int v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.F4))
+ {
+ writeInt(v);
+ }
+ }
+
+ public void rewriteInt(int v, int dest)
+ {
+ _buf.b.putInt(dest, v);
+ }
+
+ public void writeIntSeq(int[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ expand(v.Length * 4);
+ _buf.b.putIntSeq(v);
+ }
+ }
+
+ public void writeIntSeq(int count, IEnumerable<int> v)
+ {
+ if(count == 0)
+ {
+ writeSize(0);
+ return;
+ }
+
+ {
+ List<int> value = v as List<int>;
+ if(value != null)
+ {
+ writeIntSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ LinkedList<int> value = v as LinkedList<int>;
+ if(value != null)
+ {
+ writeSize(count);
+ expand(count * 4);
+ IEnumerator<int> i = v.GetEnumerator();
+ while(i.MoveNext())
+ {
+ _buf.b.putInt(i.Current);
+ }
+ return;
+ }
+ }
+
+ {
+ Queue<int> value = v as Queue<int>;
+ if(value != null)
+ {
+ writeIntSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ Stack<int> value = v as Stack<int>;
+ if(value != null)
+ {
+ writeIntSeq(value.ToArray());
+ return;
+ }
+ }
+
+ writeSize(count);
+ expand(count * 4);
+ foreach(int i in v)
+ {
+ _buf.b.putInt(i);
+ }
+ }
+
+ public void writeIntSeq(int tag, Ice.Optional<int[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeIntSeq(tag, v.Value);
+ }
+ }
+
+ public void writeIntSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<int>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
+ writeIntSeq(count, v.Value);
+ }
+ }
+
+ public void writeIntSeq(int tag, int[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || v.Length == 0 ? 1 : v.Length * 4 + (v.Length > 254 ? 5 : 1));
+ writeIntSeq(v);
+ }
+ }
+
+ public void writeIntSeq(int tag, int count, IEnumerable<int> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
+ writeIntSeq(count, v);
+ }
+ }
+
+ public int readInt()
+ {
+ try
+ {
+ return _buf.b.getInt();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.Optional<int> readInt(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.F4))
+ {
+ return new Ice.Optional<int>(readInt());
+ }
+ else
+ {
+ return new Ice.Optional<int>();
+ }
+ }
+
+ public void readInt(int tag, out bool isset, out int v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.F4))
+ {
+ v = readInt();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ public int[] readIntSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ int[] v = new int[sz];
+ _buf.b.getIntSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readIntSeq(out List<int> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new List<int>(readIntSeq());
+ }
+
+ public void readIntSeq(out LinkedList<int> l)
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new LinkedList<int>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(_buf.b.getInt());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readIntSeq(out Queue<int> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue takes the same time as constructing the queue
+ // and adding to it one element at a time, so
+ // we avoid the copy.
+ //
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new Queue<int>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(_buf.b.getInt());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readIntSeq(out Stack<int> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ int[] array = readIntSeq();
+ Array.Reverse(array);
+ l = new Stack<int>(array);
+ }
+
+ public Ice.Optional<int[]> readIntSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<int[]>(readIntSeq());
+ }
+ else
+ {
+ return new Ice.Optional<int[]>();
+ }
+ }
+
+ public void readIntSeq(int tag, out bool isset, out int[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readIntSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public void writeLong(long v)
+ {
+ expand(8);
+ _buf.b.putLong(v);
+ }
+
+ public void writeLong(int tag, Ice.Optional<long> v)
+ {
+ if(v.HasValue)
+ {
+ writeLong(tag, v.Value);
+ }
+ }
+
+ public void writeLong(int tag, long v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.F8))
+ {
+ writeLong(v);
+ }
+ }
+
+ public void writeLongSeq(long[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ expand(v.Length * 8);
+ _buf.b.putLongSeq(v);
+ }
+ }
+
+ public void writeLongSeq(int count, IEnumerable<long> v)
+ {
+ if(count == 0)
+ {
+ writeSize(0);
+ return;
+ }
+
+ {
+ List<long> value = v as List<long>;
+ if(value != null)
+ {
+ writeLongSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ LinkedList<long> value = v as LinkedList<long>;
+ if(value != null)
+ {
+ writeSize(count);
+ expand(count * 8);
+ IEnumerator<long> i = v.GetEnumerator();
+ while(i.MoveNext())
+ {
+ _buf.b.putLong(i.Current);
+ }
+ return;
+ }
+ }
+
+ {
+ Queue<long> value = v as Queue<long>;
+ if(value != null)
+ {
+ writeLongSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ Stack<long> value = v as Stack<long>;
+ if(value != null)
+ {
+ writeLongSeq(value.ToArray());
+ return;
+ }
+ }
+
+ writeSize(count);
+ expand(count * 8);
+ foreach(long l in v)
+ {
+ _buf.b.putLong(l);
+ }
+ }
+
+ public void writeLongSeq(int tag, Ice.Optional<long[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeLongSeq(tag, v.Value);
+ }
+ }
+
+ public void writeLongSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<long>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
+ writeLongSeq(count, v.Value);
+ }
+ }
+
+ public void writeLongSeq(int tag, long[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || v.Length == 0 ? 1 : v.Length * 8 + (v.Length > 254 ? 5 : 1));
+ writeLongSeq(v);
+ }
+ }
+
+ public void writeLongSeq(int tag, int count, IEnumerable<long> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
+ writeLongSeq(count, v);
+ }
+ }
+
+ public long readLong()
+ {
+ try
+ {
+ return _buf.b.getLong();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.Optional<long> readLong(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.F8))
+ {
+ return new Ice.Optional<long>(readLong());
+ }
+ else
+ {
+ return new Ice.Optional<long>();
+ }
+ }
+
+ public void readLong(int tag, out bool isset, out long v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.F8))
+ {
+ v = readLong();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ public long[] readLongSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(8);
+ long[] v = new long[sz];
+ _buf.b.getLongSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readLongSeq(out List<long> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new List<long>(readLongSeq());
+ }
+
+ public void readLongSeq(out LinkedList<long> l)
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new LinkedList<long>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(_buf.b.getLong());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readLongSeq(out Queue<long> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue takes the same time as constructing the queue
+ // and adding to it one element at a time, so
+ // we avoid the copy.
+ //
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new Queue<long>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(_buf.b.getLong());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readLongSeq(out Stack<long> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ long[] array = readLongSeq();
+ Array.Reverse(array);
+ l = new Stack<long>(array);
+ }
+
+ public Ice.Optional<long[]> readLongSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<long[]>(readLongSeq());
+ }
+ else
+ {
+ return new Ice.Optional<long[]>();
+ }
+ }
+
+ public void readLongSeq(int tag, out bool isset, out long[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readLongSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public void writeFloat(float v)
+ {
+ expand(4);
+ _buf.b.putFloat(v);
+ }
+
+ public void writeFloat(int tag, Ice.Optional<float> v)
+ {
+ if(v.HasValue)
+ {
+ writeFloat(tag, v.Value);
+ }
+ }
+
+ public void writeFloat(int tag, float v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.F4))
+ {
+ writeFloat(v);
+ }
+ }
+
+ public void writeFloatSeq(float[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ expand(v.Length * 4);
+ _buf.b.putFloatSeq(v);
+ }
+ }
+
+ public void writeFloatSeq(int count, IEnumerable<float> v)
+ {
+ if(count == 0)
+ {
+ writeSize(0);
+ return;
+ }
+
+ {
+ List<float> value = v as List<float>;
+ if(value != null)
+ {
+ writeFloatSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ LinkedList<float> value = v as LinkedList<float>;
+ if(value != null)
+ {
+ writeSize(count);
+ expand(count * 4);
+ IEnumerator<float> i = v.GetEnumerator();
+ while(i.MoveNext())
+ {
+ _buf.b.putFloat(i.Current);
+ }
+ return;
+ }
+ }
+
+ {
+ Queue<float> value = v as Queue<float>;
+ if(value != null)
+ {
+ writeFloatSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ Stack<float> value = v as Stack<float>;
+ if(value != null)
+ {
+ writeFloatSeq(value.ToArray());
+ return;
+ }
+ }
+
+ writeSize(count);
+ expand(count * 4);
+ foreach(float f in v)
+ {
+ _buf.b.putFloat(f);
+ }
+ }
+
+ public void writeFloatSeq(int tag, Ice.Optional<float[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeFloatSeq(tag, v.Value);
+ }
+ }
+
+ public void writeFloatSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<float>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
+ writeFloatSeq(count, v.Value);
+ }
+ }
+
+ public void writeFloatSeq(int tag, float[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || v.Length == 0 ? 1 : v.Length * 4 + (v.Length > 254 ? 5 : 1));
+ writeFloatSeq(v);
+ }
+ }
+
+ public void writeFloatSeq(int tag, int count, IEnumerable<float> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
+ writeFloatSeq(count, v);
+ }
+ }
+
+ public float readFloat()
+ {
+ try
+ {
+ return _buf.b.getFloat();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.Optional<float> readFloat(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.F4))
+ {
+ return new Ice.Optional<float>(readFloat());
+ }
+ else
+ {
+ return new Ice.Optional<float>();
+ }
+ }
+
+ public void readFloat(int tag, out bool isset, out float v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.F4))
+ {
+ v = readFloat();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ public float[] readFloatSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ float[] v = new float[sz];
+ _buf.b.getFloatSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readFloatSeq(out List<float> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new List<float>(readFloatSeq());
+ }
+
+ public void readFloatSeq(out LinkedList<float> l)
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new LinkedList<float>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(_buf.b.getFloat());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readFloatSeq(out Queue<float> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue takes the same time as constructing the queue
+ // and adding to it one element at a time, so
+ // we avoid the copy.
+ //
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new Queue<float>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(_buf.b.getFloat());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readFloatSeq(out Stack<float> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ float[] array = readFloatSeq();
+ Array.Reverse(array);
+ l = new Stack<float>(array);
+ }
+
+ public Ice.Optional<float[]> readFloatSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<float[]>(readFloatSeq());
+ }
+ else
+ {
+ return new Ice.Optional<float[]>();
+ }
+ }
+
+ public void readFloatSeq(int tag, out bool isset, out float[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readFloatSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public void writeDouble(double v)
+ {
+ expand(8);
+ _buf.b.putDouble(v);
+ }
+
+ public void writeDouble(int tag, Ice.Optional<double> v)
+ {
+ if(v.HasValue)
+ {
+ writeDouble(tag, v.Value);
+ }
+ }
+
+ public void writeDouble(int tag, double v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.F8))
+ {
+ writeDouble(v);
+ }
+ }
+
+ public void writeDoubleSeq(double[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ expand(v.Length * 8);
+ _buf.b.putDoubleSeq(v);
+ }
+ }
+
+ public void writeDoubleSeq(int count, IEnumerable<double> v)
+ {
+ if(count == 0)
+ {
+ writeSize(0);
+ return;
+ }
+
+ {
+ List<double> value = v as List<double>;
+ if(value != null)
+ {
+ writeDoubleSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ LinkedList<double> value = v as LinkedList<double>;
+ if(value != null)
+ {
+ writeSize(count);
+ expand(count * 8);
+ IEnumerator<double> i = v.GetEnumerator();
+ while(i.MoveNext())
+ {
+ _buf.b.putDouble(i.Current);
+ }
+ return;
+ }
+ }
+
+ {
+ Queue<double> value = v as Queue<double>;
+ if(value != null)
+ {
+ writeDoubleSeq(value.ToArray());
+ return;
+ }
+ }
+
+ {
+ Stack<double> value = v as Stack<double>;
+ if (value != null)
+ {
+ writeDoubleSeq(value.ToArray());
+ return;
+ }
+ }
+
+ writeSize(count);
+ expand(count * 8);
+ foreach(double d in v)
+ {
+ _buf.b.putDouble(d);
+ }
+ }
+
+ public void writeDoubleSeq(int tag, Ice.Optional<double[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeDoubleSeq(tag, v.Value);
+ }
+ }
+
+ public void writeDoubleSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<double>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
+ writeDoubleSeq(count, v.Value);
+ }
+ }
+
+ public void writeDoubleSeq(int tag, double[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || v.Length == 0 ? 1 : v.Length * 8 + (v.Length > 254 ? 5 : 1));
+ writeDoubleSeq(v);
+ }
+ }
+
+ public void writeDoubleSeq(int tag, int count, IEnumerable<double> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeSize(v == null || count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
+ writeDoubleSeq(count, v);
+ }
+ }
+
+ public double readDouble()
+ {
+ try
+ {
+ return _buf.b.getDouble();
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public Ice.Optional<double> readDouble(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.F8))
+ {
+ return new Ice.Optional<double>(readDouble());
+ }
+ else
+ {
+ return new Ice.Optional<double>();
+ }
+ }
+
+ public void readDouble(int tag, out bool isset, out double v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.F8))
+ {
+ v = readDouble();
+ }
+ else
+ {
+ v = 0;
+ }
+ }
+
+ public double[] readDoubleSeq()
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(8);
+ double[] v = new double[sz];
+ _buf.b.getDoubleSeq(v);
+ return v;
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readDoubleSeq(out List<double> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is faster than constructing the list
+ // and adding to it one element at a time.
+ //
+ l = new List<double>(readDoubleSeq());
+ }
+
+ public void readDoubleSeq(out LinkedList<double> l)
+ {
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new LinkedList<double>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(_buf.b.getDouble());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readDoubleSeq(out Queue<double> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue takes the same time as constructing the queue
+ // and adding to it one element at a time, so
+ // we avoid the copy.
+ //
+ try
+ {
+ int sz = readAndCheckSeqSize(4);
+ l = new Queue<double>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(_buf.b.getDouble());
+ }
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ }
+
+ public void readDoubleSeq(out Stack<double> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ double[] array = readDoubleSeq();
+ Array.Reverse(array);
+ l = new Stack<double>(array);
+ }
+
+ public Ice.Optional<double[]> readDoubleSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ return new Ice.Optional<double[]>(readDoubleSeq());
+ }
+ else
+ {
+ return new Ice.Optional<double[]>();
+ }
+ }
+
+ public void readDoubleSeq(int tag, out bool isset, out double[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ skipSize();
+ v = readDoubleSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ private static System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false, true);
+
+ public void writeString(string v)
+ {
+ if(v == null || v.Length == 0)
+ {
+ writeSize(0);
+ return;
+ }
+ byte[] arr = utf8.GetBytes(v);
+ writeSize(arr.Length);
+ expand(arr.Length);
+ _buf.b.put(arr);
+ }
+
+ public void writeString(int tag, Ice.Optional<string> v)
+ {
+ if(v.HasValue)
+ {
+ writeString(tag, v.Value);
+ }
+ }
+
+ public void writeString(int tag, string v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ writeString(v);
+ }
+ }
+
+ public void writeStringSeq(string[] v)
+ {
+ if(v == null)
+ {
+ writeSize(0);
+ }
+ else
+ {
+ writeSize(v.Length);
+ for(int i = 0; i < v.Length; i++)
+ {
+ writeString(v[i]);
+ }
+ }
+ }
+
+ public void writeStringSeq(int size, IEnumerable<string> e)
+ {
+ writeSize(size);
+ if(size != 0)
+ {
+ foreach(string s in e)
+ {
+ writeString(s);
+ }
+ }
+ }
+
+ public void writeStringSeq(int tag, Ice.Optional<String[]> v)
+ {
+ if(v.HasValue)
+ {
+ writeStringSeq(tag, v.Value);
+ }
+ }
+
+ public void writeStringSeq<T>(int tag, int count, Ice.Optional<T> v)
+ where T : IEnumerable<string>
+ {
+ if(v.HasValue && writeOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ int pos = startSize();
+ writeStringSeq(count, v.Value);
+ endSize(pos);
+ }
+ }
+
+ public void writeStringSeq(int tag, string[] v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ int pos = startSize();
+ writeStringSeq(v);
+ endSize(pos);
+ }
+ }
+
+ public void writeStringSeq(int tag, int count, IEnumerable<string> v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ int pos = startSize();
+ writeStringSeq(count, v);
+ endSize(pos);
+ }
+ }
+
+ public string readString()
+ {
+ int len = readSize();
+
+ if(len == 0)
+ {
+ return "";
+ }
+
+ //
+ // Check the buffer has enough bytes to read.
+ //
+ if(_buf.b.remaining() < len)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ try
+ {
+ //
+ // We reuse the _stringBytes array to avoid creating
+ // excessive garbage
+ //
+ if(_stringBytes == null || len > _stringBytes.Length)
+ {
+ _stringBytes = new byte[len];
+ }
+ _buf.b.get(_stringBytes, 0, len);
+ return utf8.GetString(_stringBytes, 0, len);
+ }
+ catch(InvalidOperationException ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException(ex);
+ }
+ catch(System.ArgumentException ex)
+ {
+ throw new Ice.MarshalException("Invalid UTF8 string", ex);
+ }
+ }
+
+ public Ice.Optional<string> readString(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ return new Ice.Optional<string>(readString());
+ }
+ else
+ {
+ return new Ice.Optional<string>();
+ }
+ }
+
+ public void readString(int tag, out bool isset, out string v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.VSize))
+ {
+ v = readString();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public string[] readStringSeq()
+ {
+ int sz = readAndCheckSeqSize(1);
+ string[] v = new string[sz];
+ for(int i = 0; i < sz; i++)
+ {
+ v[i] = readString();
+ }
+ return v;
+ }
+
+ public void readStringSeq(out List<string> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is slower than constructing the list
+ // and adding to it one element at a time.
+ //
+ int sz = readAndCheckSeqSize(1);
+ l = new List<string>(sz);
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Add(readString());
+ }
+ }
+
+ public void readStringSeq(out LinkedList<string> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // list is slower than constructing the list
+ // and adding to it one element at a time.
+ //
+ int sz = readAndCheckSeqSize(1);
+ l = new LinkedList<string>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.AddLast(readString());
+ }
+ }
+
+ public void readStringSeq(out Queue<string> l)
+ {
+ //
+ // Reading into an array and copy-constructing the
+ // queue is slower than constructing the queue
+ // and adding to it one element at a time.
+ //
+ int sz = readAndCheckSeqSize(1);
+ l = new Queue<string>();
+ for(int i = 0; i < sz; ++i)
+ {
+ l.Enqueue(readString());
+ }
+ }
+
+ public void readStringSeq(out Stack<string> l)
+ {
+ //
+ // Reverse the contents by copying into an array first
+ // because the stack is marshaled in top-to-bottom order.
+ //
+ string[] array = readStringSeq();
+ Array.Reverse(array);
+ l = new Stack<string>(array);
+ }
+
+ public Ice.Optional<string[]> readStringSeq(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ return new Ice.Optional<string[]>(readStringSeq());
+ }
+ else
+ {
+ return new Ice.Optional<string[]>();
+ }
+ }
+
+ public void readStringSeq(int tag, out bool isset, out string[] v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ v = readStringSeq();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public void writeProxy(Ice.ObjectPrx v)
+ {
+ instance_.proxyFactory().proxyToStream(v, this);
+ }
+
+ public void writeProxy(int tag, Ice.Optional<Ice.ObjectPrx> v)
+ {
+ if(v.HasValue)
+ {
+ writeProxy(tag, v.Value);
+ }
+ }
+
+ public void writeProxy(int tag, Ice.ObjectPrx v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ int pos = startSize();
+ writeProxy(v);
+ endSize(pos);
+ }
+ }
+
+ public Ice.ObjectPrx readProxy()
+ {
+ return instance_.proxyFactory().streamToProxy(this);
+ }
+
+ public Ice.Optional<Ice.ObjectPrx> readProxy(int tag)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ return new Ice.Optional<Ice.ObjectPrx>(readProxy());
+ }
+ else
+ {
+ return new Ice.Optional<Ice.ObjectPrx>();
+ }
+ }
+
+ public void readProxy(int tag, out bool isset, out Ice.ObjectPrx v)
+ {
+ if(isset = readOpt(tag, Ice.OptionalFormat.FSize))
+ {
+ skip(4);
+ v = readProxy();
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ public void writeEnum(int v, int maxValue)
+ {
+ if(isWriteEncoding_1_0())
+ {
+ if(maxValue < 127)
+ {
+ writeByte((byte)v);
+ }
+ else if(maxValue < 32767)
+ {
+ writeShort((short)v);
+ }
+ else
+ {
+ writeInt(v);
+ }
+ }
+ else
+ {
+ writeSize(v);
+ }
+ }
+
+ public void writeEnum(int tag, int v, int maxValue)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.Size))
+ {
+ writeEnum(v, maxValue);
+ }
+ }
+
+ public int readEnum(int maxValue)
+ {
+ if(getReadEncoding().Equals(Ice.Util.Encoding_1_0))
+ {
+ if(maxValue < 127)
+ {
+ return readByte();
+ }
+ else if(maxValue < 32767)
+ {
+ return readShort();
+ }
+ else
+ {
+ return readInt();
+ }
+ }
+ else
+ {
+ return readSize();
+ }
+ }
+
+ public void writeObject(Ice.Object v)
+ {
+ initWriteEncaps();
+ _writeEncapsStack.encoder.writeObject(v);
+ }
+
+ public void writeObject<T>(int tag, Ice.Optional<T> v)
+ where T : Ice.Object
+ {
+ if(v.HasValue)
+ {
+ writeObject(tag, v.Value);
+ }
+ }
+
+ public void writeObject(int tag, Ice.Object v)
+ {
+ if(writeOpt(tag, Ice.OptionalFormat.Class))
+ {
+ writeObject(v);
+ }
+ }
+
+ public void readObject(IPatcher patcher)
+ {
+ initReadEncaps();
+ _readEncapsStack.decoder.readObject(patcher);
+ }
+
+ public void readObject(int tag, IPatcher patcher)
+ {
+ if(readOpt(tag, Ice.OptionalFormat.Class))
+ {
+ readObject(patcher);
+ }
+ }
+
+ public void writeUserException(Ice.UserException v)
+ {
+ initWriteEncaps();
+ _writeEncapsStack.encoder.writeUserException(v);
+ }
+
+ public void throwException(UserExceptionFactory factory)
+ {
+ initReadEncaps();
+ _readEncapsStack.decoder.throwException(factory);
+ }
+
+ public void sliceObjects(bool b)
+ {
+ _sliceObjects = b;
+ }
+
+ public bool readOptImpl(int readTag, Ice.OptionalFormat expectedFormat)
+ {
+ if(isReadEncoding_1_0())
+ {
+ return false; // Optional members aren't supported with the 1.0 encoding.
+ }
+
+ while(true)
+ {
+ if(_buf.b.position() >= _readEncapsStack.start + _readEncapsStack.sz)
+ {
+ return false; // End of encapsulation also indicates end of optionals.
+ }
+
+ int v = readByte();
+ if(v == OPTIONAL_END_MARKER)
+ {
+ _buf.b.position(_buf.b.position() - 1); // Rewind.
+ return false;
+ }
+
+ Ice.OptionalFormat format = (Ice.OptionalFormat)(v & 0x07); // First 3 bits.
+ int tag = v >> 3;
+ if(tag == 30)
+ {
+ tag = readSize();
+ }
+
+ if(tag > readTag)
+ {
+ int offset = tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind
+ _buf.b.position(_buf.b.position() - offset);
+ return false; // No optional data members with the requested tag.
+ }
+ else if(tag < readTag)
+ {
+ skipOpt(format); // Skip optional data members
+ }
+ else
+ {
+ if(format != expectedFormat)
+ {
+ throw new Ice.MarshalException("invalid optional data member `" + tag + "': unexpected format");
+ }
+ return true;
+ }
+ }
+ }
+
+ public bool writeOptImpl(int tag, Ice.OptionalFormat format)
+ {
+ if(isWriteEncoding_1_0())
+ {
+ return false; // Optional members aren't supported with the 1.0 encoding.
+ }
+
+ int v = (int)format;
+ if(tag < 30)
+ {
+ v |= tag << 3;
+ writeByte((byte)v);
+ }
+ else
+ {
+ v |= 0x0F0; // tag = 30
+ writeByte((byte)v);
+ writeSize(tag);
+ }
+ return true;
+ }
+
+ public void skipOpt(Ice.OptionalFormat format)
+ {
+ switch(format)
+ {
+ case Ice.OptionalFormat.F1:
+ {
+ skip(1);
+ break;
+ }
+ case Ice.OptionalFormat.F2:
+ {
+ skip(2);
+ break;
+ }
+ case Ice.OptionalFormat.F4:
+ {
+ skip(4);
+ break;
+ }
+ case Ice.OptionalFormat.F8:
+ {
+ skip(8);
+ break;
+ }
+ case Ice.OptionalFormat.Size:
+ {
+ skipSize();
+ break;
+ }
+ case Ice.OptionalFormat.VSize:
+ {
+ skip(readSize());
+ break;
+ }
+ case Ice.OptionalFormat.FSize:
+ {
+ skip(readInt());
+ break;
+ }
+ case Ice.OptionalFormat.Class:
+ {
+ readObject(null);
+ break;
+ }
+ }
+ }
+
+ public bool skipOpts()
+ {
+ //
+ // Skip remaining un-read optional members.
+ //
+ while(true)
+ {
+ if(_buf.b.position() >= _readEncapsStack.start + _readEncapsStack.sz)
+ {
+ return false; // End of encapsulation also indicates end of optionals.
+ }
+
+ int v = readByte();
+ if(v == OPTIONAL_END_MARKER)
+ {
+ return true;
+ }
+
+ Ice.OptionalFormat format = (Ice.OptionalFormat)(v & 0x07); // Read first 3 bits.
+ if((v >> 3) == 30)
+ {
+ skipSize();
+ }
+ skipOpt(format);
+ }
+ }
+
+ public void skip(int size)
+ {
+ if(size > _buf.b.remaining())
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ _buf.b.position(_buf.b.position() + size);
+ }
+
+ public void skipSize()
+ {
+ byte b = readByte();
+ if(b == 255)
+ {
+ skip(4);
+ }
+ }
+
+ public int pos()
+ {
+ return _buf.b.position();
+ }
+
+ public void pos(int n)
+ {
+ _buf.b.position(n);
+ }
+
+ public int size()
+ {
+ return _buf.size();
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ static string getBZ2Error(int error)
+ {
+ string rc;
+
+ switch(error)
+ {
+ case BZ_SEQUENCE_ERROR:
+ {
+ rc = "BZ_SEQUENCE_ERROR";
+ break;
+ }
+ case BZ_PARAM_ERROR:
+ {
+ rc = "BZ_PARAM_ERROR";
+ break;
+ }
+ case BZ_MEM_ERROR:
+ {
+ rc = "BZ_MEM_ERROR";
+ break;
+ }
+ case BZ_DATA_ERROR:
+ {
+ rc = "BZ_DATA_ERROR";
+ break;
+ }
+ case BZ_DATA_ERROR_MAGIC:
+ {
+ rc = "BZ_DATA_ERROR_MAGIC";
+ break;
+ }
+ case BZ_IO_ERROR:
+ {
+ rc = "BZ_IO_ERROR";
+ break;
+ }
+ case BZ_UNEXPECTED_EOF:
+ {
+ rc = "BZ_UNEXPECTED_EOF";
+ break;
+ }
+ case BZ_OUTBUFF_FULL:
+ {
+ rc = "BZ_OUTBUFF_FULL";
+ break;
+ }
+ case BZ_CONFIG_ERROR:
+ {
+ rc = "BZ_CONFIG_ERROR";
+ break;
+ }
+ default:
+ {
+ rc = "Unknown bzip2 error: " + error;
+ break;
+ }
+ }
+ return rc;
+ }
+#endif
+
+ public static bool compressible()
+ {
+ return _bzlibInstalled;
+ }
+
+ public bool compress(ref BasicStream cstream, int headerSize, int compressionLevel)
+ {
+#if MANAGED || COMPACT || SILVERLIGHT
+ cstream = this;
+ return false;
+#else
+ if(!_bzlibInstalled)
+ {
+ cstream = this;
+ return false;
+ }
+
+ //
+ // Compress the message body, but not the header.
+ //
+ int uncompressedLen = size() - headerSize;
+ byte[] uncompressed = _buf.b.rawBytes(headerSize, uncompressedLen);
+ int compressedLen = (int)(uncompressedLen * 1.01 + 600);
+ byte[] compressed = new byte[compressedLen];
+
+ int rc = NativeMethods.BZ2_bzBuffToBuffCompress(compressed, ref compressedLen, uncompressed,
+ uncompressedLen, compressionLevel, 0, 0);
+ if(rc == BZ_OUTBUFF_FULL)
+ {
+ cstream = null;
+ return false;
+ }
+ else if(rc < 0)
+ {
+ Ice.CompressionException ex = new Ice.CompressionException("BZ2_bzBuffToBuffCompress failed");
+ ex.reason = getBZ2Error(rc);
+ throw ex;
+ }
+
+ //
+ // Don't bother if the compressed data is larger than the
+ // uncompressed data.
+ //
+ if(compressedLen >= uncompressedLen)
+ {
+ return false;
+ }
+
+ cstream = new BasicStream(instance_, _encoding);
+ cstream.resize(headerSize + 4 + compressedLen, false);
+ cstream.pos(0);
+
+ //
+ // Copy the header from the uncompressed stream to the
+ // compressed one.
+ //
+ cstream._buf.b.put(_buf.b.rawBytes(0, headerSize));
+
+ //
+ // Add the size of the uncompressed stream before the
+ // message body.
+ //
+ cstream.writeInt(size());
+
+ //
+ // Add the compressed message body.
+ //
+ cstream._buf.b.put(compressed, 0, compressedLen);
+
+ return true;
+#endif
+ }
+
+ public BasicStream uncompress(int headerSize, int messageSizeMax)
+ {
+#if MANAGED || COMPACT || SILVERLIGHT
+ return this;
+#else
+ if(!_bzlibInstalled)
+ {
+ return this;
+ }
+
+ pos(headerSize);
+ int uncompressedSize = readInt();
+ if(uncompressedSize <= headerSize)
+ {
+ throw new Ice.IllegalMessageSizeException("compressed size <= header size");
+ }
+ if(uncompressedSize > messageSizeMax)
+ {
+ IceInternal.Ex.throwMemoryLimitException(uncompressedSize, messageSizeMax);
+ }
+
+ int compressedLen = size() - headerSize - 4;
+ byte[] compressed = _buf.b.rawBytes(headerSize + 4, compressedLen);
+ int uncompressedLen = uncompressedSize - headerSize;
+ byte[] uncompressed = new byte[uncompressedLen];
+ int rc = NativeMethods.BZ2_bzBuffToBuffDecompress(uncompressed, ref uncompressedLen, compressed,
+ compressedLen, 0, 0);
+ if(rc < 0)
+ {
+ Ice.CompressionException ex = new Ice.CompressionException("BZ2_bzBuffToBuffDecompress failed");
+ ex.reason = getBZ2Error(rc);
+ throw ex;
+ }
+ BasicStream ucStream = new BasicStream(instance_, _encoding);
+ ucStream.resize(uncompressedSize, false);
+ ucStream.pos(0);
+ ucStream._buf.b.put(_buf.b.rawBytes(0, headerSize));
+ ucStream._buf.b.put(uncompressed, 0, uncompressedLen);
+ return ucStream;
+#endif
+ }
+
+ public bool isEmpty()
+ {
+ return _buf.empty();
+ }
+
+ public void expand(int n)
+ {
+ _buf.expand(n);
+ }
+
+ private Ice.Object createObject(string id)
+ {
+ Ice.Object obj = null;
+
+ try
+ {
+ Type c = AssemblyUtil.findType(instance_, typeToClass(id));
+ //
+ // Ensure the class is instantiable.
+ //
+ if(c != null && !c.IsAbstract && !c.IsInterface)
+ {
+ obj = (Ice.Object)AssemblyUtil.createInstance(c);
+ }
+ }
+ catch(Exception ex)
+ {
+ Ice.NoObjectFactoryException e = new Ice.NoObjectFactoryException(ex);
+ e.type = id;
+ throw e;
+ }
+
+ return obj;
+ }
+
+ private string getTypeId(int compactId)
+ {
+ String className = "IceCompactId.TypeId_" + compactId;
+ try
+ {
+ Type c = AssemblyUtil.findType(instance_, className);
+ if(c != null)
+ {
+ return (string)c.GetField("typeId").GetValue(null);
+ }
+ }
+ catch(Exception)
+ {
+ }
+ return "";
+ }
+
+ private sealed class DynamicUserExceptionFactory : UserExceptionFactory
+ {
+ internal DynamicUserExceptionFactory(Type c)
+ {
+ _class = c;
+ }
+
+ public void createAndThrow(string typeId)
+ {
+ try
+ {
+ throw (Ice.UserException)AssemblyUtil.createInstance(_class);
+ }
+ catch(Ice.UserException)
+ {
+ throw;
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.SyscallException(ex);
+ }
+ }
+
+ public void destroy()
+ {
+ }
+
+ private Type _class;
+ }
+
+ private Ice.UserException createUserException(string id)
+ {
+ Ice.UserException userEx = null;
+
+ try
+ {
+ Type c = AssemblyUtil.findType(instance_, typeToClass(id));
+ if(c != null)
+ {
+ //
+ // Ensure the class is instantiable.
+ //
+ Debug.Assert(!c.IsAbstract && !c.IsInterface);
+ userEx = (Ice.UserException)AssemblyUtil.createInstance(c);
+ }
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.MarshalException(ex);
+ }
+
+ return userEx;
+ }
+
+ private static string typeToClass(string id)
+ {
+ if(!id.StartsWith("::", StringComparison.Ordinal))
+ {
+ throw new Ice.MarshalException("expected type id but received `" + id + "'");
+ }
+ return id.Substring(2).Replace("::", ".");
+ }
+
+ //
+ // Optional data member type.
+ //
+ internal const int MemberFormatF1 = 0;
+ internal const int MemberFormatF2 = 1;
+ internal const int MemberFormatF4 = 2;
+ internal const int MemberFormatF8 = 3;
+ internal const int MemberFormatVSize = 4;
+ internal const int MemberFormatFSize = 5;
+ internal const int MemberFormatReserved = 6;
+ internal const int MemberFormatEndMarker = 7;
+
+ private Instance instance_;
+ private Buffer _buf;
+ private object _closure;
+ private byte[] _stringBytes; // Reusable array for reading strings.
+
+ private enum SliceType { NoSlice, ObjectSlice, ExceptionSlice }
+
+ abstract private class EncapsDecoder
+ {
+ internal EncapsDecoder(BasicStream stream, ReadEncaps encaps, bool sliceObjects, ObjectFactoryManager f)
+ {
+ _stream = stream;
+ _encaps = encaps;
+ _sliceObjects = sliceObjects;
+ _servantFactoryManager = f;
+ _typeIdIndex = 0;
+ _unmarshaledMap = new Dictionary<int, Ice.Object>();
+ }
+
+ internal abstract void readObject(IPatcher patcher);
+ internal abstract void throwException(UserExceptionFactory factory);
+
+ internal abstract void startInstance(SliceType type);
+ internal abstract Ice.SlicedData endInstance(bool preserve);
+ internal abstract string startSlice();
+ internal abstract void endSlice();
+ internal abstract void skipSlice();
+
+ internal virtual bool readOpt(int tag, Ice.OptionalFormat format)
+ {
+ return false;
+ }
+
+ internal virtual void readPendingObjects()
+ {
+ }
+
+ protected string readTypeId(bool isIndex)
+ {
+ if(_typeIdMap == null)
+ {
+ _typeIdMap = new Dictionary<int, string>();
+ }
+
+ if(isIndex)
+ {
+ int index = _stream.readSize();
+ string typeId;
+ if(!_typeIdMap.TryGetValue(index, out typeId))
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ return typeId;
+ }
+ else
+ {
+ string typeId = _stream.readString();
+ _typeIdMap.Add(++_typeIdIndex, typeId);
+ return typeId;
+ }
+ }
+
+ protected Ice.Object newInstance(string typeId)
+ {
+ //
+ // Try to find a factory registered for the specific type.
+ //
+ Ice.ObjectFactory userFactory = _servantFactoryManager.find(typeId);
+ Ice.Object v = null;
+ if(userFactory != null)
+ {
+ v = userFactory.create(typeId);
+ }
+
+ //
+ // If that fails, invoke the default factory if one has been
+ // registered.
+ //
+ if(v == null)
+ {
+ userFactory = _servantFactoryManager.find("");
+ if(userFactory != null)
+ {
+ v = userFactory.create(typeId);
+ }
+ }
+
+ //
+ // Last chance: try to instantiate the class dynamically.
+ //
+ if(v == null)
+ {
+ v = _stream.createObject(typeId);
+ }
+
+ return v;
+ }
+
+ protected void addPatchEntry(int index, IPatcher patcher)
+ {
+ Debug.Assert(index > 0);
+
+ //
+ // Check if already un-marshalled the object. If that's the case,
+ // just patch the object smart pointer and we're done.
+ //
+ Ice.Object obj;
+ if(_unmarshaledMap.TryGetValue(index, out obj))
+ {
+ patcher.patch(obj);
+ return;
+ }
+
+ if(_patchMap == null)
+ {
+ _patchMap = new Dictionary<int, LinkedList<IPatcher>>();
+ }
+
+ //
+ // Add patch entry if the object isn't un-marshalled yet,
+ // the smart pointer will be patched when the instance is
+ // un-marshalled.
+ //
+ LinkedList<IPatcher> l;
+ if(!_patchMap.TryGetValue(index, out l))
+ {
+ //
+ // We have no outstanding instances to be patched for this
+ // index, so make a new entry in the patch map.
+ //
+ l = new LinkedList<IPatcher>();
+ _patchMap.Add(index, l);
+ }
+
+ //
+ // Append a patch entry for this instance.
+ //
+ l.AddLast(patcher);
+ }
+
+ protected void unmarshal(int index, Ice.Object v)
+ {
+ //
+ // Add the object to the map of un-marshalled objects, this must
+ // be done before reading the objects (for circular references).
+ //
+ _unmarshaledMap.Add(index, v);
+
+ //
+ // Read the object.
+ //
+ v.read__(_stream);
+
+ if(_patchMap != null)
+ {
+ //
+ // Patch all instances now that the object is un-marshalled.
+ //
+ LinkedList<IPatcher> l;
+ if(_patchMap.TryGetValue(index, out l))
+ {
+ Debug.Assert(l.Count > 0);
+
+ //
+ // Patch all pointers that refer to the instance.
+ //
+ foreach(IPatcher p in l)
+ {
+ p.patch(v);
+ }
+
+ //
+ // Clear out the patch map for that index -- there is nothing left
+ // to patch for that index for the time being.
+ //
+ _patchMap.Remove(index);
+ }
+ }
+
+ if((_patchMap == null || _patchMap.Count == 0) && _objectList == null)
+ {
+ try
+ {
+ v.ice_postUnmarshal();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception raised by ice_postUnmarshal:\n" + ex;
+ _stream.instance().initializationData().logger.warning(s);
+ }
+ }
+ else
+ {
+ if(_objectList == null)
+ {
+ _objectList = new List<Ice.Object>();
+ }
+ _objectList.Add(v);
+
+ if(_patchMap == null || _patchMap.Count == 0)
+ {
+ //
+ // Iterate over the object list and invoke ice_postUnmarshal on
+ // each object. We must do this after all objects have been
+ // unmarshaled in order to ensure that any object data members
+ // have been properly patched.
+ //
+ foreach(Ice.Object p in _objectList)
+ {
+ try
+ {
+ p.ice_postUnmarshal();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception raised by ice_postUnmarshal:\n" + ex;
+ _stream.instance().initializationData().logger.warning(s);
+ }
+ }
+ _objectList.Clear();
+ }
+ }
+ }
+
+ protected readonly BasicStream _stream;
+ protected readonly ReadEncaps _encaps;
+ protected readonly bool _sliceObjects;
+ protected ObjectFactoryManager _servantFactoryManager;
+
+ // Encapsulation attributes for object un-marshalling
+ protected Dictionary<int, LinkedList<IPatcher> > _patchMap;
+
+ // Encapsulation attributes for object un-marshalling
+ private Dictionary<int, Ice.Object> _unmarshaledMap;
+ private Dictionary<int, string> _typeIdMap;
+ private int _typeIdIndex;
+ private List<Ice.Object> _objectList;
+ };
+
+ private sealed class EncapsDecoder10 : EncapsDecoder
+ {
+ internal EncapsDecoder10(BasicStream stream, ReadEncaps encaps, bool sliceObjects, ObjectFactoryManager f)
+ : base(stream, encaps, sliceObjects, f)
+ {
+ _sliceType = SliceType.NoSlice;
+ }
+
+ internal override void readObject(IPatcher patcher)
+ {
+ Debug.Assert(patcher != null);
+
+ //
+ // Object references are encoded as a negative integer in 1.0.
+ //
+ int index = _stream.readInt();
+ if(index > 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+ index = -index;
+
+ if(index == 0)
+ {
+ patcher.patch(null);
+ }
+ else
+ {
+ addPatchEntry(index, patcher);
+ }
+ }
+
+ internal override void throwException(UserExceptionFactory factory)
+ {
+ Debug.Assert(_sliceType == SliceType.NoSlice);
+
+ //
+ // User exception with the 1.0 encoding start with a bool flag
+ // that indicates whether or not the exception has classes.
+ //
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
+ //
+ bool usesClasses = _stream.readBool();
+
+ _sliceType = SliceType.ExceptionSlice;
+ _skipFirstSlice = false;
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _typeId;
+ while(true)
+ {
+ Ice.UserException userEx = null;
+
+ //
+ // Use a factory if one was provided.
+ //
+ if(factory != null)
+ {
+ try
+ {
+ factory.createAndThrow(_typeId);
+ }
+ catch(Ice.UserException ex)
+ {
+ userEx = ex;
+ }
+ }
+
+ if(userEx == null)
+ {
+ userEx = _stream.createUserException(_typeId);
+ }
+
+ //
+ // We found the exception.
+ //
+ if(userEx != null)
+ {
+ userEx.read__(_stream);
+ if(usesClasses)
+ {
+ readPendingObjects();
+ }
+ throw userEx;
+
+ // Never reached.
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+ try
+ {
+ startSlice();
+ }
+ catch(Ice.UnmarshalOutOfBoundsException ex)
+ {
+ //
+ // An oversight in the 1.0 encoding means there is no marker to indicate
+ // the last slice of an exception. As a result, we just try to read the
+ // next type ID, which raises UnmarshalOutOfBoundsException when the
+ // input buffer underflows.
+ //
+ // Set the reason member to a more helpful message.
+ //
+ ex.reason = "unknown exception type `" + mostDerivedId + "'";
+ throw ex;
+ }
+ }
+ }
+
+ internal override void startInstance(SliceType sliceType)
+ {
+ Debug.Assert(_sliceType == sliceType);
+ _skipFirstSlice = true;
+ }
+
+ internal override Ice.SlicedData endInstance(bool preserve)
+ {
+ //
+ // Read the Ice::Object slice.
+ //
+ if(_sliceType == SliceType.ObjectSlice)
+ {
+ startSlice();
+ int sz = _stream.readSize(); // For compatibility with the old AFM.
+ if(sz != 0)
+ {
+ throw new Ice.MarshalException("invalid Object slice");
+ }
+ endSlice();
+ }
+
+ _sliceType = SliceType.NoSlice;
+ return null;
+ }
+
+ internal override string startSlice()
+ {
+ //
+ // If first slice, don't read the header, it was already read in
+ // readInstance or throwException to find the factory.
+ //
+ if(_skipFirstSlice)
+ {
+ _skipFirstSlice = false;
+ return _typeId;
+ }
+
+ //
+ // For objects, first read the type ID bool which indicates
+ // whether or not the type ID is encoded as a string or as an
+ // index. For exceptions, the type ID is always encoded as a
+ // string.
+ //
+ if(_sliceType == SliceType.ObjectSlice) // For exceptions, the type ID is always encoded as a string
+ {
+ bool isIndex = _stream.readBool();
+ _typeId = readTypeId(isIndex);
+ }
+ else
+ {
+ _typeId = _stream.readString();
+ }
+
+ _sliceSize = _stream.readInt();
+ if(_sliceSize < 4)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ return _typeId;
+ }
+
+ internal override void endSlice()
+ {
+ }
+
+ internal override void skipSlice()
+ {
+ if(_stream.instance().traceLevels().slicing > 0)
+ {
+ Ice.Logger logger = _stream.instance().initializationData().logger;
+ string slicingCat = _stream.instance().traceLevels().slicingCat;
+ if(_sliceType == SliceType.ObjectSlice)
+ {
+ TraceUtil.traceSlicing("object", _typeId, slicingCat, logger);
+ }
+ else
+ {
+ TraceUtil.traceSlicing("exception", _typeId, slicingCat, logger);
+ }
+ }
+
+ Debug.Assert(_sliceSize >= 4);
+ _stream.skip(_sliceSize - 4);
+ }
+
+ internal override void readPendingObjects()
+ {
+ int num;
+ do
+ {
+ num = _stream.readSize();
+ for(int k = num; k > 0; --k)
+ {
+ readInstance();
+ }
+ }
+ while(num > 0);
+
+ if(_patchMap != null && _patchMap.Count > 0)
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw new Ice.MarshalException("index for class received, but no instance");
+ }
+ }
+
+ private void readInstance()
+ {
+ int index = _stream.readInt();
+
+ if(index <= 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+
+ _sliceType = SliceType.ObjectSlice;
+ _skipFirstSlice = false;
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _typeId;
+ Ice.Object v = null;
+ while(true)
+ {
+ //
+ // For the 1.0 encoding, the type ID for the base Object class
+ // marks the last slice.
+ //
+ if(_typeId.Equals(Ice.ObjectImpl.ice_staticId()))
+ {
+ throw new Ice.NoObjectFactoryException("", mostDerivedId);
+ }
+
+ v = newInstance(_typeId);
+
+ //
+ // We found a factory, we get out of this loop.
+ //
+ if(v != null)
+ {
+ break;
+ }
+
+ //
+ // If object slicing is disabled, stop un-marshalling.
+ //
+ if(!_sliceObjects)
+ {
+ throw new Ice.NoObjectFactoryException("no object factory found and object slicing is disabled",
+ _typeId);
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+ startSlice(); // Read next Slice header for next iteration.
+ }
+
+ //
+ // Un-marshal the object and add-it to the map of un-marshaled objects.
+ //
+ unmarshal(index, v);
+ }
+
+ // Object/exception attributes
+ private SliceType _sliceType;
+ private bool _skipFirstSlice;
+
+ // Slice attributes
+ private int _sliceSize;
+ private string _typeId;
+ }
+
+ private sealed class EncapsDecoder11 : EncapsDecoder
+ {
+ internal EncapsDecoder11(BasicStream stream, ReadEncaps encaps, bool sliceObjects, ObjectFactoryManager f)
+ : base(stream, encaps, sliceObjects, f)
+ {
+ _objectIdIndex = 1;
+ _current = null;
+ }
+
+ internal override void readObject(IPatcher patcher)
+ {
+ int index = _stream.readSize();
+ if(index < 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+ else if(index == 0)
+ {
+ if(patcher != null)
+ {
+ patcher.patch(null);
+ }
+ }
+ else if(_current != null && (_current.sliceFlags & FLAG_HAS_INDIRECTION_TABLE) != 0)
+ {
+ //
+ // When reading an object within a slice and there's an
+ // indirect object table, always read an indirect reference
+ // that points to an object from the indirect object table
+ // marshaled at the end of the Slice.
+ //
+ // Maintain a list of indirect references. Note that the
+ // indirect index starts at 1, so we decrement it by one to
+ // derive an index into the indirection table that we'll read
+ // at the end of the slice.
+ //
+ if(patcher != null)
+ {
+ if(_current.indirectPatchList == null)
+ {
+ _current.indirectPatchList = new Stack<IndirectPatchEntry>();
+ }
+ IndirectPatchEntry e = new IndirectPatchEntry();
+ e.index = index - 1;
+ e.patcher = patcher;
+ _current.indirectPatchList.Push(e);
+ }
+ }
+ else
+ {
+ readInstance(index, patcher);
+ }
+ }
+
+ internal override void throwException(UserExceptionFactory factory)
+ {
+ Debug.Assert(_current == null);
+
+ push(SliceType.ExceptionSlice);
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _current.typeId;
+ while(true)
+ {
+ Ice.UserException userEx = null;
+
+ //
+ // Use a factory if one was provided.
+ //
+ if(factory != null)
+ {
+ try
+ {
+ factory.createAndThrow(_current.typeId);
+ }
+ catch(Ice.UserException ex)
+ {
+ userEx = ex;
+ }
+ }
+
+ if(userEx == null)
+ {
+ userEx = _stream.createUserException(_current.typeId);
+ }
+
+ //
+ // We found the exception.
+ //
+ if(userEx != null)
+ {
+ userEx.read__(_stream);
+ throw userEx;
+
+ // Never reached.
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+
+ if((_current.sliceFlags & FLAG_IS_LAST_SLICE) != 0)
+ {
+ if(mostDerivedId.StartsWith("::", StringComparison.Ordinal))
+ {
+ throw new Ice.UnknownUserException(mostDerivedId.Substring(2));
+ }
+ else
+ {
+ throw new Ice.UnknownUserException(mostDerivedId);
+ }
+ }
+
+ startSlice();
+ }
+ }
+
+ internal override void startInstance(SliceType sliceType)
+ {
+ Debug.Assert(_current.sliceType == sliceType);
+ _current.skipFirstSlice = true;
+ }
+
+ internal override Ice.SlicedData endInstance(bool preserve)
+ {
+ Ice.SlicedData slicedData = null;
+ if(preserve)
+ {
+ slicedData = readSlicedData();
+ }
+ if(_current.slices != null)
+ {
+ _current.slices.Clear();
+ _current.indirectionTables.Clear();
+ }
+ _current = _current.previous;
+ return slicedData;
+ }
+
+ internal override string startSlice()
+ {
+ //
+ // If first slice, don't read the header, it was already read in
+ // readInstance or throwException to find the factory.
+ //
+ if(_current.skipFirstSlice)
+ {
+ _current.skipFirstSlice = false;
+ return _current.typeId;
+ }
+
+ _current.sliceFlags = _stream.readByte();
+
+ //
+ // Read the type ID, for object slices the type ID is encoded as a
+ // string or as an index, for exceptions it's always encoded as a
+ // string.
+ //
+ if(_current.sliceType == SliceType.ObjectSlice)
+ {
+ if((_current.sliceFlags & FLAG_HAS_TYPE_ID_COMPACT) == FLAG_HAS_TYPE_ID_COMPACT) // Must
+ // be
+ // checked
+ // 1st!
+ {
+ _current.typeId = "";
+ _current.compactId = _stream.readSize();
+ }
+ else if((_current.sliceFlags & (FLAG_HAS_TYPE_ID_INDEX | FLAG_HAS_TYPE_ID_STRING)) != 0)
+ {
+ _current.typeId = readTypeId((_current.sliceFlags & FLAG_HAS_TYPE_ID_INDEX) != 0);
+ _current.compactId = -1;
+ }
+ else
+ {
+ // Only the most derived slice encodes the type ID for the compact format.
+ _current.typeId = "";
+ _current.compactId = -1;
+ }
+ }
+ else
+ {
+ _current.typeId = _stream.readString();
+ _current.compactId = -1;
+ }
+
+ //
+ // Read the slice size if necessary.
+ //
+ if((_current.sliceFlags & FLAG_HAS_SLICE_SIZE) != 0)
+ {
+ _current.sliceSize = _stream.readInt();
+ if(_current.sliceSize < 4)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ }
+ else
+ {
+ _current.sliceSize = 0;
+ }
+
+ return _current.typeId;
+ }
+
+ internal override void endSlice()
+ {
+ if((_current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) != 0)
+ {
+ _stream.skipOpts();
+ }
+
+ //
+ // Read the indirection table if one is present and transform the
+ // indirect patch list into patch entries with direct references.
+ //
+ if((_current.sliceFlags & FLAG_HAS_INDIRECTION_TABLE) != 0)
+ {
+ //
+ // The table is written as a sequence<size> to conserve space.
+ //
+ int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)];
+ for(int i = 0; i < indirectionTable.Length; ++i)
+ {
+ indirectionTable[i] = readInstance(_stream.readSize(), null);
+ }
+
+ //
+ // Sanity checks. If there are optional members, it's possible
+ // that not all object references were read if they are from
+ // unknown optional data members.
+ //
+ if(indirectionTable.Length == 0)
+ {
+ throw new Ice.MarshalException("empty indirection table");
+ }
+ if((_current.indirectPatchList == null || _current.indirectPatchList.Count == 0) &&
+ (_current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) == 0)
+ {
+ throw new Ice.MarshalException("no references to indirection table");
+ }
+
+ //
+ // Convert indirect references into direct references.
+ //
+ if(_current.indirectPatchList != null)
+ {
+ foreach(IndirectPatchEntry e in _current.indirectPatchList)
+ {
+ Debug.Assert(e.index >= 0);
+ if(e.index >= indirectionTable.Length)
+ {
+ throw new Ice.MarshalException("indirection out of range");
+ }
+ addPatchEntry(indirectionTable[e.index], e.patcher);
+ }
+ _current.indirectPatchList.Clear();
+ }
+ }
+ }
+
+ internal override void skipSlice()
+ {
+ if(_stream.instance().traceLevels().slicing > 0)
+ {
+ Ice.Logger logger = _stream.instance().initializationData().logger;
+ string slicingCat = _stream.instance().traceLevels().slicingCat;
+ if(_current.sliceType == SliceType.ExceptionSlice)
+ {
+ TraceUtil.traceSlicing("exception", _current.typeId, slicingCat, logger);
+ }
+ else
+ {
+ TraceUtil.traceSlicing("object", _current.typeId, slicingCat, logger);
+ }
+ }
+
+ int start = _stream.pos();
+
+ if((_current.sliceFlags & FLAG_HAS_SLICE_SIZE) != 0)
+ {
+ Debug.Assert(_current.sliceSize >= 4);
+ _stream.skip(_current.sliceSize - 4);
+ }
+ else
+ {
+ if(_current.sliceType == SliceType.ObjectSlice)
+ {
+ throw new Ice.NoObjectFactoryException("no object factory found and compact format prevents " +
+ "slicing (the sender should use the sliced format " +
+ "instead)", _current.typeId);
+ }
+ else
+ {
+ if(_current.typeId.StartsWith("::", StringComparison.Ordinal))
+ {
+ throw new Ice.UnknownUserException(_current.typeId.Substring(2));
+ }
+ else
+ {
+ throw new Ice.UnknownUserException(_current.typeId);
+ }
+ }
+ }
+
+ //
+ // Preserve this slice.
+ //
+ Ice.SliceInfo info = new Ice.SliceInfo();
+ info.typeId = _current.typeId;
+ info.compactId = _current.compactId;
+ info.hasOptionalMembers = (_current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) != 0;
+ info.isLastSlice = (_current.sliceFlags & FLAG_IS_LAST_SLICE) != 0;
+ ByteBuffer b = _stream.getBuffer().b;
+ int end = b.position();
+ int dataEnd = end;
+ if(info.hasOptionalMembers)
+ {
+ //
+ // Don't include the optional member end marker. It will be re-written by
+ // endSlice when the sliced data is re-written.
+ //
+ --dataEnd;
+ }
+ info.bytes = new byte[dataEnd - start];
+ b.position(start);
+ b.get(info.bytes);
+ b.position(end);
+
+ if(_current.slices == null)
+ {
+ _current.slices = new List<Ice.SliceInfo>();
+ _current.indirectionTables = new List<int[]>();
+ }
+
+ //
+ // Read the indirect object table. We read the instances or their
+ // IDs if the instance is a reference to an already un-marhsaled
+ // object.
+ //
+ // The SliceInfo object sequence is initialized only if
+ // readSlicedData is called.
+ //
+ if((_current.sliceFlags & FLAG_HAS_INDIRECTION_TABLE) != 0)
+ {
+ int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)];
+ for(int i = 0; i < indirectionTable.Length; ++i)
+ {
+ indirectionTable[i] = readInstance(_stream.readSize(), null);
+ }
+ _current.indirectionTables.Add(indirectionTable);
+ }
+ else
+ {
+ _current.indirectionTables.Add(null);
+ }
+
+ _current.slices.Add(info);
+ }
+
+ internal override bool readOpt(int readTag, Ice.OptionalFormat expectedFormat)
+ {
+ if(_current == null)
+ {
+ return _stream.readOptImpl(readTag, expectedFormat);
+ }
+ else if((_current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) != 0)
+ {
+ return _stream.readOptImpl(readTag, expectedFormat);
+ }
+ return false;
+ }
+
+ private int readInstance(int index, IPatcher patcher)
+ {
+ Debug.Assert(index > 0);
+
+ if(index > 1)
+ {
+ if(patcher != null)
+ {
+ addPatchEntry(index, patcher);
+ }
+ return index;
+ }
+
+ push(SliceType.ObjectSlice);
+
+ //
+ // Get the object ID before we start reading slices. If some
+ // slices are skiped, the indirect object table are still read and
+ // might read other objects.
+ //
+ index = ++_objectIdIndex;
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ string mostDerivedId = _current.typeId;
+ Ice.Object v = null;
+ Ice.CompactIdResolver compactIdResolver = _stream.instance().initializationData().compactIdResolver;
+ while(true)
+ {
+ if(_current.compactId >= 0)
+ {
+ //
+ // Translate a compact (numeric) type ID into a string type ID.
+ //
+ _current.typeId = "";
+ if(compactIdResolver != null)
+ {
+ try
+ {
+ _current.typeId = compactIdResolver(_current.compactId);
+ }
+ catch(Ice.LocalException)
+ {
+ throw;
+ }
+ catch(System.Exception ex)
+ {
+ throw new Ice.MarshalException("exception in CompactIdResolver for ID " +
+ _current.compactId, ex);
+ }
+ }
+ if(_current.typeId.Length == 0)
+ {
+ _current.typeId = _stream.getTypeId(_current.compactId);
+ }
+ }
+
+ if(_current.typeId.Length > 0)
+ {
+ v = newInstance(_current.typeId);
+
+ //
+ // We found a factory, we get out of this loop.
+ //
+ if(v != null)
+ {
+ break;
+ }
+ }
+
+ //
+ // If object slicing is disabled, stop un-marshalling.
+ //
+ if(!_sliceObjects)
+ {
+ throw new Ice.NoObjectFactoryException("no object factory found and object slicing is disabled",
+ _current.typeId);
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+
+ //
+ // If this is the last slice, keep the object as an opaque
+ // UnknownSlicedData object.
+ //
+ if((_current.sliceFlags & FLAG_IS_LAST_SLICE) != 0)
+ {
+ //
+ // Provide a factory with an opportunity to supply the object.
+ // We pass the "::Ice::Object" ID to indicate that this is the
+ // last chance to preserve the object.
+ //
+ v = newInstance(Ice.ObjectImpl.ice_staticId());
+ if(v == null)
+ {
+ v = new Ice.UnknownSlicedObject(mostDerivedId);
+ }
+
+ break;
+ }
+
+ startSlice(); // Read next Slice header for next iteration.
+ }
+
+ //
+ // Un-marshal the object
+ //
+ unmarshal(index, v);
+
+ if(_current == null && _patchMap != null && _patchMap.Count > 0)
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw new Ice.MarshalException("index for class received, but no instance");
+ }
+
+ if(patcher != null)
+ {
+ patcher.patch(v);
+ }
+ return index;
+ }
+
+ private Ice.SlicedData readSlicedData()
+ {
+ if(_current.slices == null) // No preserved slices.
+ {
+ return null;
+ }
+
+ //
+ // The _indirectionTables member holds the indirection table for each slice
+ // in _slices.
+ //
+ Debug.Assert(_current.slices.Count == _current.indirectionTables.Count);
+ for(int n = 0; n < _current.slices.Count; ++n)
+ {
+ //
+ // We use the "objects" list in SliceInfo to hold references
+ // to the target objects. Note that the objects might not have
+ // been read yet in the case of a circular reference to an
+ // enclosing object.
+ //
+ int[] table = _current.indirectionTables[n];
+ Ice.SliceInfo info = _current.slices[n];
+ info.objects = new Ice.Object[table != null ? table.Length : 0];
+ for(int j = 0; j < info.objects.Length; ++j)
+ {
+ IPatcher patcher = new ArrayPatcher<Ice.Object>(Ice.ObjectImpl.ice_staticId(), info.objects, j);
+ addPatchEntry(table[j], patcher);
+ }
+ }
+
+ return new Ice.SlicedData(_current.slices.ToArray());
+ }
+
+ private void push(SliceType sliceType)
+ {
+ if(_current == null)
+ {
+ _current = new InstanceData(null);
+ }
+ else
+ {
+ _current = _current.next == null ? new InstanceData(_current) : _current.next;
+ }
+ _current.sliceType = sliceType;
+ _current.skipFirstSlice = false;
+ }
+
+ private sealed class IndirectPatchEntry
+ {
+ public int index;
+ public IPatcher patcher;
+ }
+
+ private sealed class InstanceData
+ {
+ internal InstanceData(InstanceData previous)
+ {
+ if(previous != null)
+ {
+ previous.next = this;
+ }
+ this.previous = previous;
+ this.next = null;
+ }
+
+ // Instance attributes
+ internal SliceType sliceType;
+ internal bool skipFirstSlice;
+ internal List<Ice.SliceInfo> slices; // Preserved slices.
+ internal List<int[]> indirectionTables;
+
+ // Slice attributes
+ internal byte sliceFlags;
+ internal int sliceSize;
+ internal string typeId;
+ internal int compactId;
+ internal Stack<IndirectPatchEntry> indirectPatchList;
+
+ internal InstanceData previous;
+ internal InstanceData next;
+ };
+ private InstanceData _current;
+
+ private int _objectIdIndex; // The ID of the next object to un-marshal.
+ };
+
+ abstract private class EncapsEncoder
+ {
+ protected EncapsEncoder(BasicStream stream, WriteEncaps encaps)
+ {
+ _stream = stream;
+ _encaps = encaps;
+ _typeIdIndex = 0;
+ _marshaledMap = new Dictionary<Ice.Object, int>();
+ }
+
+ internal abstract void writeObject(Ice.Object v);
+ internal abstract void writeUserException(Ice.UserException v);
+
+ internal abstract void startInstance(SliceType type, Ice.SlicedData data);
+ internal abstract void endInstance();
+ internal abstract void startSlice(string typeId, int compactId, bool last);
+ internal abstract void endSlice();
+
+ internal virtual bool writeOpt(int tag, Ice.OptionalFormat format)
+ {
+ return false;
+ }
+
+ internal virtual void writePendingObjects()
+ {
+ }
+
+ protected int registerTypeId(string typeId)
+ {
+ if(_typeIdMap == null)
+ {
+ _typeIdMap = new Dictionary<string, int>();
+ }
+
+ int p;
+ if(_typeIdMap.TryGetValue(typeId, out p))
+ {
+ return p;
+ }
+ else
+ {
+ _typeIdMap.Add(typeId, ++_typeIdIndex);
+ return -1;
+ }
+ }
+
+ protected readonly BasicStream _stream;
+ protected readonly WriteEncaps _encaps;
+
+ // Encapsulation attributes for object marshalling.
+ protected readonly Dictionary<Ice.Object, int> _marshaledMap;
+
+ // Encapsulation attributes for object marshalling.
+ private Dictionary<string, int> _typeIdMap;
+ private int _typeIdIndex;
+ };
+
+ private sealed class EncapsEncoder10 : EncapsEncoder
+ {
+ internal EncapsEncoder10(BasicStream stream, WriteEncaps encaps) : base(stream, encaps)
+ {
+ _sliceType = SliceType.NoSlice;
+ _objectIdIndex = 0;
+ _toBeMarshaledMap = new Dictionary<Ice.Object, int>();
+ }
+
+ internal override void writeObject(Ice.Object v)
+ {
+ //
+ // Object references are encoded as a negative integer in 1.0.
+ //
+ if(v != null)
+ {
+ _stream.writeInt(-registerObject(v));
+ }
+ else
+ {
+ _stream.writeInt(0);
+ }
+ }
+
+ internal override void writeUserException(Ice.UserException v)
+ {
+ //
+ // User exception with the 1.0 encoding start with a bool
+ // flag that indicates whether or not the exception uses
+ // classes.
+ //
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
+ //
+ bool usesClasses = v.usesClasses__();
+ _stream.writeBool(usesClasses);
+ v.write__(_stream);
+ if(usesClasses)
+ {
+ writePendingObjects();
+ }
+ }
+
+ internal override void startInstance(SliceType sliceType, Ice.SlicedData sliceData)
+ {
+ _sliceType = sliceType;
+ }
+
+ internal override void endInstance()
+ {
+ if(_sliceType == SliceType.ObjectSlice)
+ {
+ //
+ // Write the Object slice.
+ //
+ startSlice(Ice.ObjectImpl.ice_staticId(), -1, true);
+ _stream.writeSize(0); // For compatibility with the old AFM.
+ endSlice();
+ }
+ _sliceType = SliceType.NoSlice;
+ }
+
+ internal override void startSlice(string typeId, int compactId, bool last)
+ {
+ //
+ // For object slices, encode a bool to indicate how the type ID
+ // is encoded and the type ID either as a string or index. For
+ // exception slices, always encode the type ID as a string.
+ //
+ if(_sliceType == SliceType.ObjectSlice)
+ {
+ int index = registerTypeId(typeId);
+ if(index < 0)
+ {
+ _stream.writeBool(false);
+ _stream.writeString(typeId);
+ }
+ else
+ {
+ _stream.writeBool(true);
+ _stream.writeSize(index);
+ }
+ }
+ else
+ {
+ _stream.writeString(typeId);
+ }
+
+ _stream.writeInt(0); // Placeholder for the slice length.
+
+ _writeSlice = _stream.pos();
+ }
+
+ internal override void endSlice()
+ {
+ //
+ // Write the slice length.
+ //
+ int sz = _stream.pos() - _writeSlice + 4;
+ _stream.rewriteInt(sz, _writeSlice - 4);
+ }
+
+ internal override void writePendingObjects()
+ {
+ while(_toBeMarshaledMap.Count > 0)
+ {
+ //
+ // Consider the to be marshalled objects as marshalled now,
+ // this is necessary to avoid adding again the "to be
+ // marshalled objects" into _toBeMarshaledMap while writing
+ // objects.
+ //
+ foreach(KeyValuePair<Ice.Object, int> e in _toBeMarshaledMap)
+ {
+ _marshaledMap.Add(e.Key, e.Value);
+ }
+
+ Dictionary<Ice.Object, int> savedMap = _toBeMarshaledMap;
+ _toBeMarshaledMap = new Dictionary<Ice.Object, int>();
+ _stream.writeSize(savedMap.Count);
+ foreach(KeyValuePair<Ice.Object, int> p in savedMap)
+ {
+ //
+ // Ask the instance to marshal itself. Any new class
+ // instances that are triggered by the classes marshaled
+ // are added to toBeMarshaledMap.
+ //
+ _stream.writeInt(p.Value);
+
+ try
+ {
+ p.Key.ice_preMarshal();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception raised by ice_preMarshal:\n" + ex;
+ _stream.instance().initializationData().logger.warning(s);
+ }
+
+ p.Key.write__(_stream);
+ }
+ }
+ _stream.writeSize(0); // Zero marker indicates end of sequence of sequences of instances.
+ }
+
+ private int registerObject(Ice.Object v)
+ {
+ Debug.Assert(v != null);
+
+ //
+ // Look for this instance in the to-be-marshaled map.
+ //
+ int p;
+ if(_toBeMarshaledMap.TryGetValue(v, out p))
+ {
+ return p;
+ }
+
+ //
+ // Didn't find it, try the marshaled map next.
+ //
+ if(_marshaledMap.TryGetValue(v, out p))
+ {
+ return p;
+ }
+
+ //
+ // We haven't seen this instance previously, create a new
+ // index, and insert it into the to-be-marshaled map.
+ //
+ _toBeMarshaledMap.Add(v, ++_objectIdIndex);
+ return _objectIdIndex;
+ }
+
+ // Instance attributes
+ private SliceType _sliceType;
+
+ // Slice attributes
+ private int _writeSlice; // Position of the slice data members
+
+ // Encapsulation attributes for object marshalling.
+ private int _objectIdIndex;
+ private Dictionary<Ice.Object, int> _toBeMarshaledMap;
+ };
+
+ private sealed class EncapsEncoder11 : EncapsEncoder
+ {
+ internal EncapsEncoder11(BasicStream stream, WriteEncaps encaps) : base(stream, encaps)
+ {
+ _current = null;
+ _objectIdIndex = 1;
+ }
+
+ internal override void writeObject(Ice.Object v)
+ {
+ if(v == null)
+ {
+ _stream.writeSize(0);
+ }
+ else if(_current != null && _encaps.format == Ice.FormatType.SlicedFormat)
+ {
+ if(_current.indirectionTable == null)
+ {
+ _current.indirectionTable = new List<Ice.Object>();
+ _current.indirectionMap = new Dictionary<Ice.Object, int>();
+ }
+
+ //
+ // If writting an object within a slice and using the sliced
+ // format, write an index from the object indirection table.
+ //
+ int index;
+ if(!_current.indirectionMap.TryGetValue(v, out index))
+ {
+ _current.indirectionTable.Add(v);
+ int idx = _current.indirectionTable.Count; // Position + 1 (0 is reserved for nil)
+ _current.indirectionMap.Add(v, idx);
+ _stream.writeSize(idx);
+ }
+ else
+ {
+ _stream.writeSize(index);
+ }
+ }
+ else
+ {
+ writeInstance(v); // Write the instance or a reference if already marshaled.
+ }
+ }
+
+ internal override void writeUserException(Ice.UserException v)
+ {
+ v.write__(_stream);
+ }
+
+ internal override void startInstance(SliceType sliceType, Ice.SlicedData data)
+ {
+ if(_current == null)
+ {
+ _current = new InstanceData(null);
+ }
+ else
+ {
+ _current = _current.next == null ? new InstanceData(_current) : _current.next;
+ }
+ _current.sliceType = sliceType;
+ _current.firstSlice = true;
+
+ if(data != null)
+ {
+ writeSlicedData(data);
+ }
+ }
+
+ internal override void endInstance()
+ {
+ _current = _current.previous;
+ }
+
+ internal override void startSlice(string typeId, int compactId, bool last)
+ {
+ Debug.Assert((_current.indirectionTable == null || _current.indirectionTable.Count == 0) &&
+ (_current.indirectionMap == null || _current.indirectionMap.Count == 0));
+
+ _current.sliceFlagsPos = _stream.pos();
+
+ _current.sliceFlags = (byte)0;
+ if(_encaps.format == Ice.FormatType.SlicedFormat)
+ {
+ _current.sliceFlags |= FLAG_HAS_SLICE_SIZE; // Encode the slice size if using the sliced format.
+ }
+ if(last)
+ {
+ _current.sliceFlags |= FLAG_IS_LAST_SLICE; // This is the last slice.
+ }
+
+ _stream.writeByte((byte)0); // Placeholder for the slice flags
+
+ //
+ // For object slices, encode the flag and the type ID either as a
+ // string or index. For exception slices, always encode the type
+ // ID a string.
+ //
+ if(_current.sliceType == SliceType.ObjectSlice)
+ {
+ //
+ // Encode the type ID (only in the first slice for the compact
+ // encoding).
+ //
+ if(_encaps.format == Ice.FormatType.SlicedFormat || _current.firstSlice)
+ {
+ if(compactId >= 0)
+ {
+ _current.sliceFlags |= FLAG_HAS_TYPE_ID_COMPACT;
+ _stream.writeSize(compactId);
+ }
+ else
+ {
+ int index = registerTypeId(typeId);
+ if(index < 0)
+ {
+ _current.sliceFlags |= FLAG_HAS_TYPE_ID_STRING;
+ _stream.writeString(typeId);
+ }
+ else
+ {
+ _current.sliceFlags |= FLAG_HAS_TYPE_ID_INDEX;
+ _stream.writeSize(index);
+ }
+ }
+ }
+ }
+ else
+ {
+ _stream.writeString(typeId);
+ }
+
+ if((_current.sliceFlags & FLAG_HAS_SLICE_SIZE) != 0)
+ {
+ _stream.writeInt(0); // Placeholder for the slice length.
+ }
+
+ _current.writeSlice = _stream.pos();
+ _current.firstSlice = false;
+ }
+
+ internal override void endSlice()
+ {
+ //
+ // Write the optional member end marker if some optional members
+ // were encoded. Note that the optional members are encoded before
+ // the indirection table and are included in the slice size.
+ //
+ if((_current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) != 0)
+ {
+ _stream.writeByte((byte)OPTIONAL_END_MARKER);
+ }
+
+ //
+ // Write the slice length if necessary.
+ //
+ if((_current.sliceFlags & FLAG_HAS_SLICE_SIZE) != 0)
+ {
+ int sz = _stream.pos() - _current.writeSlice + 4;
+ _stream.rewriteInt(sz, _current.writeSlice - 4);
+ }
+
+ //
+ // Only write the indirection table if it contains entries.
+ //
+ if(_current.indirectionTable != null && _current.indirectionTable.Count > 0)
+ {
+ Debug.Assert(_encaps.format == Ice.FormatType.SlicedFormat);
+ _current.sliceFlags |= FLAG_HAS_INDIRECTION_TABLE;
+
+ //
+ // Write the indirection object table.
+ //
+ _stream.writeSize(_current.indirectionTable.Count);
+ foreach(Ice.Object v in _current.indirectionTable)
+ {
+ writeInstance(v);
+ }
+ _current.indirectionTable.Clear();
+ _current.indirectionMap.Clear();
+ }
+
+ //
+ // Finally, update the slice flags.
+ //
+ _stream.rewriteByte(_current.sliceFlags, _current.sliceFlagsPos);
+ }
+
+ internal override bool writeOpt(int tag, Ice.OptionalFormat format)
+ {
+ if(_current == null)
+ {
+ return _stream.writeOptImpl(tag, format);
+ }
+ else
+ {
+ if(_stream.writeOptImpl(tag, format))
+ {
+ _current.sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ private void writeSlicedData(Ice.SlicedData slicedData)
+ {
+ Debug.Assert(slicedData != null);
+
+ //
+ // We only remarshal preserved slices if we are using the sliced
+ // format. Otherwise, we ignore the preserved slices, which
+ // essentially "slices" the object into the most-derived type
+ // known by the sender.
+ //
+ if(_encaps.format != Ice.FormatType.SlicedFormat)
+ {
+ return;
+ }
+
+ foreach(Ice.SliceInfo info in slicedData.slices)
+ {
+ startSlice(info.typeId, info.compactId, info.isLastSlice);
+
+ //
+ // Write the bytes associated with this slice.
+ //
+ _stream.writeBlob(info.bytes);
+
+ if(info.hasOptionalMembers)
+ {
+ _current.sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ }
+
+ //
+ // Make sure to also re-write the object indirection table.
+ //
+ if(info.objects != null && info.objects.Length > 0)
+ {
+ if(_current.indirectionTable == null)
+ {
+ _current.indirectionTable = new List<Ice.Object>();
+ _current.indirectionMap = new Dictionary<Ice.Object, int>();
+ }
+ foreach(Ice.Object o in info.objects)
+ {
+ _current.indirectionTable.Add(o);
+ }
+ }
+
+ endSlice();
+ }
+ }
+
+ private void writeInstance(Ice.Object v)
+ {
+ Debug.Assert(v != null);
+
+ //
+ // If the instance was already marshaled, just write it's ID.
+ //
+ int p;
+ if(_marshaledMap.TryGetValue(v, out p))
+ {
+ _stream.writeSize(p);
+ return;
+ }
+
+ //
+ // We haven't seen this instance previously, create a new ID,
+ // insert it into the marshaled map, and write the instance.
+ //
+ _marshaledMap.Add(v, ++_objectIdIndex);
+
+ try
+ {
+ v.ice_preMarshal();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception raised by ice_preMarshal:\n" + ex;
+ _stream.instance().initializationData().logger.warning(s);
+ }
+
+ _stream.writeSize(1); // Object instance marker.
+ v.write__(_stream);
+ }
+
+ private sealed class InstanceData
+ {
+ internal InstanceData(InstanceData previous)
+ {
+ if(previous != null)
+ {
+ previous.next = this;
+ }
+ this.previous = previous;
+ this.next = null;
+ }
+
+ // Instance attributes
+ internal SliceType sliceType;
+ internal bool firstSlice;
+
+ // Slice attributes
+ internal byte sliceFlags;
+ internal int writeSlice; // Position of the slice data members
+ internal int sliceFlagsPos; // Position of the slice flags
+ internal List<Ice.Object> indirectionTable;
+ internal Dictionary<Ice.Object, int> indirectionMap;
+
+ internal InstanceData previous;
+ internal InstanceData next;
+ };
+ private InstanceData _current;
+
+ private int _objectIdIndex; // The ID of the next object to marhsal
+ };
+
+ private sealed class ReadEncaps
+ {
+ internal void reset()
+ {
+ decoder = null;
+ }
+
+ internal void setEncoding(Ice.EncodingVersion encoding)
+ {
+ this.encoding = encoding;
+ encoding_1_0 = encoding.Equals(Ice.Util.Encoding_1_0);
+ }
+
+ internal int start;
+ internal int sz;
+ internal Ice.EncodingVersion encoding;
+ internal bool encoding_1_0;
+
+ internal EncapsDecoder decoder;
+
+ internal ReadEncaps next;
+ }
+
+ private sealed class WriteEncaps
+ {
+ internal void reset()
+ {
+ encoder = null;
+ }
+
+ internal void setEncoding(Ice.EncodingVersion encoding)
+ {
+ this.encoding = encoding;
+ encoding_1_0 = encoding.Equals(Ice.Util.Encoding_1_0);
+ }
+
+ internal int start;
+ internal Ice.EncodingVersion encoding;
+ internal bool encoding_1_0;
+ internal Ice.FormatType format = Ice.FormatType.DefaultFormat;
+
+ internal EncapsEncoder encoder;
+
+ internal WriteEncaps next;
+ }
+
+ //
+ // The encoding version to use when there's no encapsulation to
+ // read from or write to. This is for example used to read message
+ // headers or when the user is using the streaming API with no
+ // encapsulation.
+ //
+ private Ice.EncodingVersion _encoding;
+
+ private bool isReadEncoding_1_0()
+ {
+ return _readEncapsStack != null ? _readEncapsStack.encoding_1_0 : _encoding.Equals(Ice.Util.Encoding_1_0);
+ }
+
+ private bool isWriteEncoding_1_0()
+ {
+ return _writeEncapsStack != null ? _writeEncapsStack.encoding_1_0 : _encoding.Equals(Ice.Util.Encoding_1_0);
+ }
+
+ private ReadEncaps _readEncapsStack;
+ private WriteEncaps _writeEncapsStack;
+ private ReadEncaps _readEncapsCache;
+ private WriteEncaps _writeEncapsCache;
+
+ private void initReadEncaps()
+ {
+ if(_readEncapsStack == null) // Lazy initialization
+ {
+ _readEncapsStack = _readEncapsCache;
+ if(_readEncapsStack != null)
+ {
+ _readEncapsCache = _readEncapsCache.next;
+ }
+ else
+ {
+ _readEncapsStack = new ReadEncaps();
+ }
+ _readEncapsStack.setEncoding(_encoding);
+ _readEncapsStack.sz = _buf.b.limit();
+ }
+
+ if(_readEncapsStack.decoder == null) // Lazy initialization.
+ {
+ ObjectFactoryManager factoryMgr = instance_.servantFactoryManager();
+ if(_readEncapsStack.encoding_1_0)
+ {
+ _readEncapsStack.decoder = new EncapsDecoder10(this, _readEncapsStack, _sliceObjects, factoryMgr);
+ }
+ else
+ {
+ _readEncapsStack.decoder = new EncapsDecoder11(this, _readEncapsStack, _sliceObjects, factoryMgr);
+ };
+ }
+ }
+
+ private void initWriteEncaps()
+ {
+ if(_writeEncapsStack == null) // Lazy initialization
+ {
+ _writeEncapsStack = _writeEncapsCache;
+ if(_writeEncapsStack != null)
+ {
+ _writeEncapsCache = _writeEncapsCache.next;
+ }
+ else
+ {
+ _writeEncapsStack = new WriteEncaps();
+ }
+ _writeEncapsStack.setEncoding(_encoding);
+ }
+
+ if(_writeEncapsStack.format == Ice.FormatType.DefaultFormat)
+ {
+ _writeEncapsStack.format = instance_.defaultsAndOverrides().defaultFormat;
+ }
+
+ if(_writeEncapsStack.encoder == null) // Lazy initialization.
+ {
+ if(_writeEncapsStack.encoding_1_0)
+ {
+ _writeEncapsStack.encoder = new EncapsEncoder10(this, _writeEncapsStack);
+ }
+ else
+ {
+ _writeEncapsStack.encoder = new EncapsEncoder11(this, _writeEncapsStack);
+ }
+ }
+ }
+
+ private bool _sliceObjects;
+
+ private int _startSeq;
+ private int _minSeqSize;
+
+ private const byte OPTIONAL_END_MARKER = 0xFF;
+
+ private const byte FLAG_HAS_TYPE_ID_STRING = (byte)(1<<0);
+ private const byte FLAG_HAS_TYPE_ID_INDEX = (byte)(1<<1);
+ private const byte FLAG_HAS_TYPE_ID_COMPACT = (byte)(1<<1 | 1<<0);
+ private const byte FLAG_HAS_OPTIONAL_MEMBERS = (byte)(1<<2);
+ private const byte FLAG_HAS_INDIRECTION_TABLE = (byte)(1<<3);
+ private const byte FLAG_HAS_SLICE_SIZE = (byte)(1<<4);
+ private const byte FLAG_IS_LAST_SLICE = (byte)(1<<5);
+
+ private static bool _bzlibInstalled;
+
+ const int BZ_SEQUENCE_ERROR = -1;
+ const int BZ_PARAM_ERROR = -2;
+ const int BZ_MEM_ERROR = -3;
+ const int BZ_DATA_ERROR = -4;
+ const int BZ_DATA_ERROR_MAGIC = -5;
+ const int BZ_IO_ERROR = -6;
+ const int BZ_UNEXPECTED_EOF = -7;
+ const int BZ_OUTBUFF_FULL = -8;
+ const int BZ_CONFIG_ERROR = -9;
+ }
+
+}
diff --git a/csharp/src/Ice/BatchRequestInterceptor.cs b/csharp/src/Ice/BatchRequestInterceptor.cs
new file mode 100644
index 00000000000..7cd79d63991
--- /dev/null
+++ b/csharp/src/Ice/BatchRequestInterceptor.cs
@@ -0,0 +1,57 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ public interface BatchRequest
+ {
+ /// <summary>
+ /// Confirms the queuing of the batch request.
+ /// </summary>
+ void enqueue();
+
+ /// <summary>
+ /// Get the marshalled size of the request.
+ /// </summary>
+ /// <returns>The request size.</returns>
+ int getSize();
+
+ /// <summary>
+ /// Get the name of the operation
+ /// </summary>
+ /// <returns>The request operation.</returns>
+ string getOperation();
+
+ /// <summary>
+ /// The proxy used to invoke the batch request.
+ /// </summary>
+ /// <returns>The request proxy.</returns>
+ Ice.ObjectPrx getProxy();
+ };
+
+ /// <summary>
+ /// Base interface for listening to batch request queues.
+ /// </summary>
+ public interface BatchRequestInterceptor
+ {
+ /// <summary>
+ /// Called by the Ice runtime when a batch request is about to be
+ /// added to the batch request queue of a proxy or connection.
+ ///
+ /// The implementation of this method must call enqueue() on the
+ /// request to confirm its addition to the queue, if not called
+ /// the request isn't added to the queue. The implementation can
+ /// raise an Ice local exception to notify the caller of a failure.
+ /// </summary>
+ /// <param name="request">The batch request.</param>
+ /// <param name="queueBatchRequestCount">The number of batch request queued.</param>
+ /// <param name="queueBatchRequestSize">The size of the queued batch requests.</param>
+ void enqueue(Ice.BatchRequest request, int queueBatchRequestCount, int queueBatchRequestSize);
+ };
+};
diff --git a/csharp/src/Ice/BatchRequestQueue.cs b/csharp/src/Ice/BatchRequestQueue.cs
new file mode 100644
index 00000000000..2973c6fae12
--- /dev/null
+++ b/csharp/src/Ice/BatchRequestQueue.cs
@@ -0,0 +1,244 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Diagnostics;
+
+namespace IceInternal
+{
+ sealed class BatchRequestI : Ice.BatchRequest
+ {
+ public BatchRequestI(BatchRequestQueue queue)
+ {
+ _queue = queue;
+ }
+
+ public void reset(Ice.ObjectPrx proxy, string operation, int size)
+ {
+ _proxy = proxy;
+ _operation = operation;
+ _size = size;
+ }
+
+ public void enqueue()
+ {
+ _queue.enqueueBatchRequest();
+ }
+
+ public Ice.ObjectPrx getProxy()
+ {
+ return _proxy;
+ }
+
+ public string getOperation()
+ {
+ return _operation;
+ }
+
+ public int getSize()
+ {
+ return _size;
+ }
+
+ private BatchRequestQueue _queue;
+ private Ice.ObjectPrx _proxy;
+ private string _operation;
+ private int _size;
+ };
+
+
+ public sealed class BatchRequestQueue
+ {
+ public BatchRequestQueue(Instance instance, bool datagram)
+ {
+ Ice.InitializationData initData = instance.initializationData();
+ _interceptor = initData.batchRequestInterceptor;
+ _batchStreamInUse = false;
+ _batchRequestNum = 0;
+ _batchStream = new BasicStream(instance, Ice.Util.currentProtocolEncoding);
+ _batchStream.writeBlob(Protocol.requestBatchHdr);
+ _batchMarker = _batchStream.size();
+ _request = new BatchRequestI(this);
+
+ _maxSize = instance.batchAutoFlushSize();
+ if(_maxSize > 0 && datagram)
+ {
+ int udpSndSize = initData.properties.getPropertyAsIntWithDefault("Ice.UDP.SndSize",
+ 65535 - _udpOverhead);
+ if(udpSndSize < _maxSize)
+ {
+ _maxSize = udpSndSize;
+ }
+ }
+ }
+
+ public void
+ prepareBatchRequest(BasicStream os)
+ {
+ lock(this)
+ {
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ waitStreamInUse(false);
+ _batchStreamInUse = true;
+ _batchStream.swap(os);
+ }
+ }
+
+ public void
+ finishBatchRequest(BasicStream os, Ice.ObjectPrx proxy, string operation)
+ {
+ //
+ // No need for synchronization, no other threads are supposed
+ // to modify the queue since we set _batchStreamInUse to true.
+ //
+ Debug.Assert(_batchStreamInUse);
+ _batchStream.swap(os);
+
+ try
+ {
+ _batchStreamCanFlush = true; // Allow flush to proceed even if the stream is marked in use.
+
+ if(_maxSize > 0 && _batchStream.size() >= _maxSize)
+ {
+ proxy.begin_ice_flushBatchRequests(); // Auto flush
+ }
+
+ Debug.Assert(_batchMarker < _batchStream.size());
+ if(_interceptor != null)
+ {
+ _request.reset(proxy, operation, _batchStream.size() - _batchMarker);
+ _interceptor.enqueue(_request, _batchRequestNum, _batchMarker);
+ }
+ else
+ {
+ _batchMarker = _batchStream.size();
+ ++_batchRequestNum;
+ }
+ }
+ finally
+ {
+ lock(this)
+ {
+ _batchStream.resize(_batchMarker, false);
+ _batchStreamInUse = false;
+ _batchStreamCanFlush = false;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+ }
+
+ public void
+ abortBatchRequest(BasicStream os)
+ {
+ lock(this)
+ {
+ if(_batchStreamInUse)
+ {
+ _batchStream.swap(os);
+ _batchStream.resize(_batchMarker, false);
+ _batchStreamInUse = false;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+ }
+
+ public int
+ swap(BasicStream os)
+ {
+ lock(this)
+ {
+ if(_batchRequestNum == 0)
+ {
+ return 0;
+ }
+
+ waitStreamInUse(true);
+
+ byte[] lastRequest = null;
+ if(_batchMarker < _batchStream.size())
+ {
+ lastRequest = new byte[_batchStream.size() - _batchMarker];
+ Buffer buffer = _batchStream.getBuffer();
+ buffer.b.position(_batchMarker);
+ buffer.b.get(lastRequest);
+ _batchStream.resize(_batchMarker, false);
+ }
+
+ int requestNum = _batchRequestNum;
+ _batchStream.swap(os);
+
+ //
+ // Reset the batch.
+ //
+ _batchRequestNum = 0;
+ _batchStream.writeBlob(Protocol.requestBatchHdr);
+ _batchMarker = _batchStream.size();
+ if(lastRequest != null)
+ {
+ _batchStream.writeBlob(lastRequest);
+ }
+ return requestNum;
+ }
+ }
+
+ public void
+ destroy(Ice.LocalException ex)
+ {
+ lock(this)
+ {
+ _exception = ex;
+ }
+ }
+
+ public bool
+ isEmpty()
+ {
+ lock(this)
+ {
+ return _batchStream.size() == Protocol.requestBatchHdr.Length;
+ }
+ }
+
+ private void
+ waitStreamInUse(bool flush)
+ {
+ //
+ // This is similar to a mutex lock in that the stream is
+ // only "locked" while marshaling. As such we don't permit the wait
+ // to be interrupted. Instead the interrupted status is saved and
+ // restored.
+ //
+ while(_batchStreamInUse && !(flush && _batchStreamCanFlush))
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ }
+
+ internal void enqueueBatchRequest()
+ {
+ Debug.Assert(_batchMarker < _batchStream.size());
+ _batchMarker = _batchStream.size();
+ ++_batchRequestNum;
+ }
+
+ private Ice.BatchRequestInterceptor _interceptor;
+ private BasicStream _batchStream;
+ private bool _batchStreamInUse;
+ private bool _batchStreamCanFlush;
+ private int _batchRequestNum;
+ private int _batchMarker;
+ private BatchRequestI _request;
+ private Ice.LocalException _exception;
+ private int _maxSize;
+
+ private static int _udpOverhead = 20 + 8;
+ }
+};
diff --git a/csharp/src/Ice/Buffer.cs b/csharp/src/Ice/Buffer.cs
new file mode 100644
index 00000000000..c0d1747a103
--- /dev/null
+++ b/csharp/src/Ice/Buffer.cs
@@ -0,0 +1,195 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Diagnostics;
+
+ //
+ // An instance of ByteBuffer cannot grow beyond its initial capacity.
+ // This class wraps a ByteBuffer and supports reallocation.
+ //
+ public class Buffer
+ {
+ public Buffer() : this(ByteBuffer.ByteOrder.LITTLE_ENDIAN)
+ {
+ }
+
+ public Buffer(ByteBuffer.ByteOrder order)
+ {
+ b = _emptyBuffer;
+ _size = 0;
+ _capacity = 0;
+ _order = order;
+ }
+
+ public Buffer(byte[] data) : this(data, ByteBuffer.ByteOrder.LITTLE_ENDIAN)
+ {
+ }
+
+ public Buffer(byte[] data, ByteBuffer.ByteOrder order)
+ {
+ b = ByteBuffer.wrap(data);
+ b.order(order);
+ _size = data.Length;
+ _capacity = 0;
+ _order = order;
+ }
+
+ public int size()
+ {
+ return _size;
+ }
+
+ public bool empty()
+ {
+ return _size == 0;
+ }
+
+ public void clear()
+ {
+ b = _emptyBuffer;
+ _size = 0;
+ _capacity = 0;
+ }
+
+ //
+ // Call expand(n) to add room for n additional bytes. Note that expand()
+ // examines the current position of the buffer first; we don't want to
+ // expand the buffer if the caller is writing to a location that is
+ // already in the buffer.
+ //
+ public void expand(int n)
+ {
+ int sz = (b == _emptyBuffer) ? n : b.position() + n;
+ if(sz > _size)
+ {
+ resize(sz, false);
+ }
+ }
+
+ public void resize(int n, bool reading)
+ {
+ Debug.Assert(b == _emptyBuffer || _capacity > 0);
+
+ if(n == 0)
+ {
+ clear();
+ }
+ else if(n > _capacity)
+ {
+ reserve(n);
+ }
+ _size = n;
+
+ //
+ // When used for reading, we want to set the buffer's limit to the new size.
+ //
+ if(reading)
+ {
+ b.limit(_size);
+ }
+ }
+
+ public void reset()
+ {
+ if(_size > 0 && _size * 2 < _capacity)
+ {
+ //
+ // If the current buffer size is smaller than the
+ // buffer capacity, we shrink the buffer memory to the
+ // current size. This is to avoid holding on to too much
+ // memory if it's not needed anymore.
+ //
+ if(++_shrinkCounter > 2)
+ {
+ reserve(_size);
+ _shrinkCounter = 0;
+ }
+ }
+ else
+ {
+ _shrinkCounter = 0;
+ }
+ _size = 0;
+ if(b != _emptyBuffer)
+ {
+ b.limit(b.capacity());
+ b.position(0);
+ }
+ }
+
+ private void reserve(int n)
+ {
+ Debug.Assert(_capacity == b.capacity());
+
+ if(n > _capacity)
+ {
+ _capacity = System.Math.Max(n, 2 * _capacity);
+ _capacity = System.Math.Max(240, _capacity);
+ }
+ else if(n < _capacity)
+ {
+ _capacity = n;
+ }
+ else
+ {
+ return;
+ }
+
+ try
+ {
+ ByteBuffer buf = ByteBuffer.allocate(_capacity);
+
+ if(b == _emptyBuffer)
+ {
+ b = buf;
+ }
+ else
+ {
+ int pos = b.position();
+ b.position(0);
+ b.limit(System.Math.Min(_capacity, b.capacity()));
+ buf.put(b);
+ b = buf;
+ b.limit(b.capacity());
+ b.position(pos);
+ }
+
+ b.order(_order);
+ }
+ catch(System.OutOfMemoryException)
+ {
+ _capacity = b.capacity(); // Restore the previous capacity
+ throw;
+ }
+ catch(System.Exception ex)
+ {
+ _capacity = b.capacity(); // Restore the previous capacity.
+ Ice.MarshalException e = new Ice.MarshalException(ex);
+ e.reason = "unexpected exception while trying to allocate a ByteBuffer:\n" + ex;
+ throw e;
+ }
+ finally
+ {
+ Debug.Assert(_capacity == b.capacity());
+ }
+ }
+
+ public ByteBuffer b;
+ // Sentinel used for null buffer.
+ static private ByteBuffer _emptyBuffer = new ByteBuffer();
+
+ private int _size;
+ private int _capacity; // Cache capacity to avoid excessive method calls.
+ private int _shrinkCounter;
+ private ByteBuffer.ByteOrder _order;
+ }
+
+}
diff --git a/csharp/src/Ice/ByteBuffer.cs b/csharp/src/Ice/ByteBuffer.cs
new file mode 100644
index 00000000000..a736c01679d
--- /dev/null
+++ b/csharp/src/Ice/ByteBuffer.cs
@@ -0,0 +1,999 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace IceInternal
+{
+ public class ByteBuffer
+ {
+
+ public ByteBuffer()
+ {
+ _order = ByteOrder.BIG_ENDIAN;
+ }
+
+ public enum ByteOrder { BIG_ENDIAN, LITTLE_ENDIAN };
+
+ public static ByteOrder nativeOrder()
+ {
+ return NO._o;
+ }
+
+ public ByteOrder order()
+ {
+ return _order;
+ }
+
+ public ByteBuffer order(ByteOrder bo)
+ {
+ _order = bo;
+ return this;
+ }
+
+ public static ByteBuffer allocate(int capacity)
+ {
+ if(capacity < 0)
+ {
+ throwOutOfRange("capacity", capacity, "capacity must be non-negative");
+ }
+ ByteBuffer ret = new ByteBuffer();
+ ret._position = 0;
+ ret._limit = capacity;
+ ret._capacity = capacity;
+ ret._bytes = new byte[capacity];
+ ret._valBytes = new ValBytes();
+ return ret;
+ }
+
+ public static ByteBuffer wrap(byte[] bytes)
+ {
+ ByteBuffer ret = new ByteBuffer();
+ ret._position = 0;
+ ret._limit = bytes.Length;
+ ret._capacity = bytes.Length;
+ ret._bytes = bytes;
+ ret._valBytes = new ValBytes();
+ return ret;
+ }
+
+ public int position()
+ {
+ return _position;
+ }
+
+ public ByteBuffer position(int pos)
+ {
+ if(pos < 0)
+ {
+ throwOutOfRange("pos", pos, "position must be non-negative");
+ }
+ if(pos > _limit)
+ {
+ throwOutOfRange("pos", pos, "position must be less than limit");
+ }
+ _position = pos;
+ return this;
+ }
+
+ public int limit()
+ {
+ return _limit;
+ }
+
+ public ByteBuffer limit(int newLimit)
+ {
+ if(newLimit < 0)
+ {
+ throwOutOfRange("newLimit", newLimit, "limit must be non-negative");
+ }
+ if(newLimit > _capacity)
+ {
+ throwOutOfRange("newLimit", newLimit, "limit must be less than capacity");
+ }
+ _limit = newLimit;
+ return this;
+ }
+
+ public void clear()
+ {
+ _position = 0;
+ _limit = _capacity;
+ }
+
+ public void flip()
+ {
+ _limit = _position;
+ _position = 0;
+ }
+
+ public void compact()
+ {
+ if(_position < _limit)
+ {
+ int n = _limit - _position;
+ System.Buffer.BlockCopy(_bytes, _position, _bytes, 0, n);
+ _position = n;
+ }
+ else
+ {
+ _position = 0;
+ }
+ _limit = _capacity;
+ }
+
+ public int remaining()
+ {
+ return _limit - _position;
+ }
+
+ public bool hasRemaining()
+ {
+ return _position < _limit;
+ }
+
+ public int capacity()
+ {
+ return _capacity;
+ }
+
+ public byte[] toArray()
+ {
+ int len = remaining();
+ byte[] rc = new byte[len];
+ System.Buffer.BlockCopy(_bytes, 0, rc, 0, len);
+ return rc;
+ }
+
+ public byte[] toArray(int startIndex, int length)
+ {
+ if(startIndex < 0)
+ {
+ throwOutOfRange("startIndex", startIndex, "startIndex must be non-negative");
+ }
+ if(startIndex >= _position)
+ {
+ throwOutOfRange("startIndex", startIndex, "startIndex must be less than position");
+ }
+ if(length < 0)
+ {
+ throwOutOfRange("length", length, "length must be non-negative");
+ }
+ if(startIndex + length > _position)
+ {
+ throw new ArgumentException("startIndex + length must not exceed end mark of buffer");
+ }
+ byte[] rc = new byte[length];
+ System.Buffer.BlockCopy(_bytes, startIndex, rc, 0, length);
+ return rc;
+ }
+
+ public ByteBuffer put(ByteBuffer buf)
+ {
+ int len = buf.remaining();
+ checkOverflow(len);
+ System.Buffer.BlockCopy(buf._bytes, buf._position, _bytes, _position, len);
+ _position += len;
+ return this;
+ }
+
+ public byte get()
+ {
+ checkUnderflow(1);
+ return System.Buffer.GetByte(_bytes, _position++);
+ }
+
+ public byte get(int pos)
+ {
+ return System.Buffer.GetByte(_bytes, pos);
+ }
+
+ public ByteBuffer get(byte[] b)
+ {
+ return get(b, 0, System.Buffer.ByteLength(b));
+ }
+
+ public ByteBuffer get(byte[] b, int offset, int length)
+ {
+ if(offset < 0)
+ {
+ throwOutOfRange("offset", offset, "offset must be non-negative");
+ }
+ if(offset + length > System.Buffer.ByteLength(b))
+ {
+ throwOutOfRange("length", length, "insufficient room beyond given offset in destination array");
+ }
+ checkUnderflow(length);
+ System.Buffer.BlockCopy(_bytes, _position, b, offset, length);
+ _position += length;
+ return this;
+ }
+
+ public ByteBuffer put(byte b)
+ {
+ checkOverflow(1);
+ System.Buffer.SetByte(_bytes, _position++, b);
+ return this;
+ }
+
+ public ByteBuffer put(int pos, byte b)
+ {
+ System.Buffer.SetByte(_bytes, pos, b);
+ return this;
+ }
+
+ public ByteBuffer put(byte[] b)
+ {
+ return put(b, 0, System.Buffer.ByteLength(b));
+ }
+
+ public ByteBuffer put(byte[]b, int offset, int length)
+ {
+ if(offset < 0)
+ {
+ throwOutOfRange("offset", offset, "offset must be non-negative");
+ }
+ if(offset + length > System.Buffer.ByteLength(b))
+ {
+ throwOutOfRange("length", length, "insufficient data beyond given offset in source array");
+ }
+ if(length > 0)
+ {
+ checkOverflow(length);
+ System.Buffer.BlockCopy(b, offset, _bytes, _position, length);
+ _position += length;
+ }
+ return this;
+ }
+
+ public bool getBool()
+ {
+ return get() == 1;
+ }
+
+ public void getBoolSeq(bool[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkUnderflow(len);
+ System.Buffer.BlockCopy(_bytes, _position, seq, 0, len);
+ _position += len;
+ }
+
+ public ByteBuffer putBool(bool b)
+ {
+ return put(b ? (byte)1 : (byte)0);
+ }
+
+ public ByteBuffer putBoolSeq(bool[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkOverflow(len);
+ System.Buffer.BlockCopy(seq, 0, _bytes, _position, len);
+ _position += len;
+ return this;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ struct ValBytes
+ {
+ [FieldOffset(0)]
+ public short shortVal;
+
+ [FieldOffset(0)]
+ public int intVal;
+
+ [FieldOffset(0)]
+ public long longVal;
+
+ [FieldOffset(0)]
+ public float floatVal;
+
+ [FieldOffset(0)]
+ public double doubleVal;
+
+ [FieldOffset(0)]
+ public byte b0;
+ [FieldOffset(1)]
+ public byte b1;
+ [FieldOffset(2)]
+ public byte b2;
+ [FieldOffset(3)]
+ public byte b3;
+ [FieldOffset(4)]
+ public byte b4;
+ [FieldOffset(5)]
+ public byte b5;
+ [FieldOffset(6)]
+ public byte b6;
+ [FieldOffset(7)]
+ public byte b7;
+ }
+
+ public short getShort()
+ {
+ short v = getShort(_position);
+ _position += 2;
+ return v;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public short getShort(int pos)
+ {
+ checkUnderflow(pos, 2);
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[pos])
+ {
+ _valBytes.shortVal = *((short*)p);
+ }
+#else
+ _valBytes.b0 = _bytes[pos];
+ _valBytes.b1 = _bytes[pos + 1];
+#endif
+ }
+ else
+ {
+ _valBytes.b1 = _bytes[pos];
+ _valBytes.b0 = _bytes[pos + 1];
+ }
+ return _valBytes.shortVal;
+ }
+
+ public void getShortSeq(short[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkUnderflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(_bytes, _position, seq, 0, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 2;
+ _valBytes.b1 = _bytes[index];
+ _valBytes.b0 = _bytes[index + 1];
+ seq[i] = _valBytes.shortVal;
+ }
+ }
+ _position += len;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public ByteBuffer putShort(short val)
+ {
+ checkOverflow(2);
+ _valBytes.shortVal = val;
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[_position])
+ {
+ *((short*)p) = _valBytes.shortVal;
+ }
+#else
+ _bytes[_position] = _valBytes.b0;
+ _bytes[_position + 1] = _valBytes.b1;
+#endif
+ }
+ else
+ {
+ _bytes[_position + 1] = _valBytes.b0;
+ _bytes[_position] = _valBytes.b1;
+ }
+ _position += 2;
+ return this;
+ }
+
+ public ByteBuffer putShortSeq(short[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkOverflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(seq, 0, _bytes, _position, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 2;
+ _valBytes.shortVal = seq[i];
+ _bytes[index + 1] = _valBytes.b0;
+ _bytes[index] = _valBytes.b1;
+ }
+ }
+ _position += len;
+ return this;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public int getInt()
+ {
+ checkUnderflow(4);
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[_position])
+ {
+ _valBytes.intVal = *((int*)p);
+ }
+#else
+ _valBytes.b0 = _bytes[_position];
+ _valBytes.b1 = _bytes[_position + 1];
+ _valBytes.b2 = _bytes[_position + 2];
+ _valBytes.b3 = _bytes[_position + 3];
+#endif
+ }
+ else
+ {
+ _valBytes.b3 = _bytes[_position];
+ _valBytes.b2 = _bytes[_position + 1];
+ _valBytes.b1 = _bytes[_position + 2];
+ _valBytes.b0 = _bytes[_position + 3];
+ }
+ _position += 4;
+ return _valBytes.intVal;
+ }
+
+ public void getIntSeq(int[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkUnderflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(_bytes, _position, seq, 0, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 4;
+ _valBytes.b3 = _bytes[index];
+ _valBytes.b2 = _bytes[index + 1];
+ _valBytes.b1 = _bytes[index + 2];
+ _valBytes.b0 = _bytes[index + 3];
+ seq[i] = _valBytes.intVal;
+ }
+ }
+ _position += len;
+ }
+
+ public ByteBuffer putInt(int val)
+ {
+ putInt(_position, val);
+ _position += 4;
+ return this;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public ByteBuffer putInt(int pos, int val)
+ {
+ if(pos < 0)
+ {
+ throwOutOfRange("pos", pos, "position must be non-negative");
+ }
+ if(pos + 4 > _limit)
+ {
+ throwOutOfRange("pos", pos, "position must be less than limit - 4");
+ }
+ _valBytes.intVal = val;
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[pos])
+ {
+ *((int*)p) = _valBytes.intVal;
+ }
+#else
+ _bytes[pos] = _valBytes.b0;
+ _bytes[pos + 1] = _valBytes.b1;
+ _bytes[pos + 2] = _valBytes.b2;
+ _bytes[pos + 3] = _valBytes.b3;
+#endif
+ }
+ else
+ {
+ _bytes[pos + 3] = _valBytes.b0;
+ _bytes[pos + 2] = _valBytes.b1;
+ _bytes[pos + 1] = _valBytes.b2;
+ _bytes[pos] = _valBytes.b3;
+ }
+ return this;
+ }
+
+ public ByteBuffer putIntSeq(int[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkOverflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(seq, 0, _bytes, _position, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 4;
+ _valBytes.intVal = seq[i];
+ _bytes[index + 3] = _valBytes.b0;
+ _bytes[index + 2] = _valBytes.b1;
+ _bytes[index + 1] = _valBytes.b2;
+ _bytes[index] = _valBytes.b3;
+ }
+ }
+ _position += len;
+ return this;
+ }
+
+ public long getLong()
+ {
+ long v = getLong(_position);
+ _position += 8;
+ return v;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public long getLong(int pos)
+ {
+ checkUnderflow(pos, 8);
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[pos])
+ {
+ _valBytes.longVal = *((long*)p);
+ }
+#else
+ _valBytes.b0 = _bytes[pos];
+ _valBytes.b1 = _bytes[pos + 1];
+ _valBytes.b2 = _bytes[pos + 2];
+ _valBytes.b3 = _bytes[pos + 3];
+ _valBytes.b4 = _bytes[pos + 4];
+ _valBytes.b5 = _bytes[pos + 5];
+ _valBytes.b6 = _bytes[pos + 6];
+ _valBytes.b7 = _bytes[pos + 7];
+#endif
+ }
+ else
+ {
+ _valBytes.b7 = _bytes[pos];
+ _valBytes.b6 = _bytes[pos + 1];
+ _valBytes.b5 = _bytes[pos + 2];
+ _valBytes.b4 = _bytes[pos + 3];
+ _valBytes.b3 = _bytes[pos + 4];
+ _valBytes.b2 = _bytes[pos + 5];
+ _valBytes.b1 = _bytes[pos + 6];
+ _valBytes.b0 = _bytes[pos + 7];
+ }
+ return _valBytes.longVal;
+ }
+
+ public void getLongSeq(long[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkUnderflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(_bytes, _position, seq, 0, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 8;
+ _valBytes.b7 = _bytes[index];
+ _valBytes.b6 = _bytes[index + 1];
+ _valBytes.b5 = _bytes[index + 2];
+ _valBytes.b4 = _bytes[index + 3];
+ _valBytes.b3 = _bytes[index + 4];
+ _valBytes.b2 = _bytes[index + 5];
+ _valBytes.b1 = _bytes[index + 6];
+ _valBytes.b0 = _bytes[index + 7];
+ seq[i] = _valBytes.longVal;
+ }
+ }
+ _position += len;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public ByteBuffer putLong(long val)
+ {
+ checkOverflow(8);
+ _valBytes.longVal = val;
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[_position])
+ {
+ *((long*)p) = _valBytes.longVal;
+ }
+#else
+ _bytes[_position] = _valBytes.b0;
+ _bytes[_position + 1] = _valBytes.b1;
+ _bytes[_position + 2] = _valBytes.b2;
+ _bytes[_position + 3] = _valBytes.b3;
+ _bytes[_position + 4] = _valBytes.b4;
+ _bytes[_position + 5] = _valBytes.b5;
+ _bytes[_position + 6] = _valBytes.b6;
+ _bytes[_position + 7] = _valBytes.b7;
+#endif
+ }
+ else
+ {
+ _bytes[_position + 7] = _valBytes.b0;
+ _bytes[_position + 6] = _valBytes.b1;
+ _bytes[_position + 5] = _valBytes.b2;
+ _bytes[_position + 4] = _valBytes.b3;
+ _bytes[_position + 3] = _valBytes.b4;
+ _bytes[_position + 2] = _valBytes.b5;
+ _bytes[_position + 1] = _valBytes.b6;
+ _bytes[_position] = _valBytes.b7;
+ }
+ _position += 8;
+ return this;
+ }
+
+ public ByteBuffer putLongSeq(long[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkOverflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(seq, 0, _bytes, _position, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 8;
+ _valBytes.longVal = seq[i];
+ _bytes[index + 7] = _valBytes.b0;
+ _bytes[index + 6] = _valBytes.b1;
+ _bytes[index + 5] = _valBytes.b2;
+ _bytes[index + 4] = _valBytes.b3;
+ _bytes[index + 3] = _valBytes.b4;
+ _bytes[index + 2] = _valBytes.b5;
+ _bytes[index + 1] = _valBytes.b6;
+ _bytes[index] = _valBytes.b7;
+ }
+ }
+ _position += len;
+ return this;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public float getFloat()
+ {
+ checkUnderflow(4);
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[_position])
+ {
+ _valBytes.floatVal = *((float*)p);
+ }
+#else
+ _valBytes.b0 = _bytes[_position];
+ _valBytes.b1 = _bytes[_position + 1];
+ _valBytes.b2 = _bytes[_position + 2];
+ _valBytes.b3 = _bytes[_position + 3];
+#endif
+ }
+ else
+ {
+ _valBytes.b3 = _bytes[_position];
+ _valBytes.b2 = _bytes[_position + 1];
+ _valBytes.b1 = _bytes[_position + 2];
+ _valBytes.b0 = _bytes[_position + 3];
+ }
+ _position += 4;
+ return _valBytes.floatVal;
+ }
+
+ public void getFloatSeq(float[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkUnderflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(_bytes, _position, seq, 0, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 4;
+ _valBytes.b3 = _bytes[index];
+ _valBytes.b2 = _bytes[index + 1];
+ _valBytes.b1 = _bytes[index + 2];
+ _valBytes.b0 = _bytes[index + 3];
+ seq[i] = _valBytes.floatVal;
+ }
+ }
+ _position += len;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public ByteBuffer putFloat(float val)
+ {
+ checkOverflow(4);
+ _valBytes.floatVal = val;
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[_position])
+ {
+ *((float*)p) = _valBytes.floatVal;
+ }
+#else
+ _bytes[_position] = _valBytes.b0;
+ _bytes[_position + 1] = _valBytes.b1;
+ _bytes[_position + 2] = _valBytes.b2;
+ _bytes[_position + 3] = _valBytes.b3;
+#endif
+ }
+ else
+ {
+ _bytes[_position + 3] = _valBytes.b0;
+ _bytes[_position + 2] = _valBytes.b1;
+ _bytes[_position + 1] = _valBytes.b2;
+ _bytes[_position] = _valBytes.b3;
+ }
+ _position += 4;
+ return this;
+ }
+
+ public ByteBuffer putFloatSeq(float[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkOverflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(seq, 0, _bytes, _position, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 4;
+ _valBytes.floatVal = seq[i];
+ _bytes[index + 3] = _valBytes.b0;
+ _bytes[index + 2] = _valBytes.b1;
+ _bytes[index + 1] = _valBytes.b2;
+ _bytes[index] = _valBytes.b3;
+ }
+ }
+ _position += len;
+ return this;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public double getDouble()
+ {
+ checkUnderflow(8);
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[_position])
+ {
+ _valBytes.doubleVal = *((double*)p);
+ }
+#else
+ _valBytes.b0 = _bytes[_position];
+ _valBytes.b1 = _bytes[_position + 1];
+ _valBytes.b2 = _bytes[_position + 2];
+ _valBytes.b3 = _bytes[_position + 3];
+ _valBytes.b4 = _bytes[_position + 4];
+ _valBytes.b5 = _bytes[_position + 5];
+ _valBytes.b6 = _bytes[_position + 6];
+ _valBytes.b7 = _bytes[_position + 7];
+#endif
+ }
+ else
+ {
+ _valBytes.b7 = _bytes[_position];
+ _valBytes.b6 = _bytes[_position + 1];
+ _valBytes.b5 = _bytes[_position + 2];
+ _valBytes.b4 = _bytes[_position + 3];
+ _valBytes.b3 = _bytes[_position + 4];
+ _valBytes.b2 = _bytes[_position + 5];
+ _valBytes.b1 = _bytes[_position + 6];
+ _valBytes.b0 = _bytes[_position + 7];
+ }
+ _position += 8;
+ return _valBytes.doubleVal;
+ }
+
+ public void getDoubleSeq(double[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkUnderflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(_bytes, _position, seq, 0, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 8;
+ _valBytes.b7 = _bytes[index];
+ _valBytes.b6 = _bytes[index + 1];
+ _valBytes.b5 = _bytes[index + 2];
+ _valBytes.b4 = _bytes[index + 3];
+ _valBytes.b3 = _bytes[index + 4];
+ _valBytes.b2 = _bytes[index + 5];
+ _valBytes.b1 = _bytes[index + 6];
+ _valBytes.b0 = _bytes[index + 7];
+ seq[i] = _valBytes.doubleVal;
+ }
+ }
+ _position += len;
+ }
+
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ unsafe
+#endif
+ public ByteBuffer putDouble(double val)
+ {
+ checkOverflow(8);
+ _valBytes.doubleVal = val;
+ if(NO._o == _order)
+ {
+#if !MANAGED && !COMPACT && !SILVERLIGHT
+ fixed(byte* p = &_bytes[_position])
+ {
+ *((double*)p) = _valBytes.doubleVal;
+ }
+#else
+ _bytes[_position] = _valBytes.b0;
+ _bytes[_position + 1] = _valBytes.b1;
+ _bytes[_position + 2] = _valBytes.b2;
+ _bytes[_position + 3] = _valBytes.b3;
+ _bytes[_position + 4] = _valBytes.b4;
+ _bytes[_position + 5] = _valBytes.b5;
+ _bytes[_position + 6] = _valBytes.b6;
+ _bytes[_position + 7] = _valBytes.b7;
+#endif
+ }
+ else
+ {
+ _bytes[_position + 7] = _valBytes.b0;
+ _bytes[_position + 6] = _valBytes.b1;
+ _bytes[_position + 5] = _valBytes.b2;
+ _bytes[_position + 4] = _valBytes.b3;
+ _bytes[_position + 3] = _valBytes.b4;
+ _bytes[_position + 2] = _valBytes.b5;
+ _bytes[_position + 1] = _valBytes.b6;
+ _bytes[_position] = _valBytes.b7;
+ }
+ _position += 8;
+ return this;
+ }
+
+ public ByteBuffer putDoubleSeq(double[] seq)
+ {
+ int len = System.Buffer.ByteLength(seq);
+ checkOverflow(len);
+ if(NO._o == _order)
+ {
+ System.Buffer.BlockCopy(seq, 0, _bytes, _position, len);
+ }
+ else
+ {
+ for(int i = 0; i < seq.Length; ++i)
+ {
+ int index = _position + i * 8;
+ _valBytes.doubleVal = seq[i];
+ _bytes[index + 7] = _valBytes.b0;
+ _bytes[index + 6] = _valBytes.b1;
+ _bytes[index + 5] = _valBytes.b2;
+ _bytes[index + 4] = _valBytes.b3;
+ _bytes[index + 3] = _valBytes.b4;
+ _bytes[index + 2] = _valBytes.b5;
+ _bytes[index + 1] = _valBytes.b6;
+ _bytes[index] = _valBytes.b7;
+ }
+ }
+ _position += len;
+ return this;
+ }
+
+ public byte[] rawBytes()
+ {
+ return _bytes;
+ }
+
+ public byte[] rawBytes(int offset, int len)
+ {
+ if(offset + len > _limit)
+ {
+ throw new InvalidOperationException("buffer underflow");
+ }
+ byte[] rc = new byte[len];
+ Array.Copy(_bytes, offset, rc, 0, len);
+ return rc;
+ }
+
+ private void checkUnderflow(int size)
+ {
+ if(_position + size > _limit)
+ {
+ throw new InvalidOperationException("buffer underflow");
+ }
+ }
+
+ private void checkUnderflow(int pos, int size)
+ {
+ if(pos + size > _limit)
+ {
+ throw new InvalidOperationException("buffer underflow");
+ }
+ }
+
+ private void checkOverflow(int size)
+ {
+ if(_position + size > _limit)
+ {
+ throw new InvalidOperationException("buffer overflow");
+ }
+ }
+
+ private int _position;
+ private int _limit;
+ private int _capacity;
+ private byte[] _bytes;
+ private ValBytes _valBytes;
+ private ByteOrder _order;
+
+ private class NO // Native Order
+ {
+ static NO()
+ {
+ _o = BitConverter.IsLittleEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN;
+ }
+ internal static readonly ByteOrder _o;
+
+ private NO()
+ {
+ }
+ }
+
+ private static void throwOutOfRange(string param, object value, string message)
+ {
+#if COMPACT || SILVERLIGHT
+ throw new ArgumentOutOfRangeException(param, message);
+#else
+ throw new ArgumentOutOfRangeException(param, value, message);
+#endif
+ }
+ }
+}
diff --git a/csharp/src/Ice/CollectionBase.cs b/csharp/src/Ice/CollectionBase.cs
new file mode 100644
index 00000000000..3c505f58ee6
--- /dev/null
+++ b/csharp/src/Ice/CollectionBase.cs
@@ -0,0 +1,450 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections.Generic;
+
+namespace IceInternal
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public abstract class CollectionBase<T> : System.Collections.IList
+ {
+ protected List<T> list_;
+
+ public CollectionBase()
+ {
+ list_ = new List<T>();
+ }
+
+ public CollectionBase(int capacity)
+ {
+ list_ = new List<T>(capacity);
+ }
+
+ public CollectionBase(T[] a)
+ {
+ if(a == null)
+ {
+ throw new ArgumentNullException("a", "Cannot construct collection from null array");
+ }
+
+ list_ = new List<T>(a.Length);
+ list_.AddRange(a);
+ }
+
+ public CollectionBase(IEnumerable<T> l)
+ {
+ if(l == null)
+ {
+ throw new ArgumentNullException("l", "Cannot construct collection from null collection");
+ }
+
+ list_ = new List<T>();
+ list_.AddRange(l);
+ }
+
+ public static implicit operator List<T>(CollectionBase<T> l)
+ {
+ return l.list_;
+ }
+
+
+ public void CopyTo(T[] a__)
+ {
+ list_.CopyTo(a__);
+ }
+
+ public void CopyTo(T[] a__, int i__)
+ {
+ list_.CopyTo(a__, i__);
+ }
+
+ public void CopyTo(int i__, T[] a__, int ai__, int _c_)
+ {
+ list_.CopyTo(i__, a__, ai__, _c_);
+ }
+
+ public T[] ToArray()
+ {
+ return list_.ToArray();
+ }
+
+ public virtual void TrimToSize()
+ {
+ list_.TrimExcess();
+ }
+
+ public virtual void Sort()
+ {
+ list_.Sort();
+ }
+
+ public virtual void Sort(System.Collections.IComparer comparer)
+ {
+ list_.Sort(new Comparer(comparer));
+ }
+
+ public virtual void Sort(int index, int count, System.Collections.IComparer comparer)
+ {
+ list_.Sort(index, count, new Comparer(comparer));
+ }
+
+ public virtual void Reverse()
+ {
+ list_.Reverse();
+ }
+
+ public virtual void Reverse(int index, int count)
+ {
+ list_.Reverse(index, count);
+ }
+
+ public virtual int BinarySearch(T value)
+ {
+ return list_.BinarySearch(value);
+ }
+
+ public virtual int BinarySearch(T value, System.Collections.IComparer comparer)
+ {
+ return list_.BinarySearch(value, new Comparer(comparer));
+ }
+
+ public virtual int BinarySearch(int index, int count, T value, System.Collections.IComparer comparer)
+ {
+ return list_.BinarySearch(index, count, value, new Comparer(comparer));
+ }
+
+ public virtual void InsertRange(int index, CollectionBase<T> c)
+ {
+ list_.InsertRange(index, c.list_);
+ }
+
+ public virtual void InsertRange(int index, T[] c)
+ {
+ list_.InsertRange(index, c);
+ }
+
+ public virtual void RemoveRange(int index, int count)
+ {
+ list_.RemoveRange(index, count);
+ }
+
+ public virtual void SetRange(int index, CollectionBase<T> c)
+ {
+ if(c == null)
+ {
+ throw new ArgumentNullException("c", "Collection must not be null for SetRange()");
+ }
+ if(index < 0 || index + c.Count > list_.Count)
+ {
+ throw new ArgumentOutOfRangeException("index", "Index out of range");
+ }
+ for(int i = index; i < list_.Count; ++i)
+ {
+ list_[i] = c[i - index];
+ }
+ }
+
+ public virtual void SetRange(int index, T[] c)
+ {
+ if(c == null)
+ {
+ throw new ArgumentNullException("c", "Collection must not be null for SetRange()");
+ }
+ if(index < 0 || index + c.Length > list_.Count)
+ {
+ throw new ArgumentOutOfRangeException("index", "Index out of range");
+ }
+ for(int i = index; i < list_.Count; ++i)
+ {
+ list_[i] = c[i - index];
+ }
+ }
+
+ public virtual int LastIndexOf(T value)
+ {
+ return list_.LastIndexOf(value);
+ }
+
+ public virtual int LastIndexOf(T value, int startIndex)
+ {
+ return list_.LastIndexOf(value, startIndex);
+ }
+
+ public virtual int LastIndexOf(T value, int startIndex, int count)
+ {
+ return list_.LastIndexOf(value, startIndex, count);
+ }
+
+ public void AddRange(CollectionBase<T> s__)
+ {
+ list_.AddRange(s__.list_);
+ }
+
+ public void AddRange(T[] a__)
+ {
+ list_.AddRange(a__);
+ }
+
+ public int Capacity
+ {
+ get
+ {
+ return list_.Capacity;
+ }
+
+ set
+ {
+ list_.Capacity = value;
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ return list_.Count;
+ }
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return list_.GetEnumerator();
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ return list_.GetEnumerator();
+ }
+
+ public void RemoveAt(int index)
+ {
+ list_.RemoveAt(index);
+ }
+
+ public int Add(T value)
+ {
+ list_.Add(value);
+ return list_.Count - 1;
+ }
+
+ public void Clear()
+ {
+ list_.Clear();
+ }
+
+ public bool IsFixedSize
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public int IndexOf(T value)
+ {
+ return list_.IndexOf(value);
+ }
+
+ public void Insert(int index, T value)
+ {
+ list_.Insert(index, value);
+ }
+
+ public void Remove(T value)
+ {
+ list_.Remove(value);
+ }
+
+ public bool Contains(T value)
+ {
+ return list_.Contains(value);
+ }
+
+ public bool IsSynchronized
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public object SyncRoot
+ {
+ get
+ {
+ return this;
+ }
+ }
+
+ public T this[int index]
+ {
+ get
+ {
+ return list_[index];
+ }
+ set
+ {
+ list_[index] = value;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ int h = 5381;
+ for(int i = 0; i < Count; ++i)
+ {
+ T v__ = list_[i];
+ IceInternal.HashUtil.hashAdd(ref h, v__);
+ }
+ return h;
+ }
+
+ public override bool Equals(object other)
+ {
+ if(object.ReferenceEquals(this, other))
+ {
+ return true;
+ }
+ try
+ {
+ CollectionBase<T> c = (CollectionBase<T>)other;
+ if(list_.Count != c.list_.Count)
+ {
+ return false;
+ }
+ if(list_.Count == 0)
+ {
+ return true;
+ }
+ for(int i = 0; i < list_.Count; ++i)
+ {
+ if(!Equals(list_[i], c.list_[i]))
+ {
+ return false;
+ }
+ }
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static bool operator==(CollectionBase<T> lhs__, CollectionBase<T> rhs__)
+ {
+ return Equals(lhs__, rhs__);
+ }
+
+ public static bool operator!=(CollectionBase<T> lhs__, CollectionBase<T> rhs__)
+ {
+ return !Equals(lhs__, rhs__);
+ }
+
+ private class Comparer : IComparer<T>
+ {
+ private System.Collections.IComparer _c;
+
+ public Comparer(System.Collections.IComparer c)
+ {
+ _c = c;
+ }
+
+ public virtual int Compare(T l, T r)
+ {
+ return _c.Compare(l, r);
+ }
+ }
+
+ public int Add(object o)
+ {
+ checkType(o);
+ return Add((T)o);
+ }
+
+ public bool Contains(object o)
+ {
+ checkType(o);
+ return Contains((T)o);
+ }
+
+ public int IndexOf(object o)
+ {
+ checkType(o);
+ return IndexOf((T)o);
+ }
+
+ public void Insert(int i, object o)
+ {
+ checkType(o);
+ Insert(i, (T)o);
+ }
+
+ public void Remove(object o)
+ {
+ checkType(o);
+ Remove((T)o);
+ }
+
+ object System.Collections.IList.this[int index]
+ {
+ get
+ {
+ return this[index];
+ }
+ set
+ {
+ checkType(value);
+ this[index] = (T)value;
+ }
+ }
+
+ public void CopyTo(Array a, int index)
+ {
+ Type t = a.GetType().GetElementType();
+ if(!t.IsAssignableFrom(typeof(T)))
+ {
+ throw new ArgumentException("a__", "Cannot assign " + typeof(T).ToString() + " to array of "
+ + t.ToString());
+ }
+ CopyTo((T[])a, index);
+ }
+
+ private void checkType(object o)
+ {
+
+ if(o != null && !(o is T))
+ {
+ throw new ArgumentException("Cannot use an object of type " + o.GetType().ToString()
+ + " with a collection of " + typeof(T).ToString());
+ }
+ }
+ }
+
+}
+
+namespace Ice
+{
+ [Obsolete("This class is deprecated.")]
+ public abstract class CollectionBase<T> : IceInternal.CollectionBase<T>
+ {
+ }
+}
diff --git a/csharp/src/Ice/Collections.cs b/csharp/src/Ice/Collections.cs
new file mode 100644
index 00000000000..65db2114791
--- /dev/null
+++ b/csharp/src/Ice/Collections.cs
@@ -0,0 +1,239 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace IceUtilInternal
+{
+ public sealed class Collections
+ {
+ public static bool SequenceEquals(ICollection seq1, ICollection seq2)
+ {
+ if(object.ReferenceEquals(seq1, seq2))
+ {
+ return true;
+ }
+
+ if((seq1 == null && seq2 != null) || (seq1 != null && seq2 == null))
+ {
+ return false;
+ }
+
+ if(seq1.Count == seq2.Count)
+ {
+ IEnumerator e1 = seq1.GetEnumerator();
+ IEnumerator e2 = seq2.GetEnumerator();
+ while(e1.MoveNext())
+ {
+ e2.MoveNext();
+ if(e1.Current == null)
+ {
+ if(e2.Current != null)
+ {
+ return false;
+ }
+ }
+ else if(!e1.Current.Equals(e2.Current))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool SequenceEquals(IEnumerable seq1, IEnumerable seq2)
+ {
+ if(object.ReferenceEquals(seq1, seq2))
+ {
+ return true;
+ }
+
+ if((seq1 == null && seq2 != null) || (seq1 != null && seq2 == null))
+ {
+ return false;
+ }
+
+ IEnumerator e1 = seq1.GetEnumerator();
+ IEnumerator e2 = seq2.GetEnumerator();
+ while(e1.MoveNext())
+ {
+ if(!e2.MoveNext())
+ {
+ return false;
+ }
+ if(e1.Current == null)
+ {
+ if(e2.Current != null)
+ {
+ return false;
+ }
+ }
+ else if(!e1.Current.Equals(e2.Current))
+ {
+ return false;
+ }
+ }
+
+ if(e2.MoveNext())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static int SequenceGetHashCode(IEnumerable seq)
+ {
+ int h = 5381;
+ IEnumerator e = seq.GetEnumerator();
+ while(e.MoveNext())
+ {
+ IceInternal.HashUtil.hashAdd(ref h, e.Current);
+ }
+ return h;
+ }
+
+ public static bool DictionaryEquals(IDictionary d1, IDictionary d2)
+ {
+ if(object.ReferenceEquals(d1, d2))
+ {
+ return true;
+ }
+
+ if((d1 == null && d2 != null) || (d1 != null && d2 == null))
+ {
+ return false;
+ }
+
+ if(d1.Count == d2.Count)
+ {
+ IDictionaryEnumerator e1 = d1.GetEnumerator();
+ IDictionaryEnumerator e2 = d2.GetEnumerator();
+ while(e1.MoveNext())
+ {
+ e2.MoveNext();
+ if(!e1.Key.Equals(e2.Key))
+ {
+ return false;
+ }
+ if(e1.Value == null)
+ {
+ if(e2.Value != null)
+ {
+ return false;
+ }
+ }
+ else if(!e1.Value.Equals(e2.Value))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static int DictionaryGetHashCode(IDictionary d)
+ {
+ int h = 5381;
+ IDictionaryEnumerator e = d.GetEnumerator();
+ while(e.MoveNext())
+ {
+ IceInternal.HashUtil.hashAdd(ref h, e.Key);
+ IceInternal.HashUtil.hashAdd(ref h, e.Value);
+ }
+ return h;
+ }
+
+ public static void Shuffle<T>(ref List<T> l)
+ {
+ lock(rand_)
+ {
+ for(int j = 0; j < l.Count - 1; ++j)
+ {
+ int r = rand_.Next(l.Count - j) + j;
+ Debug.Assert(r >= j && r < l.Count);
+ if(r != j)
+ {
+ T tmp = l[j];
+ l[j] = l[r];
+ l[r] = tmp;
+ }
+ }
+ }
+ }
+
+ public static void Sort<T>(ref List<T> array, IComparer<T> comparator)
+ {
+ //
+ // This Sort method implements the merge sort algorithm
+ // which is a stable sort (unlike the Sort method of the
+ // System.Collections.ArrayList which is unstable).
+ //
+ Sort1(ref array, 0, array.Count, comparator);
+ }
+
+ private static void Sort1<T>(ref List<T> array, int begin, int end, IComparer<T> comparator)
+ {
+ int mid;
+ if(end - begin <= 1)
+ {
+ return;
+ }
+
+ mid = (begin + end) / 2;
+ Sort1(ref array, begin, mid, comparator);
+ Sort1(ref array, mid, end, comparator);
+ Merge(ref array, begin, mid, end, comparator);
+ }
+
+ private static void Merge<T>(ref List<T> array, int begin, int mid, int end, IComparer<T> comparator)
+ {
+ int i = begin;
+ int j = mid;
+ int k = 0;
+
+ T[] tmp = new T[end - begin];
+ while(i < mid && j < end)
+ {
+ if(comparator.Compare(array[i], array[j]) <= 0)
+ {
+ tmp[k++] = array[i++];
+ }
+ else
+ {
+ tmp[k++] = array[j++];
+ }
+ }
+
+ while(i < mid)
+ {
+ tmp[k++] = array[i++];
+ }
+ while(j < end)
+ {
+ tmp[k++] = array[j++];
+ }
+ for(i = 0; i < (end - begin); ++i)
+ {
+ array[begin + i] = tmp[i];
+ }
+ }
+
+ private static System.Random rand_ = new System.Random(unchecked((int)System.DateTime.Now.Ticks));
+ }
+}
diff --git a/csharp/src/Ice/CollocatedRequestHandler.cs b/csharp/src/Ice/CollocatedRequestHandler.cs
new file mode 100644
index 00000000000..4fcd670003c
--- /dev/null
+++ b/csharp/src/Ice/CollocatedRequestHandler.cs
@@ -0,0 +1,346 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using Ice.Instrumentation;
+
+namespace IceInternal
+{
+ public class CollocatedRequestHandler : RequestHandler, ResponseHandler
+ {
+ private void
+ fillInValue(BasicStream os, int pos, int value)
+ {
+ os.rewriteInt(value, pos);
+ }
+
+ public
+ CollocatedRequestHandler(Reference @ref, Ice.ObjectAdapter adapter)
+ {
+ _reference = @ref;
+ _dispatcher = _reference.getInstance().initializationData().dispatcher != null;
+ _response = _reference.getMode() == Reference.Mode.ModeTwoway;
+ _adapter = (Ice.ObjectAdapterI)adapter;
+
+ _logger = _reference.getInstance().initializationData().logger; // Cached for better performance.
+ _traceLevels = _reference.getInstance().traceLevels(); // Cached for better performance.
+ _requestId = 0;
+ }
+
+ public RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler)
+ {
+ return previousHandler == this ? newHandler : this;
+ }
+
+ public bool sendAsyncRequest(ProxyOutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback)
+ {
+ return outAsync.invokeCollocated(this, out sentCallback);
+ }
+
+ public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
+ {
+ lock(this)
+ {
+ int requestId;
+ if(_sendAsyncRequests.TryGetValue(outAsync, out requestId))
+ {
+ if(requestId > 0)
+ {
+ _asyncRequests.Remove(requestId);
+ }
+ _sendAsyncRequests.Remove(outAsync);
+ Ice.AsyncCallback cb = outAsync.completed(ex);
+ if(cb != null)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ return;
+ }
+ if(outAsync is OutgoingAsync)
+ {
+ OutgoingAsync o = (OutgoingAsync)outAsync;
+ Debug.Assert(o != null);
+ foreach(KeyValuePair<int, OutgoingAsyncBase> e in _asyncRequests)
+ {
+ if(e.Value == o)
+ {
+ _asyncRequests.Remove(e.Key);
+ Ice.AsyncCallback cb = outAsync.completed(ex);
+ if(cb != null)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public void sendResponse(int requestId, BasicStream os, byte status, bool amd)
+ {
+ Ice.AsyncCallback cb = null;
+ OutgoingAsyncBase outAsync;
+ lock(this)
+ {
+ Debug.Assert(_response);
+
+ os.pos(Protocol.replyHdr.Length + 4);
+
+ if(_traceLevels.protocol >= 1)
+ {
+ fillInValue(os, 10, os.size());
+ TraceUtil.traceRecv(os, _logger, _traceLevels);
+ }
+
+ if(_asyncRequests.TryGetValue(requestId, out outAsync))
+ {
+ _asyncRequests.Remove(requestId);
+ outAsync.getIs().swap(os);
+ cb = outAsync.completed();
+ }
+ }
+
+ if(cb != null)
+ {
+ if(amd)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ else
+ {
+ outAsync.invokeCompleted(cb);
+ }
+ }
+ _adapter.decDirectCount();
+ }
+
+ public void
+ sendNoResponse()
+ {
+ _adapter.decDirectCount();
+ }
+
+ public bool
+ systemException(int requestId, Ice.SystemException ex, bool amd)
+ {
+ handleException(requestId, ex, amd);
+ _adapter.decDirectCount();
+ return true;
+ }
+
+ public void
+ invokeException(int requestId, Ice.LocalException ex, int invokeNum, bool amd)
+ {
+ handleException(requestId, ex, amd);
+ _adapter.decDirectCount();
+ }
+
+ public Reference
+ getReference()
+ {
+ return _reference;
+ }
+
+ public Ice.ConnectionI
+ getConnection()
+ {
+ return null;
+ }
+
+ public bool invokeAsyncRequest(OutgoingAsyncBase outAsync, int batchRequestNum, bool synchronous,
+ out Ice.AsyncCallback sentCallback)
+ {
+ int requestId = 0;
+ {
+ lock(this)
+ {
+ outAsync.cancelable(this); // This will throw if the request is canceled
+
+ if(_response)
+ {
+ requestId = ++_requestId;
+ _asyncRequests.Add(requestId, outAsync);
+ }
+
+ _sendAsyncRequests.Add(outAsync, requestId);
+ }
+ }
+
+ outAsync.attachCollocatedObserver(_adapter, requestId);
+
+ if(synchronous)
+ {
+ //
+ // Treat this collocated call as if it is a synchronous invocation.
+ //
+ if(_reference.getInvocationTimeout() > 0 || !_response)
+ {
+ // Don't invoke from the user thread, invocation timeouts wouldn't work otherwise.
+ _adapter.getThreadPool().dispatch(() =>
+ {
+ if(sentAsync(outAsync))
+ {
+ invokeAll(outAsync.getOs(), requestId, batchRequestNum);
+ }
+ }, null);
+ }
+ else if(_dispatcher)
+ {
+ _adapter.getThreadPool().dispatchFromThisThread(() =>
+ {
+ if(sentAsync(outAsync))
+ {
+ invokeAll(outAsync.getOs(), requestId, batchRequestNum);
+ }
+ }, null);
+ }
+ else // Optimization: directly call invokeAll if there's no dispatcher.
+ {
+ if(sentAsync(outAsync))
+ {
+ invokeAll(outAsync.getOs(), requestId, batchRequestNum);
+ }
+ }
+ sentCallback = null;
+ }
+ else
+ {
+ _adapter.getThreadPool().dispatch(() =>
+ {
+ if(sentAsync(outAsync))
+ {
+ invokeAll(outAsync.getOs(), requestId, batchRequestNum);
+ }
+ }, null);
+ sentCallback = null;
+ }
+ return false;
+ }
+
+ private bool sentAsync(OutgoingAsyncBase outAsync)
+ {
+ lock(this)
+ {
+ if(!_sendAsyncRequests.Remove(outAsync))
+ {
+ return false; // The request timed-out.
+ }
+ }
+
+ Ice.AsyncCallback cb = outAsync.sent();
+ if(cb != null)
+ {
+ outAsync.invokeSent(cb);
+ }
+ return true;
+ }
+
+ private void invokeAll(BasicStream os, int requestId, int batchRequestNum)
+ {
+ if(batchRequestNum > 0)
+ {
+ os.pos(Protocol.requestBatchHdr.Length);
+ }
+ else
+ {
+ os.pos(Protocol.requestHdr.Length);
+ }
+
+ if(_traceLevels.protocol >= 1)
+ {
+ fillInValue(os, 10, os.size());
+ if(requestId > 0)
+ {
+ fillInValue(os, Protocol.headerSize, requestId);
+ }
+ else if(batchRequestNum > 0)
+ {
+ fillInValue(os, Protocol.headerSize, batchRequestNum);
+ }
+ TraceUtil.traceSend(os, _logger, _traceLevels);
+ }
+
+ int invokeNum = batchRequestNum > 0 ? batchRequestNum : 1;
+ ServantManager servantManager = _adapter.getServantManager();
+ try
+ {
+ while(invokeNum > 0)
+ {
+ try
+ {
+ _adapter.incDirectCount();
+ }
+ catch(Ice.ObjectAdapterDeactivatedException ex)
+ {
+ handleException(requestId, ex, false);
+ return;
+ }
+
+ Incoming @in = new Incoming(_reference.getInstance(), this, null, _adapter, _response, (byte)0,
+ requestId);
+ @in.invoke(servantManager, os);
+ --invokeNum;
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ invokeException(requestId, ex, invokeNum, false); // Fatal invocation exception
+ }
+ }
+
+ void
+ handleException(int requestId, Ice.Exception ex, bool amd)
+ {
+ if(requestId == 0)
+ {
+ return; // Ignore exception for oneway messages.
+ }
+
+ OutgoingAsyncBase outAsync;
+ Ice.AsyncCallback cb = null;
+ lock(this)
+ {
+ if(_asyncRequests.TryGetValue(requestId, out outAsync))
+ {
+ _asyncRequests.Remove(requestId);
+ cb = outAsync.completed(ex);
+ }
+ }
+
+ if(cb != null)
+ {
+ if(amd)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ else
+ {
+ outAsync.invokeCompleted(cb);
+ }
+ }
+ }
+
+ private readonly Reference _reference;
+ private readonly bool _dispatcher;
+ private readonly bool _response;
+ private readonly Ice.ObjectAdapterI _adapter;
+ private readonly Ice.Logger _logger;
+ private readonly TraceLevels _traceLevels;
+
+ private int _requestId;
+
+ private Dictionary<OutgoingAsyncBase, int> _sendAsyncRequests = new Dictionary<OutgoingAsyncBase, int>();
+ private Dictionary<int, OutgoingAsyncBase> _asyncRequests = new Dictionary<int, OutgoingAsyncBase>();
+ }
+}
diff --git a/csharp/src/Ice/CommunicatorI.cs b/csharp/src/Ice/CommunicatorI.cs
new file mode 100644
index 00000000000..915709fb641
--- /dev/null
+++ b/csharp/src/Ice/CommunicatorI.cs
@@ -0,0 +1,294 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections.Generic;
+
+namespace Ice
+{
+
+ sealed class CommunicatorI : Communicator
+ {
+ public void destroy()
+ {
+ instance_.destroy();
+ }
+
+ public void shutdown()
+ {
+ instance_.objectAdapterFactory().shutdown();
+ }
+
+ public void waitForShutdown()
+ {
+ instance_.objectAdapterFactory().waitForShutdown();
+ }
+
+ public bool isShutdown()
+ {
+ return instance_.objectAdapterFactory().isShutdown();
+ }
+
+ public Ice.ObjectPrx stringToProxy(string s)
+ {
+ return instance_.proxyFactory().stringToProxy(s);
+ }
+
+ public string proxyToString(Ice.ObjectPrx proxy)
+ {
+ return instance_.proxyFactory().proxyToString(proxy);
+ }
+
+ public Ice.ObjectPrx propertyToProxy(string s)
+ {
+ return instance_.proxyFactory().propertyToProxy(s);
+ }
+
+ public Dictionary<string, string> proxyToProperty(Ice.ObjectPrx proxy, string prefix)
+ {
+ return instance_.proxyFactory().proxyToProperty(proxy, prefix);
+ }
+
+ public Ice.Identity stringToIdentity(string s)
+ {
+ return instance_.stringToIdentity(s);
+ }
+
+ public string identityToString(Ice.Identity ident)
+ {
+ return instance_.identityToString(ident);
+ }
+
+ public ObjectAdapter createObjectAdapter(string name)
+ {
+ return instance_.objectAdapterFactory().createObjectAdapter(name, null);
+ }
+
+ public ObjectAdapter createObjectAdapterWithEndpoints(string name, string endpoints)
+ {
+ if(name.Length == 0)
+ {
+ name = System.Guid.NewGuid().ToString();
+ }
+
+ getProperties().setProperty(name + ".Endpoints", endpoints);
+ return instance_.objectAdapterFactory().createObjectAdapter(name, null);
+ }
+
+ public ObjectAdapter createObjectAdapterWithRouter(string name, RouterPrx router)
+ {
+ if(name.Length == 0)
+ {
+ name = System.Guid.NewGuid().ToString();
+ }
+
+ //
+ // We set the proxy properties here, although we still use the proxy supplied.
+ //
+ Dictionary<string, string> properties = proxyToProperty(router, name + ".Router");
+ foreach(KeyValuePair<string, string> entry in properties)
+ {
+ getProperties().setProperty(entry.Key, entry.Value);
+ }
+
+ return instance_.objectAdapterFactory().createObjectAdapter(name, router);
+ }
+
+ public void addObjectFactory(ObjectFactory factory, string id)
+ {
+ instance_.servantFactoryManager().add(factory, id);
+ }
+
+ public ObjectFactory findObjectFactory(string id)
+ {
+ return instance_.servantFactoryManager().find(id);
+ }
+
+ public Properties getProperties()
+ {
+ return instance_.initializationData().properties;
+ }
+
+ public Logger getLogger()
+ {
+ return instance_.initializationData().logger;
+ }
+
+ public Ice.Instrumentation.CommunicatorObserver getObserver()
+ {
+ return instance_.initializationData().observer;
+ }
+
+ public RouterPrx getDefaultRouter()
+ {
+ return instance_.referenceFactory().getDefaultRouter();
+ }
+
+ public void setDefaultRouter(RouterPrx router)
+ {
+ instance_.setDefaultRouter(router);
+ }
+
+ public LocatorPrx getDefaultLocator()
+ {
+ return instance_.referenceFactory().getDefaultLocator();
+ }
+
+ public void setDefaultLocator(LocatorPrx locator)
+ {
+ instance_.setDefaultLocator(locator);
+ }
+
+ public ImplicitContext getImplicitContext()
+ {
+ return instance_.getImplicitContext();
+ }
+
+ public PluginManager getPluginManager()
+ {
+ return instance_.pluginManager();
+ }
+
+ public void flushBatchRequests()
+ {
+ AsyncResult r = begin_flushBatchRequests();
+ end_flushBatchRequests(r);
+ }
+
+ public AsyncResult begin_flushBatchRequests()
+ {
+ return begin_flushBatchRequests(null, null);
+ }
+
+ private const string __flushBatchRequests_name = "flushBatchRequests";
+
+ public AsyncResult begin_flushBatchRequests(AsyncCallback cb, object cookie)
+ {
+ IceInternal.OutgoingConnectionFactory connectionFactory = instance_.outgoingConnectionFactory();
+ IceInternal.ObjectAdapterFactory adapterFactory = instance_.objectAdapterFactory();
+
+ //
+ // This callback object receives the results of all invocations
+ // of Connection.begin_flushBatchRequests.
+ //
+ IceInternal.CommunicatorFlushBatch result =
+ new IceInternal.CommunicatorFlushBatch(this, instance_, __flushBatchRequests_name, cookie);
+
+ if(cb != null)
+ {
+ result.whenCompletedWithAsyncCallback(cb);
+ }
+
+ connectionFactory.flushAsyncBatchRequests(result);
+ adapterFactory.flushAsyncBatchRequests(result);
+
+ //
+ // Inform the callback that we have finished initiating all of the
+ // flush requests. If all of the requests have already completed,
+ // the callback is invoked now.
+ //
+ result.ready();
+
+ return result;
+ }
+
+ public void end_flushBatchRequests(AsyncResult result)
+ {
+ IceInternal.CommunicatorFlushBatch outAsync =
+ IceInternal.CommunicatorFlushBatch.check(result, this, __flushBatchRequests_name);
+ outAsync.wait();
+ }
+
+ public Ice.ObjectPrx createAdmin(ObjectAdapter adminAdapter, Identity adminIdentity)
+ {
+ return instance_.createAdmin(adminAdapter, adminIdentity);
+ }
+
+ public Ice.ObjectPrx getAdmin()
+ {
+ return instance_.getAdmin();
+ }
+
+ public void addAdminFacet(Ice.Object servant, string facet)
+ {
+ instance_.addAdminFacet(servant, facet);
+ }
+
+ public Ice.Object removeAdminFacet(string facet)
+ {
+ return instance_.removeAdminFacet(facet);
+ }
+
+ public Ice.Object findAdminFacet(string facet)
+ {
+ return instance_.findAdminFacet(facet);
+ }
+
+ public Dictionary<string, Ice.Object> findAllAdminFacets()
+ {
+ return instance_.findAllAdminFacets();
+ }
+
+ public void Dispose()
+ {
+ destroy();
+ }
+
+ internal CommunicatorI(InitializationData initData)
+ {
+ instance_ = new IceInternal.Instance(this, initData);
+ }
+
+ /*
+ ~CommunicatorI()
+ {
+ if(!destroyed_)
+ {
+ if(!System.Environment.HasShutdownStarted)
+ {
+ instance_.initializationData().logger.warning(
+ "Ice::Communicator::destroy() has not been called");
+ }
+ else
+ {
+ System.Console.Error.WriteLine("Ice::Communicator::destroy() has not been called");
+ }
+ }
+ }
+ */
+
+ //
+ // Certain initialization tasks need to be completed after the
+ // constructor.
+ //
+ internal void finishSetup(ref string[] args)
+ {
+ try
+ {
+ instance_.finishSetup(ref args, this);
+ }
+ catch(System.Exception)
+ {
+ instance_.destroy();
+ throw;
+ }
+ }
+
+ //
+ // For use by Util.getInstance()
+ //
+ internal IceInternal.Instance getInstance()
+ {
+ return instance_;
+ }
+
+ private IceInternal.Instance instance_;
+ }
+
+}
diff --git a/csharp/src/Ice/Compare.cs b/csharp/src/Ice/Compare.cs
new file mode 100644
index 00000000000..750ad9d940e
--- /dev/null
+++ b/csharp/src/Ice/Compare.cs
@@ -0,0 +1,185 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+
+namespace Ice
+{
+ public class CollectionComparer
+ {
+ //
+ // Try to compare two collections efficiently, by doing a reference
+ // and count comparison. If equality or inequality can be determined
+ // this way, 'result' contains the outcome of the comparison and the
+ // return value is true. Otherwise, if equality or inequality cannot
+ // be determined this way, 'result' and return value are both false.
+ //
+ private static bool cheapComparison(System.Collections.ICollection c1,
+ System.Collections.ICollection c2,
+ out bool result)
+ {
+ if(object.ReferenceEquals(c1, c2))
+ {
+ result = true;
+ return true; // Equal references means the collections are equal.
+ }
+ if(c1 == null || c2 == null)
+ {
+ result = false;
+ return true; // The references are not equal and one of them is null, so c1 and c2 are not equal.
+ }
+ if(c1.Count != c2.Count)
+ {
+ result = false;
+ return true; // Different number of elements, so c1 and c2 are not equal.
+ }
+ if(c1.Count == 0)
+ {
+ result = true;
+ return true; // Same number of elements, both zero, so c1 and c2 are equal.
+ }
+
+ result = false; // Couldn't get a result cheaply.
+ return false; // c1 and c2 may still be equal, but we have to compare elements to find out.
+ }
+
+ //
+ // Compare two dictionaries for value equality (as implemented by the Equals() method of its elements).
+ //
+ public static bool Equals(System.Collections.IDictionary d1, System.Collections.IDictionary d2)
+ {
+ try
+ {
+ bool result;
+ if(cheapComparison(d1, d2, out result))
+ {
+ return result;
+ }
+
+ System.Collections.ICollection keys1 = d1.Keys;
+ foreach(object k in keys1)
+ {
+ if(d2.Contains(k))
+ {
+ object v1 = d1[k];
+ object v2 = d2[k];
+ if(v1 == null)
+ {
+ if(v2 != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if(!v1.Equals(v2))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ //
+ // Compare two collections for equality (as implemented by the Equals() method of its elements).
+ // Order is significant.
+ //
+ public static bool Equals(System.Collections.ICollection c1, System.Collections.ICollection c2)
+ {
+ try
+ {
+ bool result;
+ if(cheapComparison(c1, c2, out result))
+ {
+ return result;
+ }
+
+ System.Collections.IEnumerator e = c2.GetEnumerator();
+ foreach(object o in c1)
+ {
+ e.MoveNext();
+ if(!Equals(o, e.Current))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+ }
+
+ //
+ // Compare two collections for equality (as implemented by the Equals() method of its elements).
+ // Order is significant.
+ //
+ public static bool Equals(System.Collections.IEnumerable c1, System.Collections.IEnumerable c2)
+ {
+ try
+ {
+ if(object.ReferenceEquals(c1, c2))
+ {
+ return true; // Equal references means the collections are equal.
+ }
+ if(c1 == null || c2 == null)
+ {
+ return false; // The references are not equal and one of them is null, so c1 and c2 are not equal.
+ }
+
+ System.Collections.IEnumerator e1 = c1.GetEnumerator();
+ System.Collections.IEnumerator e2 = c2.GetEnumerator();
+ while(e1.MoveNext())
+ {
+ if(!e2.MoveNext())
+ {
+ return false; // c2 has fewer elements than c1.
+ }
+ if(e1.Current == null)
+ {
+ if(e2.Current != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if(!e1.Current.Equals(e2.Current))
+ {
+ return false;
+ }
+ }
+ }
+ if(e2.MoveNext())
+ {
+ return false; // c2 has more elements than c1.
+ }
+ return true;
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/csharp/src/Ice/ConnectRequestHandler.cs b/csharp/src/Ice/ConnectRequestHandler.cs
new file mode 100644
index 00000000000..67ff6629605
--- /dev/null
+++ b/csharp/src/Ice/ConnectRequestHandler.cs
@@ -0,0 +1,343 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using Ice.Instrumentation;
+
+namespace IceInternal
+{
+ public class ConnectRequestHandler : RequestHandler, Reference.GetConnectionCallback, RouterInfo.AddProxyCallback
+ {
+ public RequestHandler connect(Ice.ObjectPrxHelperBase proxy)
+ {
+ lock(this)
+ {
+ try
+ {
+ if(!initialized())
+ {
+ _proxies.Add(proxy);
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ //
+ // Only throw if the connection didn't get established. If
+ // it died after being established, we allow the caller to
+ // retry the connection establishment by not throwing here.
+ //
+ if(_connection == null)
+ {
+ throw ex;
+ }
+ }
+
+ return proxy.setRequestHandler__(_requestHandler);
+ }
+ }
+
+ public RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler)
+ {
+ return previousHandler == this ? newHandler : this;
+ }
+
+ public bool sendAsyncRequest(ProxyOutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback)
+ {
+ lock(this)
+ {
+ if(!_initialized)
+ {
+ outAsync.cancelable(this); // This will throw if the request is canceled
+ }
+
+ try
+ {
+ if(!initialized())
+ {
+ _requests.AddLast(outAsync);
+ sentCallback = null;
+ return false;
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ throw new RetryException(ex);
+ }
+ }
+ return outAsync.invokeRemote(_connection, _compress, _response, out sentCallback);
+ }
+
+ public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
+ {
+ lock(this)
+ {
+ if(_exception != null)
+ {
+ return; // The request has been notified of a failure already.
+ }
+
+ if(!initialized())
+ {
+ LinkedListNode<ProxyOutgoingAsyncBase> p = _requests.First;
+ while(p != null)
+ {
+ if(p.Value == outAsync)
+ {
+ _requests.Remove(p);
+ Ice.AsyncCallback cb = outAsync.completed(ex);
+ if(cb != null)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ return;
+ }
+ p = p.Next;
+ }
+ Debug.Assert(false); // The request has to be queued if it timed out and we're not initialized yet.
+ }
+ }
+ _connection.asyncRequestCanceled(outAsync, ex);
+ }
+
+ public Reference getReference()
+ {
+ return _reference;
+ }
+
+ public Ice.ConnectionI getConnection()
+ {
+ lock(this)
+ {
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ else
+ {
+ return _connection;
+ }
+ }
+ }
+
+ //
+ // Implementation of Reference.GetConnectionCallback
+ //
+
+ public void setConnection(Ice.ConnectionI connection, bool compress)
+ {
+ lock(this)
+ {
+ Debug.Assert(_exception == null && _connection == null);
+ _connection = connection;
+ _compress = compress;
+ }
+
+ //
+ // If this proxy is for a non-local object, and we are using a router, then
+ // add this proxy to the router info object.
+ //
+ RouterInfo ri = _reference.getRouterInfo();
+ if(ri != null && !ri.addProxy(_proxy, this))
+ {
+ return; // The request handler will be initialized once addProxy returns.
+ }
+
+ //
+ // We can now send the queued requests.
+ //
+ flushRequests();
+ }
+
+ public void setException(Ice.LocalException ex)
+ {
+ lock(this)
+ {
+ Debug.Assert(!_initialized && _exception == null);
+ _exception = ex;
+ _proxies.Clear();
+ _proxy = null; // Break cyclic reference count.
+
+ //
+ // NOTE: remove the request handler *before* notifying the
+ // requests that the connection failed. It's important to ensure
+ // that future invocations will obtain a new connect request
+ // handler once invocations are notified.
+ //
+ try
+ {
+ _reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this);
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ // Ignore
+ }
+
+ foreach(ProxyOutgoingAsyncBase outAsync in _requests)
+ {
+ Ice.AsyncCallback cb = outAsync.completed(_exception);
+ if(cb != null)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ }
+ _requests.Clear();
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ //
+ // Implementation of RouterInfo.AddProxyCallback
+ //
+ public void addedProxy()
+ {
+ //
+ // The proxy was added to the router info, we're now ready to send the
+ // queued requests.
+ //
+ flushRequests();
+ }
+
+ public ConnectRequestHandler(Reference @ref, Ice.ObjectPrx proxy)
+ {
+ _reference = @ref;
+ _response = _reference.getMode() == Reference.Mode.ModeTwoway;
+ _proxy = (Ice.ObjectPrxHelperBase)proxy;
+ _initialized = false;
+ _flushing = false;
+ _requestHandler = this;
+ }
+
+ private bool initialized()
+ {
+ if(_initialized)
+ {
+ Debug.Assert(_connection != null);
+ return true;
+ }
+ else
+ {
+ while(_flushing && _exception == null)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ else
+ {
+ return _initialized;
+ }
+ }
+ }
+
+ private void flushRequests()
+ {
+ lock(this)
+ {
+ Debug.Assert(_connection != null && !_initialized);
+
+ //
+ // We set the _flushing flag to true to prevent any additional queuing. Callers
+ // might block for a little while as the queued requests are being sent but this
+ // shouldn't be an issue as the request sends are non-blocking.
+ //
+ _flushing = true;
+ }
+
+ Ice.LocalException exception = null;
+ foreach(ProxyOutgoingAsyncBase outAsync in _requests)
+ {
+ try
+ {
+ Ice.AsyncCallback sentCallback = null;
+ if(outAsync.invokeRemote(_connection, _compress, _response, out sentCallback))
+ {
+ if(sentCallback != null)
+ {
+ outAsync.invokeSentAsync(sentCallback);
+ }
+ }
+ }
+ catch(RetryException ex)
+ {
+ exception = ex.get();
+
+ // Remove the request handler before retrying.
+ _reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this);
+
+ outAsync.retryException(ex.get());
+ }
+ catch(Ice.LocalException ex)
+ {
+ exception = ex;
+ Ice.AsyncCallback cb = outAsync.completed(ex);
+ if(cb != null)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ }
+ }
+ _requests.Clear();
+
+ //
+ // If we aren't caching the connection, don't bother creating a
+ // connection request handler. Otherwise, update the proxies
+ // request handler to use the more efficient connection request
+ // handler.
+ //
+ if(_reference.getCacheConnection() && exception == null)
+ {
+ _requestHandler = new ConnectionRequestHandler(_reference, _connection, _compress);
+ foreach(Ice.ObjectPrxHelperBase prx in _proxies)
+ {
+ prx.updateRequestHandler__(this, _requestHandler);
+ }
+ }
+
+ lock(this)
+ {
+ Debug.Assert(!_initialized);
+ _exception = exception;
+ _initialized = _exception == null;
+ _flushing = false;
+
+ //
+ // Only remove once all the requests are flushed to
+ // guarantee serialization.
+ //
+ _reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this);
+
+ _proxies.Clear();
+ _proxy = null; // Break cyclic reference count.
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ private Reference _reference;
+ private bool _response;
+
+ private Ice.ObjectPrxHelperBase _proxy;
+ private HashSet<Ice.ObjectPrxHelperBase> _proxies = new HashSet<Ice.ObjectPrxHelperBase>();
+
+ private Ice.ConnectionI _connection;
+ private bool _compress;
+ private Ice.LocalException _exception;
+ private bool _initialized;
+ private bool _flushing;
+
+ private LinkedList<ProxyOutgoingAsyncBase> _requests = new LinkedList<ProxyOutgoingAsyncBase>();
+ private RequestHandler _requestHandler;
+ }
+}
diff --git a/csharp/src/Ice/ConnectionFactory.cs b/csharp/src/Ice/ConnectionFactory.cs
new file mode 100644
index 00000000000..215b64322b1
--- /dev/null
+++ b/csharp/src/Ice/ConnectionFactory.cs
@@ -0,0 +1,1758 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Net.Sockets;
+ using System.Threading;
+ using System.Text;
+ using IceUtilInternal;
+
+ public class MultiDictionary<K, V> : Dictionary<K, ICollection<V>>
+ {
+ public void
+ Add(K key, V value)
+ {
+ ICollection<V> list = null;
+ if(!this.TryGetValue(key, out list))
+ {
+ list = new List<V>();
+ this.Add(key, list);
+ }
+ list.Add(value);
+ }
+
+ public void
+ Remove(K key, V value)
+ {
+ ICollection<V> list = this[key];
+ list.Remove(value);
+ if(list.Count == 0)
+ {
+ this.Remove(key);
+ }
+ }
+ }
+
+ public sealed class OutgoingConnectionFactory
+ {
+ public interface CreateConnectionCallback
+ {
+ void setConnection(Ice.ConnectionI connection, bool compress);
+ void setException(Ice.LocalException ex);
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ return;
+ }
+
+ foreach(ICollection<Ice.ConnectionI> connections in _connections.Values)
+ {
+ foreach(Ice.ConnectionI c in connections)
+ {
+ c.destroy(Ice.ConnectionI.CommunicatorDestroyed);
+ }
+ }
+
+ _destroyed = true;
+ _communicator = null;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public void updateConnectionObservers()
+ {
+ lock(this)
+ {
+ foreach(ICollection<Ice.ConnectionI> connections in _connections.Values)
+ {
+ foreach(Ice.ConnectionI c in connections)
+ {
+ c.updateObserver();
+ }
+ }
+ }
+ }
+
+ public void waitUntilFinished()
+ {
+ Dictionary<Connector, ICollection<Ice.ConnectionI>> connections = null;
+ lock(this)
+ {
+ //
+ // First we wait until the factory is destroyed. We also
+ // wait until there are no pending connections
+ // anymore. Only then we can be sure the _connections
+ // contains all connections.
+ //
+ while(!_destroyed || _pending.Count > 0 || _pendingConnectCount > 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ //
+ // We want to wait until all connections are finished outside the
+ // thread synchronization.
+ //
+ connections = new Dictionary<Connector, ICollection<Ice.ConnectionI>>(_connections);
+ }
+
+ //
+ // Now we wait until the destruction of each connection is finished.
+ //
+ foreach(ICollection<Ice.ConnectionI> cl in connections.Values)
+ {
+ foreach(Ice.ConnectionI c in cl)
+ {
+ c.waitUntilFinished();
+ }
+ }
+
+ lock(this)
+ {
+ // Ensure all the connections are finished and reapable at this point.
+ ICollection<Ice.ConnectionI> cons = _monitor.swapReapedConnections();
+ if(cons != null)
+ {
+ int size = 0;
+ foreach(ICollection<Ice.ConnectionI> cl in _connections.Values)
+ {
+ size += cl.Count;
+ }
+ Debug.Assert(cons.Count == size);
+ _connections.Clear();
+ _connectionsByEndpoint.Clear();
+ }
+ else
+ {
+ Debug.Assert(_connections.Count == 0);
+ Debug.Assert(_connectionsByEndpoint.Count == 0);
+ }
+ _monitor.destroy();
+ }
+ }
+
+
+ public void create(EndpointI[] endpts, bool hasMore, Ice.EndpointSelectionType selType,
+ CreateConnectionCallback callback)
+ {
+ Debug.Assert(endpts.Length > 0);
+
+ //
+ // Apply the overrides.
+ //
+ List<EndpointI> endpoints = applyOverrides(endpts);
+
+ //
+ // Try to find a connection to one of the given endpoints.
+ //
+ try
+ {
+ bool compress;
+ Ice.ConnectionI connection = findConnection(endpoints, out compress);
+ if(connection != null)
+ {
+ callback.setConnection(connection, compress);
+ return;
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ return;
+ }
+
+ ConnectCallback cb = new ConnectCallback(this, endpoints, hasMore, callback, selType);
+ cb.getConnectors();
+ }
+
+ public void setRouterInfo(IceInternal.RouterInfo routerInfo)
+ {
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(routerInfo != null);
+
+ //
+ // Search for connections to the router's client proxy
+ // endpoints, and update the object adapter for such
+ // connections, so that callbacks from the router can be
+ // received over such connections.
+ //
+ Ice.ObjectAdapter adapter = routerInfo.getAdapter();
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ EndpointI[] endpoints = routerInfo.getClientEndpoints();
+ for(int i = 0; i < endpoints.Length; i++)
+ {
+ EndpointI endpoint = endpoints[i];
+
+ //
+ // Modify endpoints with overrides.
+ //
+ if(defaultsAndOverrides.overrideTimeout)
+ {
+ endpoint = endpoint.timeout(defaultsAndOverrides.overrideTimeoutValue);
+ }
+
+ //
+ // The Ice.ConnectionI object does not take the compression flag of
+ // endpoints into account, but instead gets the information
+ // about whether messages should be compressed or not from
+ // other sources. In order to allow connection sharing for
+ // endpoints that differ in the value of the compression flag
+ // only, we always set the compression flag to false here in
+ // this connection factory.
+ //
+ endpoint = endpoint.compress(false);
+
+ foreach(ICollection<Ice.ConnectionI> connections in _connections.Values)
+ {
+ foreach(Ice.ConnectionI connection in connections)
+ {
+ if(connection.endpoint().Equals(endpoint))
+ {
+ connection.setAdapter(adapter);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void removeAdapter(Ice.ObjectAdapter adapter)
+ {
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ return;
+ }
+
+ foreach(ICollection<Ice.ConnectionI> connectionList in _connections.Values)
+ {
+ foreach(Ice.ConnectionI connection in connectionList)
+ {
+ if(connection.getAdapter() == adapter)
+ {
+ connection.setAdapter(null);
+ }
+ }
+ }
+ }
+ }
+
+ public void flushAsyncBatchRequests(CommunicatorFlushBatch outAsync)
+ {
+ ICollection<Ice.ConnectionI> c = new List<Ice.ConnectionI>();
+
+ lock(this)
+ {
+ if(!_destroyed)
+ {
+ foreach(ICollection<Ice.ConnectionI> connectionList in _connections.Values)
+ {
+ foreach(Ice.ConnectionI conn in connectionList)
+ {
+ if(conn.isActiveOrHolding())
+ {
+ c.Add(conn);
+ }
+ }
+ }
+ }
+ }
+
+ foreach(Ice.ConnectionI conn in c)
+ {
+ try
+ {
+ outAsync.flushConnection(conn);
+ }
+ catch(Ice.LocalException)
+ {
+ // Ignore.
+ }
+ }
+ }
+
+ //
+ // Only for use by Instance.
+ //
+ internal OutgoingConnectionFactory(Ice.Communicator communicator, Instance instance)
+ {
+ _communicator = communicator;
+ _instance = instance;
+ _destroyed = false;
+ _monitor = new FactoryACMMonitor(instance, instance.clientACM());
+ _pendingConnectCount = 0;
+ }
+
+ private List<EndpointI> applyOverrides(EndpointI[] endpts)
+ {
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ List<EndpointI> endpoints = new List<EndpointI>();
+ for(int i = 0; i < endpts.Length; i++)
+ {
+ //
+ // Modify endpoints with overrides.
+ //
+ if(defaultsAndOverrides.overrideTimeout)
+ {
+ endpoints.Add(endpts[i].timeout(defaultsAndOverrides.overrideTimeoutValue));
+ }
+ else
+ {
+ endpoints.Add(endpts[i]);
+ }
+ }
+
+ return endpoints;
+ }
+
+ private Ice.ConnectionI findConnection(List<EndpointI> endpoints, out bool compress)
+ {
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ Debug.Assert(endpoints.Count > 0);
+
+ foreach(EndpointI endpoint in endpoints)
+ {
+ ICollection<Ice.ConnectionI> connectionList = null;
+ if(!_connectionsByEndpoint.TryGetValue(endpoint, out connectionList))
+ {
+ continue;
+ }
+
+ foreach(Ice.ConnectionI connection in connectionList)
+ {
+ if(connection.isActiveOrHolding()) // Don't return destroyed or unvalidated connections
+ {
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ compress = defaultsAndOverrides.overrideCompressValue;
+ }
+ else
+ {
+ compress = endpoint.compress();
+ }
+ return connection;
+ }
+ }
+ }
+
+ compress = false; // Satisfy the compiler
+ return null;
+ }
+ }
+
+ //
+ // Must be called while synchronized.
+ //
+ private Ice.ConnectionI findConnection(List<ConnectorInfo> connectors, out bool compress)
+ {
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ foreach(ConnectorInfo ci in connectors)
+ {
+ if(_pending.ContainsKey(ci.connector))
+ {
+ continue;
+ }
+
+ ICollection<Ice.ConnectionI> connectionList = null;
+ if(!_connections.TryGetValue(ci.connector, out connectionList))
+ {
+ continue;
+ }
+
+ foreach(Ice.ConnectionI connection in connectionList)
+ {
+ if(connection.isActiveOrHolding()) // Don't return destroyed or un-validated connections
+ {
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ compress = defaultsAndOverrides.overrideCompressValue;
+ }
+ else
+ {
+ compress = ci.endpoint.compress();
+ }
+ return connection;
+ }
+ }
+ }
+
+ compress = false; // Satisfy the compiler
+ return null;
+ }
+
+ internal void incPendingConnectCount()
+ {
+ //
+ // Keep track of the number of pending connects. The outgoing connection factory
+ // waitUntilFinished() method waits for all the pending connects to terminate before
+ // to return. This ensures that the communicator client thread pool isn't destroyed
+ // too soon and will still be available to execute the ice_exception() callbacks for
+ // the asynchronous requests waiting on a connection to be established.
+ //
+
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+ ++_pendingConnectCount;
+ }
+ }
+
+ internal void decPendingConnectCount()
+ {
+ lock(this)
+ {
+ --_pendingConnectCount;
+ Debug.Assert(_pendingConnectCount >= 0);
+ if(_destroyed && _pendingConnectCount == 0)
+ {
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+ }
+
+ private Ice.ConnectionI getConnection(List<ConnectorInfo> connectors, ConnectCallback cb, out bool compress)
+ {
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ //
+ // Reap closed connections
+ //
+ ICollection<Ice.ConnectionI> cons = _monitor.swapReapedConnections();
+ if(cons != null)
+ {
+ foreach(Ice.ConnectionI c in cons)
+ {
+ _connections.Remove(c.connector(), c);
+ _connectionsByEndpoint.Remove(c.endpoint(), c);
+ _connectionsByEndpoint.Remove(c.endpoint().compress(true), c);
+ }
+ }
+
+ //
+ // Try to get the connection. We may need to wait for other threads to
+ // finish if one of them is currently establishing a connection to one
+ // of our connectors.
+ //
+ while(true)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ //
+ // Search for a matching connection. If we find one, we're done.
+ //
+ Ice.ConnectionI connection = findConnection(connectors, out compress);
+ if(connection != null)
+ {
+ return connection;
+ }
+
+ if(addToPending(cb, connectors))
+ {
+ //
+ // If a callback is not specified we wait until another thread notifies us about a
+ // change to the pending list. Otherwise, if a callback is provided we're done:
+ // when the pending list changes the callback will be notified and will try to
+ // get the connection again.
+ //
+ if(cb == null)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ //
+ // If no thread is currently establishing a connection to one of our connectors,
+ // we get out of this loop and start the connection establishment to one of the
+ // given connectors.
+ //
+ break;
+ }
+ }
+ }
+
+ //
+ // At this point, we're responsible for establishing the connection to one of
+ // the given connectors. If it's a non-blocking connect, calling nextConnector
+ // will start the connection establishment. Otherwise, we return null to get
+ // the caller to establish the connection.
+ //
+ if(cb != null)
+ {
+ cb.nextConnector();
+ }
+
+ compress = false; // Satisfy the compiler
+ return null;
+ }
+
+ private Ice.ConnectionI createConnection(Transceiver transceiver, ConnectorInfo ci)
+ {
+ lock(this)
+ {
+ Debug.Assert(_pending.ContainsKey(ci.connector) && transceiver != null);
+
+ //
+ // Create and add the connection to the connection map. Adding the connection to the map
+ // is necessary to support the interruption of the connection initialization and validation
+ // in case the communicator is destroyed.
+ //
+ Ice.ConnectionI connection;
+ try
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ connection = new Ice.ConnectionI(_communicator, _instance, _monitor, transceiver, ci.connector,
+ ci.endpoint.compress(false), null);
+ }
+ catch(Ice.LocalException)
+ {
+ try
+ {
+ transceiver.close();
+ }
+ catch(Ice.LocalException)
+ {
+ // Ignore
+ }
+ throw;
+ }
+
+ _connections.Add(ci.connector, connection);
+ _connectionsByEndpoint.Add(connection.endpoint(), connection);
+ _connectionsByEndpoint.Add(connection.endpoint().compress(true), connection);
+ return connection;
+ }
+ }
+
+ private void finishGetConnection(List<ConnectorInfo> connectors,
+ ConnectorInfo ci,
+ Ice.ConnectionI connection,
+ ConnectCallback cb)
+ {
+ HashSet<ConnectCallback> connectionCallbacks = new HashSet<ConnectCallback>();
+ if(cb != null)
+ {
+ connectionCallbacks.Add(cb);
+ }
+
+ HashSet<ConnectCallback> callbacks = new HashSet<ConnectCallback>();
+ lock(this)
+ {
+ foreach(ConnectorInfo c in connectors)
+ {
+ HashSet<ConnectCallback> s = null;
+ if(_pending.TryGetValue(c.connector, out s))
+ {
+ foreach(ConnectCallback cc in s)
+ {
+ if(cc.hasConnector(ci))
+ {
+ connectionCallbacks.Add(cc);
+ }
+ else
+ {
+ callbacks.Add(cc);
+ }
+ }
+ _pending.Remove(c.connector);
+ }
+ }
+
+ foreach(ConnectCallback cc in connectionCallbacks)
+ {
+ cc.removeFromPending();
+ callbacks.Remove(cc);
+ }
+ foreach(ConnectCallback cc in callbacks)
+ {
+ cc.removeFromPending();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+
+ bool compress;
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ compress = defaultsAndOverrides.overrideCompressValue;
+ }
+ else
+ {
+ compress = ci.endpoint.compress();
+ }
+
+ foreach(ConnectCallback cc in callbacks)
+ {
+ cc.getConnection();
+ }
+ foreach(ConnectCallback cc in connectionCallbacks)
+ {
+ cc.setConnection(connection, compress);
+ }
+ }
+
+ private void finishGetConnection(List<ConnectorInfo> connectors, Ice.LocalException ex, ConnectCallback cb)
+ {
+ HashSet<ConnectCallback> failedCallbacks = new HashSet<ConnectCallback>();
+ if(cb != null)
+ {
+ failedCallbacks.Add(cb);
+ }
+
+ HashSet<ConnectCallback> callbacks = new HashSet<ConnectCallback>();
+ lock(this)
+ {
+ foreach(ConnectorInfo c in connectors)
+ {
+ HashSet<ConnectCallback> s = null;
+ if(_pending.TryGetValue(c.connector, out s))
+ {
+ foreach(ConnectCallback cc in s)
+ {
+ if(cc.removeConnectors(connectors))
+ {
+ failedCallbacks.Add(cc);
+ }
+ else
+ {
+ callbacks.Add(cc);
+ }
+ }
+ _pending.Remove(c.connector);
+ }
+ }
+
+ foreach(ConnectCallback cc in callbacks)
+ {
+ Debug.Assert(!failedCallbacks.Contains(cc));
+ cc.removeFromPending();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+
+ foreach(ConnectCallback cc in callbacks)
+ {
+ cc.getConnection();
+ }
+ foreach(ConnectCallback cc in failedCallbacks)
+ {
+ cc.setException(ex);
+ }
+ }
+
+ private void handleConnectionException(Ice.LocalException ex, bool hasMore)
+ {
+ TraceLevels traceLevels = _instance.traceLevels();
+ if(traceLevels.retry >= 2)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("connection to endpoint failed");
+ if(ex is Ice.CommunicatorDestroyedException)
+ {
+ s.Append("\n");
+ }
+ else
+ {
+ if(hasMore)
+ {
+ s.Append(", trying next endpoint\n");
+ }
+ else
+ {
+ s.Append(" and no more endpoints to try\n");
+ }
+ }
+ s.Append(ex);
+ _instance.initializationData().logger.trace(traceLevels.retryCat, s.ToString());
+ }
+ }
+
+ private bool
+ addToPending(ConnectCallback cb, List<ConnectorInfo> connectors)
+ {
+ //
+ // Add the callback to each connector pending list.
+ //
+ bool found = false;
+ foreach(ConnectorInfo ci in connectors)
+ {
+ HashSet<ConnectCallback> cbs = null;
+ if(_pending.TryGetValue(ci.connector, out cbs))
+ {
+ found = true;
+ if(cb != null)
+ {
+ cbs.Add(cb); // Add the callback to each pending connector.
+ }
+ }
+ }
+
+ if(found)
+ {
+ return true;
+ }
+
+ //
+ // If there's no pending connection for the given connectors, we're
+ // responsible for its establishment. We add empty pending lists,
+ // other callbacks to the same connectors will be queued.
+ //
+ foreach(ConnectorInfo ci in connectors)
+ {
+ if(!_pending.ContainsKey(ci.connector))
+ {
+ _pending.Add(ci.connector, new HashSet<ConnectCallback>());
+ }
+ }
+ return false;
+ }
+
+ private void
+ removeFromPending(ConnectCallback cb, List<ConnectorInfo> connectors)
+ {
+ foreach(ConnectorInfo ci in connectors)
+ {
+ HashSet<ConnectCallback> cbs = null;
+ if(_pending.TryGetValue(ci.connector, out cbs))
+ {
+ cbs.Remove(cb);
+ }
+ }
+ }
+
+ internal void handleException(Ice.LocalException ex, bool hasMore)
+ {
+ TraceLevels traceLevels = _instance.traceLevels();
+ if(traceLevels.retry >= 2)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't resolve endpoint host");
+ if(ex is Ice.CommunicatorDestroyedException)
+ {
+ s.Append("\n");
+ }
+ else
+ {
+ if(hasMore)
+ {
+ s.Append(", trying next endpoint\n");
+ }
+ else
+ {
+ s.Append(" and no more endpoints to try\n");
+ }
+ }
+ s.Append(ex);
+ _instance.initializationData().logger.trace(traceLevels.retryCat, s.ToString());
+ }
+ }
+
+ private class ConnectorInfo
+ {
+ internal ConnectorInfo(Connector c, EndpointI e)
+ {
+ connector = c;
+ endpoint = e;
+ }
+
+ public override bool Equals(object obj)
+ {
+ ConnectorInfo r = (ConnectorInfo)obj;
+ return connector.Equals(r.connector);
+ }
+
+ public override int GetHashCode()
+ {
+ return connector.GetHashCode();
+ }
+
+ public Connector connector;
+ public EndpointI endpoint;
+ }
+
+ private class ConnectCallback : Ice.ConnectionI.StartCallback, EndpointI_connectors
+ {
+ internal ConnectCallback(OutgoingConnectionFactory f, List<EndpointI> endpoints, bool more,
+ CreateConnectionCallback cb, Ice.EndpointSelectionType selType)
+ {
+ _factory = f;
+ _endpoints = endpoints;
+ _hasMore = more;
+ _callback = cb;
+ _selType = selType;
+ _endpointsIter = 0;
+ }
+
+ //
+ // Methods from ConnectionI.StartCallback
+ //
+ public void connectionStartCompleted(Ice.ConnectionI connection)
+ {
+ if(_observer != null)
+ {
+ _observer.detach();
+ }
+ connection.activate();
+ _factory.finishGetConnection(_connectors, _current, connection, this);
+ }
+
+ public void connectionStartFailed(Ice.ConnectionI connection, Ice.LocalException ex)
+ {
+ if(_observer != null)
+ {
+ _observer.failed(ex.ice_name());
+ _observer.detach();
+ }
+ _factory.handleConnectionException(ex, _hasMore || _iter < _connectors.Count);
+ if(ex is Ice.CommunicatorDestroyedException) // No need to continue.
+ {
+ _factory.finishGetConnection(_connectors, ex, this);
+ }
+ else if(_iter < _connectors.Count) // Try the next connector.
+ {
+ nextConnector();
+ }
+ else
+ {
+ _factory.finishGetConnection(_connectors, ex, this);
+ }
+ }
+
+ //
+ // Methods from EndpointI_connectors
+ //
+ public void connectors(List<Connector> cons)
+ {
+ foreach(Connector connector in cons)
+ {
+ _connectors.Add(new ConnectorInfo(connector, _currentEndpoint));
+ }
+
+ if(_endpointsIter < _endpoints.Count)
+ {
+ nextEndpoint();
+ }
+ else
+ {
+ Debug.Assert(_connectors.Count > 0);
+
+ //
+ // We now have all the connectors for the given endpoints. We can try to obtain the
+ // connection.
+ //
+ _iter = 0;
+ getConnection();
+ }
+ }
+
+ public void exception(Ice.LocalException ex)
+ {
+ _factory.handleException(ex, _hasMore || _endpointsIter < _endpoints.Count);
+ if(_endpointsIter < _endpoints.Count)
+ {
+ nextEndpoint();
+ }
+ else if(_connectors.Count > 0)
+ {
+ //
+ // We now have all the connectors for the given endpoints. We can try to obtain the
+ // connection.
+ //
+ _iter = 0;
+ getConnection();
+ }
+ else
+ {
+ _callback.setException(ex);
+ _factory.decPendingConnectCount(); // Must be called last.
+ }
+ }
+
+ public void setConnection(Ice.ConnectionI connection, bool compress)
+ {
+ //
+ // Callback from the factory: the connection to one of the callback
+ // connectors has been established.
+ //
+ _callback.setConnection(connection, compress);
+ _factory.decPendingConnectCount(); // Must be called last.
+ }
+
+ public void setException(Ice.LocalException ex)
+ {
+ //
+ // Callback from the factory: connection establishment failed.
+ //
+ _callback.setException(ex);
+ _factory.decPendingConnectCount(); // Must be called last.
+ }
+
+ public bool hasConnector(ConnectorInfo ci)
+ {
+ return _connectors.Contains(ci);
+ }
+
+ public bool removeConnectors(List<ConnectorInfo> connectors)
+ {
+ foreach(ConnectorInfo ci in connectors)
+ {
+ while(_connectors.Remove(ci)); // Remove all of them.
+ }
+ return _connectors.Count == 0;
+ }
+
+ public void removeFromPending()
+ {
+ _factory.removeFromPending(this, _connectors);
+ }
+
+ public void getConnectors()
+ {
+ try
+ {
+ //
+ // Notify the factory that there's an async connect pending. This is necessary
+ // to prevent the outgoing connection factory to be destroyed before all the
+ // pending asynchronous connects are finished.
+ //
+ _factory.incPendingConnectCount();
+ }
+ catch(Ice.LocalException ex)
+ {
+ _callback.setException(ex);
+ return;
+ }
+
+ nextEndpoint();
+ }
+
+ void nextEndpoint()
+ {
+ try
+ {
+ Debug.Assert(_endpointsIter < _endpoints.Count);
+ _currentEndpoint = _endpoints[_endpointsIter++];
+ _currentEndpoint.connectors_async(_selType, this);
+ }
+ catch(Ice.LocalException ex)
+ {
+ exception(ex);
+ }
+ }
+
+ internal void getConnection()
+ {
+ try
+ {
+ //
+ // If all the connectors have been created, we ask the factory to get a
+ // connection.
+ //
+ bool compress;
+ Ice.ConnectionI connection = _factory.getConnection(_connectors, this, out compress);
+ if(connection == null)
+ {
+ //
+ // A null return value from getConnection indicates that the connection
+ // is being established and that everthing has been done to ensure that
+ // the callback will be notified when the connection establishment is
+ // done.
+ //
+ return;
+ }
+
+ _callback.setConnection(connection, compress);
+ _factory.decPendingConnectCount(); // Must be called last.
+ }
+ catch(Ice.LocalException ex)
+ {
+ _callback.setException(ex);
+ _factory.decPendingConnectCount(); // Must be called last.
+ }
+ }
+
+ internal void nextConnector()
+ {
+ Ice.ConnectionI connection = null;
+ try
+ {
+ Debug.Assert(_iter < _connectors.Count);
+ _current = _connectors[_iter++];
+
+ Ice.Instrumentation.CommunicatorObserver obsv = _factory._instance.initializationData().observer;
+ if(obsv != null)
+ {
+ _observer = obsv.getConnectionEstablishmentObserver(_current.endpoint,
+ _current.connector.ToString());
+ if(_observer != null)
+ {
+ _observer.attach();
+ }
+ }
+
+ if(_factory._instance.traceLevels().network >= 2)
+ {
+ StringBuilder s = new StringBuilder("trying to establish ");
+ s.Append(_current.endpoint.protocol());
+ s.Append(" connection to ");
+ s.Append(_current.connector.ToString());
+ _factory._instance.initializationData().logger.trace(
+ _factory._instance.traceLevels().networkCat, s.ToString());
+ }
+
+ connection = _factory.createConnection(_current.connector.connect(), _current);
+ connection.start(this);
+ }
+ catch(Ice.LocalException ex)
+ {
+ if(_factory._instance.traceLevels().network >= 2)
+ {
+ StringBuilder s = new StringBuilder("failed to establish ");
+ s.Append(_current.endpoint.protocol());
+ s.Append(" connection to ");
+ s.Append(_current.connector.ToString());
+ s.Append(ex);
+ _factory._instance.initializationData().logger.trace(
+ _factory._instance.traceLevels().networkCat, s.ToString());
+ }
+
+ connectionStartFailed(connection, ex);
+ }
+ }
+
+ private OutgoingConnectionFactory _factory;
+ private bool _hasMore;
+ private CreateConnectionCallback _callback;
+ private List<EndpointI> _endpoints;
+ private Ice.EndpointSelectionType _selType;
+ private int _endpointsIter;
+ private EndpointI _currentEndpoint;
+ private List<ConnectorInfo> _connectors = new List<ConnectorInfo>();
+ private int _iter;
+ private ConnectorInfo _current;
+ private Ice.Instrumentation.Observer _observer;
+ }
+
+ private Ice.Communicator _communicator;
+ private readonly Instance _instance;
+ private FactoryACMMonitor _monitor;
+ private bool _destroyed;
+
+ private MultiDictionary<Connector, Ice.ConnectionI> _connections =
+ new MultiDictionary<Connector, Ice.ConnectionI>();
+ private MultiDictionary<EndpointI, Ice.ConnectionI> _connectionsByEndpoint =
+ new MultiDictionary<EndpointI, Ice.ConnectionI>();
+ private Dictionary<Connector, HashSet<ConnectCallback>> _pending =
+ new Dictionary<Connector, HashSet<ConnectCallback>>();
+ private int _pendingConnectCount;
+ }
+
+ public sealed class IncomingConnectionFactory : EventHandler, Ice.ConnectionI.StartCallback
+ {
+ public void activate()
+ {
+ lock(this)
+ {
+ setState(StateActive);
+ }
+ }
+
+ public void hold()
+ {
+ lock(this)
+ {
+ setState(StateHolding);
+ }
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ setState(StateClosed);
+ }
+ }
+
+ public void updateConnectionObservers()
+ {
+ lock(this)
+ {
+ foreach(Ice.ConnectionI connection in _connections)
+ {
+ connection.updateObserver();
+ }
+ }
+ }
+
+ public void waitUntilHolding()
+ {
+ ICollection<Ice.ConnectionI> connections;
+
+ lock(this)
+ {
+ //
+ // First we wait until the connection factory itself is in
+ // holding state.
+ //
+ while(_state < StateHolding)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ //
+ // We want to wait until all connections are in holding state
+ // outside the thread synchronization.
+ //
+ connections = new List<Ice.ConnectionI>(_connections);
+ }
+
+ //
+ // Now we wait until each connection is in holding state.
+ //
+ foreach(Ice.ConnectionI connection in connections)
+ {
+ connection.waitUntilHolding();
+ }
+ }
+
+ public void waitUntilFinished()
+ {
+ ICollection<Ice.ConnectionI> connections = null;
+
+ lock(this)
+ {
+ //
+ // First we wait until the factory is destroyed. If we are using
+ // an acceptor, we also wait for it to be closed.
+ //
+ while(_state != StateFinished)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ //
+ // Clear the OA. See bug 1673 for the details of why this is necessary.
+ //
+ _adapter = null;
+
+ //
+ // We want to wait until all connections are finished outside the
+ // thread synchronization.
+ //
+ connections = new List<Ice.ConnectionI>(_connections);
+ }
+
+ foreach(Ice.ConnectionI connection in connections)
+ {
+ connection.waitUntilFinished();
+ }
+
+ lock(this)
+ {
+ if(_transceiver != null)
+ {
+ Debug.Assert(_connections.Count <= 1); // The connection isn't monitored or reaped.
+ }
+ else
+ {
+ // Ensure all the connections are finished and reapable at this point.
+ ICollection<Ice.ConnectionI> cons = _monitor.swapReapedConnections();
+ Debug.Assert((cons == null ? 0 : cons.Count) == _connections.Count);
+ if(cons != null)
+ {
+ cons.Clear();
+ }
+ }
+ _connections.Clear();
+ _monitor.destroy();
+ }
+ }
+
+ public EndpointI endpoint()
+ {
+ // No mutex protection necessary, _endpoint is immutable.
+ return _endpoint;
+ }
+
+ public ICollection<Ice.ConnectionI> connections()
+ {
+ lock(this)
+ {
+ ICollection<Ice.ConnectionI> connections = new List<Ice.ConnectionI>();
+
+ //
+ // Only copy connections which have not been destroyed.
+ //
+ foreach(Ice.ConnectionI connection in _connections)
+ {
+ if(connection.isActiveOrHolding())
+ {
+ connections.Add(connection);
+ }
+ }
+
+ return connections;
+ }
+ }
+
+ public void flushAsyncBatchRequests(CommunicatorFlushBatch outAsync)
+ {
+ //
+ // connections() is synchronized, no need to synchronize here.
+ //
+ foreach(Ice.ConnectionI connection in connections())
+ {
+ try
+ {
+ outAsync.flushConnection(connection);
+ }
+ catch(Ice.LocalException)
+ {
+ // Ignore.
+ }
+ }
+ }
+
+ //
+ // Operations from EventHandler.
+ //
+ public override bool startAsync(int operation, AsyncCallback callback, ref bool completedSynchronously)
+ {
+ if(_state >= StateClosed)
+ {
+ return false;
+ }
+
+ Debug.Assert(_acceptor != null);
+ try
+ {
+ completedSynchronously = _acceptor.startAccept(callback, this);
+ }
+ catch(Ice.LocalException ex)
+ {
+ string s = "can't accept connections:\n" + ex + '\n' + _acceptor.ToString();
+ try
+ {
+ _instance.initializationData().logger.error(s);
+ }
+ finally
+ {
+#if !COMPACT && !SILVERLIGHT
+ System.Environment.FailFast(s);
+#endif
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public override bool finishAsync(int unused)
+ {
+ try
+ {
+ _acceptor.finishAccept();
+ }
+ catch(Ice.LocalException ex)
+ {
+ if(Network.noMoreFds(ex.InnerException))
+ {
+ string s = "can't accept more connections:\n" + ex + '\n' + _acceptor.ToString();
+ try
+ {
+ _instance.initializationData().logger.error(s);
+ }
+ finally
+ {
+#if !COMPACT && !SILVERLIGHT
+ System.Environment.FailFast(s);
+#endif
+ }
+ return false;
+ }
+ else
+ {
+ string s = "couldn't accept connection:\n" + ex + '\n' + _acceptor.ToString();
+ _instance.initializationData().logger.error(s);
+ return false;
+ }
+ }
+ return _state < StateClosed;
+ }
+
+ public override void message(ref ThreadPoolCurrent current)
+ {
+ Ice.ConnectionI connection = null;
+
+ ThreadPoolMessage msg = new ThreadPoolMessage(this);
+
+ lock(this)
+ {
+ if(!msg.startIOScope(ref current))
+ {
+ return;
+ }
+
+ try
+ {
+ if(_state >= StateClosed)
+ {
+ return;
+ }
+ else if(_state == StateHolding)
+ {
+ return;
+ }
+
+ //
+ // Reap closed connections
+ //
+ ICollection<Ice.ConnectionI> cons = _monitor.swapReapedConnections();
+ if(cons != null)
+ {
+ foreach(Ice.ConnectionI c in cons)
+ {
+ _connections.Remove(c);
+ }
+ }
+
+ //
+ // Now accept a new connection.
+ //
+ Transceiver transceiver = null;
+ try
+ {
+ transceiver = _acceptor.accept();
+
+ if(_instance.traceLevels().network >= 2)
+ {
+ StringBuilder s = new StringBuilder("trying to accept ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connection\n");
+ s.Append(transceiver.ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+ }
+ catch(Ice.SocketException ex)
+ {
+ if(Network.noMoreFds(ex.InnerException))
+ {
+ string s = "can't accept more connections:\n" + ex + '\n' + _acceptor.ToString();
+ try
+ {
+ _instance.initializationData().logger.error(s);
+ }
+ finally
+ {
+#if !COMPACT && !SILVERLIGHT
+ System.Environment.FailFast(s);
+#endif
+ }
+ }
+
+ // Ignore socket exceptions.
+ return;
+ }
+ catch(Ice.LocalException ex)
+ {
+ // Warn about other Ice local exceptions.
+ if(_warn)
+ {
+ warning(ex);
+ }
+ return;
+ }
+
+ Debug.Assert(transceiver != null);
+
+ try
+ {
+ connection = new Ice.ConnectionI(_adapter.getCommunicator(), _instance, _monitor, transceiver,
+ null, _endpoint, _adapter);
+ }
+ catch(Ice.LocalException ex)
+ {
+ try
+ {
+ transceiver.close();
+ }
+ catch(Ice.LocalException)
+ {
+ // Ignore
+ }
+
+ if(_warn)
+ {
+ warning(ex);
+ }
+ return;
+ }
+
+ _connections.Add(connection);
+ }
+ finally
+ {
+ msg.finishIOScope(ref current);
+ }
+ }
+
+ Debug.Assert(connection != null);
+ connection.start(this);
+ }
+
+ public override void finished(ref ThreadPoolCurrent current)
+ {
+ lock(this)
+ {
+ Debug.Assert(_state == StateClosed);
+ setState(StateFinished);
+ }
+ }
+
+ public override string ToString()
+ {
+ if(_transceiver != null)
+ {
+ return _transceiver.ToString();
+ }
+ return _acceptor.ToString();
+ }
+
+ //
+ // Operations from ConnectionI.StartCallback
+ //
+ public void connectionStartCompleted(Ice.ConnectionI connection)
+ {
+ lock(this)
+ {
+ //
+ // Initially, connections are in the holding state. If the factory is active
+ // we activate the connection.
+ //
+ if(_state == StateActive)
+ {
+ connection.activate();
+ }
+ }
+ }
+
+ public void connectionStartFailed(Ice.ConnectionI connection, Ice.LocalException ex)
+ {
+ lock(this)
+ {
+ if(_state >= StateClosed)
+ {
+ return;
+ }
+
+ //
+ // Do not warn about connection exceptions here. The connection is not yet validated.
+ //
+ }
+ }
+
+ public IncomingConnectionFactory(Instance instance, EndpointI endpoint, Ice.ObjectAdapterI adapter)
+ {
+ _instance = instance;
+ _endpoint = endpoint;
+ _adapter = adapter;
+ _warn = _instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Connections") > 0;
+ _connections = new HashSet<Ice.ConnectionI>();
+ _state = StateHolding;
+ _monitor = new FactoryACMMonitor(instance, ((Ice.ObjectAdapterI)adapter).getACM());
+
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideTimeout)
+ {
+ _endpoint = _endpoint.timeout(defaultsAndOverrides.overrideTimeoutValue);
+ }
+
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ _endpoint = _endpoint.compress(defaultsAndOverrides.overrideCompressValue);
+ }
+
+ try
+ {
+ _transceiver = _endpoint.transceiver();
+ if(_transceiver != null)
+ {
+ if(_instance.traceLevels().network >= 2)
+ {
+ StringBuilder s = new StringBuilder("attempting to bind to ");
+ s.Append(_endpoint.protocol());
+ s.Append(" socket\n");
+ s.Append(_transceiver.ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+ _endpoint = _transceiver.bind();
+
+ Ice.ConnectionI connection = new Ice.ConnectionI(_adapter.getCommunicator(), _instance, null,
+ _transceiver, null, _endpoint, _adapter);
+ connection.startAndWait();
+ _connections.Add(connection);
+ }
+ else
+ {
+ createAcceptor();
+ }
+ }
+ catch(System.Exception ex)
+ {
+ //
+ // Clean up.
+ //
+ if(_transceiver != null)
+ {
+ try
+ {
+ _transceiver.close();
+ }
+ catch(Ice.LocalException)
+ {
+ // Ignore
+ }
+ }
+
+ _state = StateFinished;
+ _monitor.destroy();
+ _connections.Clear();
+
+ if(ex is Ice.LocalException)
+ {
+ throw;
+ }
+ else
+ {
+ throw new Ice.SyscallException(ex);
+ }
+ }
+ }
+
+ private const int StateActive = 0;
+ private const int StateHolding = 1;
+ private const int StateClosed = 2;
+ private const int StateFinished = 3;
+
+ private void setState(int state)
+ {
+ if(_state == state) // Don't switch twice.
+ {
+ return;
+ }
+
+ switch (state)
+ {
+ case StateActive:
+ {
+ if(_state != StateHolding) // Can only switch from holding to active.
+ {
+ return;
+ }
+ if(_acceptor != null)
+ {
+ if(_instance.traceLevels().network >= 1)
+ {
+ StringBuilder s = new StringBuilder("accepting ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connections at ");
+ s.Append(_acceptor.ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat,
+ s.ToString());
+ }
+ _adapter.getThreadPool().register(this, SocketOperation.Read);
+ }
+
+ foreach(Ice.ConnectionI connection in _connections)
+ {
+ connection.activate();
+ }
+ break;
+ }
+
+ case StateHolding:
+ {
+ if(_state != StateActive) // Can only switch from active to holding.
+ {
+ return;
+ }
+ if(_acceptor != null)
+ {
+ if(_instance.traceLevels().network >= 1)
+ {
+ StringBuilder s = new StringBuilder("holding ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connections at ");
+ s.Append(_acceptor.ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat,
+ s.ToString());
+ }
+ _adapter.getThreadPool().unregister(this, SocketOperation.Read);
+ }
+
+ foreach(Ice.ConnectionI connection in _connections)
+ {
+ connection.hold();
+ }
+ break;
+ }
+
+ case StateClosed:
+ {
+ if(_acceptor != null)
+ {
+ _adapter.getThreadPool().finish(this);
+ closeAcceptor();
+ }
+ else
+ {
+ state = StateFinished;
+ }
+
+ foreach(Ice.ConnectionI connection in _connections)
+ {
+ connection.destroy(Ice.ConnectionI.ObjectAdapterDeactivated);
+ }
+ break;
+ }
+
+ case StateFinished:
+ {
+ Debug.Assert(_state == StateClosed);
+ break;
+ }
+ }
+
+ _state = state;
+ System.Threading.Monitor.PulseAll(this);
+ }
+
+ private void createAcceptor()
+ {
+ try
+ {
+ _acceptor = _endpoint.acceptor(_adapter.getName());
+ Debug.Assert(_acceptor != null);
+
+ if(_instance.traceLevels().network >= 2)
+ {
+ StringBuilder s = new StringBuilder("attempting to bind to ");
+ s.Append(_endpoint.protocol());
+ s.Append(" socket ");
+ s.Append(_acceptor.ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+ _endpoint = _acceptor.listen();
+
+ if(_instance.traceLevels().network >= 1)
+ {
+ StringBuilder s = new StringBuilder("listening for ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connections\n");
+ s.Append(_acceptor.toDetailedString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+
+ _adapter.getThreadPool().initialize(this);
+
+ if(_state == StateActive)
+ {
+ _adapter.getThreadPool().unregister(this, SocketOperation.Read);
+ }
+ }
+ catch(SystemException ex)
+ {
+ if(_acceptor != null)
+ {
+ _acceptor.close();
+ }
+ throw ex;
+ }
+ }
+
+ private void closeAcceptor()
+ {
+ if(_instance.traceLevels().network >= 1)
+ {
+ StringBuilder s = new StringBuilder("stopping to accept ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connections at ");
+ s.Append(_acceptor.ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+
+ _acceptor.close();
+ }
+
+ private void warning(Ice.LocalException ex)
+ {
+ _instance.initializationData().logger.warning("connection exception:\n" + ex + '\n' +
+ _acceptor.ToString());
+ }
+
+ private Instance _instance;
+ private FactoryACMMonitor _monitor;
+
+ private Acceptor _acceptor;
+ private readonly Transceiver _transceiver;
+ private EndpointI _endpoint;
+
+ private Ice.ObjectAdapterI _adapter;
+
+ private readonly bool _warn;
+
+ private HashSet<Ice.ConnectionI> _connections;
+
+ private int _state;
+ }
+
+}
diff --git a/csharp/src/Ice/ConnectionI.cs b/csharp/src/Ice/ConnectionI.cs
new file mode 100644
index 00000000000..581536eade7
--- /dev/null
+++ b/csharp/src/Ice/ConnectionI.cs
@@ -0,0 +1,2990 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Text;
+ using System.Threading;
+ using Ice.Instrumentation;
+
+ public sealed class ConnectionI :
+ IceInternal.EventHandler, IceInternal.ResponseHandler, IceInternal.CancellationHandler, Connection
+ {
+ public interface StartCallback
+ {
+ void connectionStartCompleted(ConnectionI connection);
+ void connectionStartFailed(ConnectionI connection, LocalException ex);
+ }
+
+ private class TimeoutCallback : IceInternal.TimerTask
+ {
+ public TimeoutCallback(ConnectionI connection)
+ {
+ _connection = connection;
+ }
+
+ public void runTimerTask()
+ {
+ _connection.timedOut();
+ }
+
+ private Ice.ConnectionI _connection;
+ }
+
+ public void start(StartCallback callback)
+ {
+ try
+ {
+ lock(this)
+ {
+ //
+ // The connection might already be closed if the communicator was destroyed.
+ //
+ if(_state >= StateClosed)
+ {
+ Debug.Assert(_exception != null);
+ throw _exception;
+ }
+
+ if(!initialize(IceInternal.SocketOperation.None) || !validate(IceInternal.SocketOperation.None))
+ {
+ _startCallback = callback;
+ return;
+ }
+
+ //
+ // We start out in holding state.
+ //
+ setState(StateHolding);
+ }
+ }
+ catch(LocalException ex)
+ {
+ exception(ex);
+ callback.connectionStartFailed(this, _exception);
+ return;
+ }
+
+ callback.connectionStartCompleted(this);
+ }
+
+ public void startAndWait()
+ {
+ try
+ {
+ lock(this)
+ {
+ //
+ // The connection might already be closed if the communicator was destroyed.
+ //
+ if(_state >= StateClosed)
+ {
+ Debug.Assert(_exception != null);
+ throw _exception;
+ }
+
+ if(!initialize(IceInternal.SocketOperation.None) || !validate(IceInternal.SocketOperation.None))
+ {
+ //
+ // Wait for the connection to be validated.
+ //
+ while(_state <= StateNotValidated)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ if(_state >= StateClosing)
+ {
+ Debug.Assert(_exception != null);
+ throw _exception;
+ }
+ }
+
+ //
+ // We start out in holding state.
+ //
+ setState(StateHolding);
+ }
+ }
+ catch(LocalException ex)
+ {
+ exception(ex);
+ waitUntilFinished();
+ return;
+ }
+ }
+
+ public void activate()
+ {
+ lock(this)
+ {
+ if(_state <= StateNotValidated)
+ {
+ return;
+ }
+
+ if(_acmLastActivity > -1)
+ {
+ _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis();
+ }
+ setState(StateActive);
+ }
+ }
+
+ public void hold()
+ {
+ lock(this)
+ {
+ if(_state <= StateNotValidated)
+ {
+ return;
+ }
+
+ setState(StateHolding);
+ }
+ }
+
+ // DestructionReason.
+ public const int ObjectAdapterDeactivated = 0;
+ public const int CommunicatorDestroyed = 1;
+
+ public void destroy(int reason)
+ {
+ lock(this)
+ {
+ switch(reason)
+ {
+ case ObjectAdapterDeactivated:
+ {
+ setState(StateClosing, new ObjectAdapterDeactivatedException());
+ break;
+ }
+
+ case CommunicatorDestroyed:
+ {
+ setState(StateClosing, new CommunicatorDestroyedException());
+ break;
+ }
+ }
+ }
+ }
+
+ public void close(bool force)
+ {
+ lock(this)
+ {
+ if(force)
+ {
+ setState(StateClosed, new ForcedCloseConnectionException());
+ }
+ else
+ {
+ //
+ // If we do a graceful shutdown, then we wait until all
+ // outstanding requests have been completed. Otherwise,
+ // the CloseConnectionException will cause all outstanding
+ // requests to be retried, regardless of whether the
+ // server has processed them or not.
+ //
+ while(_asyncRequests.Count != 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ setState(StateClosing, new CloseConnectionException());
+ }
+ }
+ }
+
+ public bool isActiveOrHolding()
+ {
+ lock(this)
+ {
+ return _state > StateNotValidated && _state < StateClosing;
+ }
+ }
+
+ public bool isFinished()
+ {
+ //
+ // We can use TryLock here, because as long as there are still
+ // threads operating in this connection object, connection
+ // destruction is considered as not yet finished.
+ //
+ if(!System.Threading.Monitor.TryEnter(this))
+ {
+ return false;
+ }
+
+ try
+ {
+ if(_state != StateFinished || _dispatchCount != 0)
+ {
+ return false;
+ }
+
+ Debug.Assert(_state == StateFinished);
+ return true;
+ }
+ finally
+ {
+ System.Threading.Monitor.Exit(this);
+ }
+ }
+
+ public void throwException()
+ {
+ lock(this)
+ {
+ if(_exception != null)
+ {
+ Debug.Assert(_state >= StateClosing);
+ throw _exception;
+ }
+ }
+ }
+
+ public void waitUntilHolding()
+ {
+ lock(this)
+ {
+ while(_state < StateHolding || _dispatchCount > 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ }
+ }
+
+ public void waitUntilFinished()
+ {
+ lock(this)
+ {
+ //
+ // We wait indefinitely until the connection is finished and all
+ // outstanding requests are completed. Otherwise we couldn't
+ // guarantee that there are no outstanding calls when deactivate()
+ // is called on the servant locators.
+ //
+ while(_state < StateFinished || _dispatchCount > 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ Debug.Assert(_state == StateFinished);
+
+ //
+ // Clear the OA. See bug 1673 for the details of why this is necessary.
+ //
+ _adapter = null;
+ }
+ }
+
+ public void updateObserver()
+ {
+ lock(this)
+ {
+ if(_state < StateNotValidated || _state > StateClosed)
+ {
+ return;
+ }
+
+ Debug.Assert(_instance.initializationData().observer != null);
+ _observer = _instance.initializationData().observer.getConnectionObserver(initConnectionInfo(),
+ _endpoint,
+ toConnectionState(_state),
+ _observer);
+ if(_observer != null)
+ {
+ _observer.attach();
+ }
+ else
+ {
+ _writeStreamPos = -1;
+ _readStreamPos = -1;
+ }
+ }
+ }
+
+ public void monitor(long now, IceInternal.ACMConfig acm)
+ {
+ lock(this)
+ {
+ if(_state != StateActive)
+ {
+ return;
+ }
+
+ //
+ // We send a heartbeat if there was no activity in the last
+ // (timeout / 4) period. Sending a heartbeat sooner than
+ // really needed is safer to ensure that the receiver will
+ // receive in time the heartbeat. Sending the heartbeat if
+ // there was no activity in the last (timeout / 2) period
+ // isn't enough since monitor() is called only every (timeout
+ // / 2) period.
+ //
+ // Note that this doesn't imply that we are sending 4 heartbeats
+ // per timeout period because the monitor() method is sill only
+ // called every (timeout / 2) period.
+ //
+ if(acm.heartbeat == ACMHeartbeat.HeartbeatAlways ||
+ (acm.heartbeat != ACMHeartbeat.HeartbeatOff && _writeStream.isEmpty() &&
+ now >= (_acmLastActivity + acm.timeout / 4)))
+ {
+ if(acm.heartbeat != ACMHeartbeat.HeartbeatOnInvocation || _dispatchCount > 0)
+ {
+ heartbeat();
+ }
+ }
+
+ if(_readStream.size() > IceInternal.Protocol.headerSize || !_writeStream.isEmpty())
+ {
+ //
+ // If writing or reading, nothing to do, the connection
+ // timeout will kick-in if writes or reads don't progress.
+ // This check is necessary because the actitivy timer is
+ // only set when a message is fully read/written.
+ //
+ return;
+ }
+
+ if(acm.close != ACMClose.CloseOff && now >= (_acmLastActivity + acm.timeout))
+ {
+ if(acm.close == ACMClose.CloseOnIdleForceful ||
+ (acm.close != ACMClose.CloseOnIdle && (_asyncRequests.Count > 0)))
+ {
+ //
+ // Close the connection if we didn't receive a heartbeat in
+ // the last period.
+ //
+ setState(StateClosed, new ConnectionTimeoutException());
+ }
+ else if(acm.close != ACMClose.CloseOnInvocation &&
+ _dispatchCount == 0 && _batchRequestQueue.isEmpty() &&
+ _asyncRequests.Count == 0)
+ {
+ //
+ // The connection is idle, close it.
+ //
+ setState(StateClosing, new ConnectionTimeoutException());
+ }
+ }
+ }
+ }
+
+ public bool sendAsyncRequest(IceInternal.OutgoingAsyncBase og, bool compress, bool response,
+ int batchRequestNum, out Ice.AsyncCallback sentCallback)
+ {
+ IceInternal.BasicStream os = og.getOs();
+
+ lock(this)
+ {
+ if(_exception != null)
+ {
+ //
+ // If the connection is closed before we even have a chance
+ // to send our request, we always try to send the request
+ // again.
+ //
+ throw new IceInternal.RetryException(_exception);
+ }
+
+ Debug.Assert(_state > StateNotValidated);
+ Debug.Assert(_state < StateClosing);
+
+ //
+ // Ensure the message isn't bigger than what we can send with the
+ // transport.
+ //
+ _transceiver.checkSendSize(os.getBuffer());
+
+ //
+ // Notify the request that it's cancelable with this connection.
+ // This will throw if the request is canceled.
+ //
+ og.cancelable(this);
+
+ int requestId = 0;
+ if(response)
+ {
+ //
+ // Create a new unique request ID.
+ //
+ requestId = _nextRequestId++;
+ if(requestId <= 0)
+ {
+ _nextRequestId = 1;
+ requestId = _nextRequestId++;
+ }
+
+ //
+ // Fill in the request ID.
+ //
+ os.pos(IceInternal.Protocol.headerSize);
+ os.writeInt(requestId);
+ }
+ else if(batchRequestNum > 0)
+ {
+ os.pos(IceInternal.Protocol.headerSize);
+ os.writeInt(batchRequestNum);
+ }
+
+ og.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId);
+
+ bool sent;
+ try
+ {
+ OutgoingMessage msg = new OutgoingMessage(og, os, compress, requestId);
+ sent = sendMessage(msg);
+ sentCallback = msg.sentCallback;
+ }
+ catch(LocalException ex)
+ {
+ setState(StateClosed, ex);
+ Debug.Assert(_exception != null);
+ throw _exception;
+ }
+
+ if(response)
+ {
+ //
+ // Add to the async requests map.
+ //
+ _asyncRequests[requestId] = og;
+ }
+ return sent;
+ }
+ }
+
+ public IceInternal.BatchRequestQueue getBatchRequestQueue()
+ {
+ return _batchRequestQueue;
+ }
+
+ public void flushBatchRequests()
+ {
+ end_flushBatchRequests(begin_flushBatchRequests());
+ }
+
+ public AsyncResult begin_flushBatchRequests()
+ {
+ return begin_flushBatchRequestsInternal(null, null);
+ }
+
+ public AsyncResult begin_flushBatchRequests(AsyncCallback cb, object cookie)
+ {
+ return begin_flushBatchRequestsInternal(cb, cookie);
+ }
+
+ public void end_flushBatchRequests(AsyncResult r)
+ {
+ IceInternal.ConnectionFlushBatch outAsync =
+ IceInternal.ConnectionFlushBatch.check(r, this, __flushBatchRequests_name);
+ outAsync.wait();
+ }
+
+ private const string __flushBatchRequests_name = "flushBatchRequests";
+
+ private AsyncResult begin_flushBatchRequestsInternal(AsyncCallback cb, object cookie)
+ {
+ IceInternal.ConnectionFlushBatch result =
+ new IceInternal.ConnectionFlushBatch(this, _communicator, _instance, __flushBatchRequests_name, cookie);
+ if(cb != null)
+ {
+ result.whenCompletedWithAsyncCallback(cb);
+ }
+ result.invoke();
+ return result;
+ }
+
+ public void setCallback(ConnectionCallback callback)
+ {
+ lock(this)
+ {
+ if(_state >= StateClosed)
+ {
+ if(callback != null)
+ {
+ _threadPool.dispatch(() =>
+ {
+ try
+ {
+ callback.closed(this);
+ }
+ catch(System.Exception ex)
+ {
+ _logger.error("connection callback exception:\n" + ex + '\n' + _desc);
+ }
+ } , this);
+ }
+ }
+ else
+ {
+ _callback = callback;
+ }
+ }
+ }
+
+ public void setACM(Optional<int> timeout, Optional<ACMClose> close, Optional<ACMHeartbeat> heartbeat)
+ {
+ lock(this)
+ {
+ if(_monitor == null || _state >= StateClosed)
+ {
+ return;
+ }
+
+ if(_state == StateActive)
+ {
+ _monitor.remove(this);
+ }
+ _monitor = _monitor.acm(timeout, close, heartbeat);
+
+ if(_monitor.getACM().timeout <= 0)
+ {
+ _acmLastActivity = -1; // Disable the recording of last activity.
+ }
+ else if(_state == StateActive && _acmLastActivity == -1)
+ {
+ _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis();
+ }
+
+ if(_state == StateActive)
+ {
+ _monitor.add(this);
+ }
+ }
+ }
+
+ public ACM getACM()
+ {
+ lock(this)
+ {
+ return _monitor != null ? _monitor.getACM() : new ACM(0, ACMClose.CloseOff, ACMHeartbeat.HeartbeatOff);
+ }
+ }
+
+ public void asyncRequestCanceled(IceInternal.OutgoingAsyncBase outAsync, Ice.LocalException ex)
+ {
+ //
+ // NOTE: This isn't called from a thread pool thread.
+ //
+
+ lock(this)
+ {
+ if(_state >= StateClosed)
+ {
+ return; // The request has already been or will be shortly notified of the failure.
+ }
+
+ LinkedListNode<OutgoingMessage> p;
+ for(p = _sendStreams.First; p != null; p = p.Next)
+ {
+ OutgoingMessage o = p.Value;
+ if(o.outAsync == outAsync)
+ {
+ if(o.requestId > 0)
+ {
+ _asyncRequests.Remove(o.requestId);
+ }
+
+ if(ex is Ice.ConnectionTimeoutException)
+ {
+ setState(StateClosed, ex);
+ }
+ else
+ {
+ //
+ // If the request is being sent, don't remove it from the send streams,
+ // it will be removed once the sending is finished.
+ //
+ o.canceled();
+ if(o != _sendStreams.First.Value)
+ {
+ _sendStreams.Remove(p);
+ }
+ Ice.AsyncCallback cb = outAsync.completed(ex);
+ if(cb != null)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ }
+ return;
+ }
+ }
+
+ if(outAsync is IceInternal.OutgoingAsync)
+ {
+ foreach(KeyValuePair<int, IceInternal.OutgoingAsyncBase> kvp in _asyncRequests)
+ {
+ if(kvp.Value == outAsync)
+ {
+ if(ex is Ice.ConnectionTimeoutException)
+ {
+ setState(StateClosed, ex);
+ }
+ else
+ {
+ _asyncRequests.Remove(kvp.Key);
+ Ice.AsyncCallback cb = outAsync.completed(ex);
+ if(cb != null)
+ {
+ outAsync.invokeCompletedAsync(cb);
+ }
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public void sendResponse(int requestId, IceInternal.BasicStream os, byte compressFlag, bool amd)
+ {
+ lock(this)
+ {
+ Debug.Assert(_state > StateNotValidated);
+
+ try
+ {
+ if(--_dispatchCount == 0)
+ {
+ if(_state == StateFinished)
+ {
+ reap();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+
+ if(_state >= StateClosed)
+ {
+ Debug.Assert(_exception != null);
+ throw _exception;
+ }
+
+ sendMessage(new OutgoingMessage(os, compressFlag != 0, true));
+
+ if(_state == StateClosing && _dispatchCount == 0)
+ {
+ initiateShutdown();
+ }
+ }
+ catch(LocalException ex)
+ {
+ setState(StateClosed, ex);
+ }
+ }
+ }
+
+ public void sendNoResponse()
+ {
+ lock(this)
+ {
+ Debug.Assert(_state > StateNotValidated);
+
+ try
+ {
+ if(--_dispatchCount == 0)
+ {
+ if(_state == StateFinished)
+ {
+ reap();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+
+ if(_state >= StateClosed)
+ {
+ Debug.Assert(_exception != null);
+ throw _exception;
+ }
+
+ if(_state == StateClosing && _dispatchCount == 0)
+ {
+ initiateShutdown();
+ }
+ }
+ catch(LocalException ex)
+ {
+ setState(StateClosed, ex);
+ }
+ }
+ }
+
+ public bool systemException(int requestId, Ice.SystemException ex, bool amd)
+ {
+ return false; // System exceptions aren't marshalled.
+ }
+
+ public void invokeException(int requestId, LocalException ex, int invokeNum, bool amd)
+ {
+ //
+ // Fatal exception while invoking a request. Since sendResponse/sendNoResponse isn't
+ // called in case of a fatal exception we decrement _dispatchCount here.
+ //
+
+ lock(this)
+ {
+ setState(StateClosed, ex);
+
+ if(invokeNum > 0)
+ {
+ Debug.Assert(_dispatchCount >= invokeNum);
+ _dispatchCount -= invokeNum;
+ if(_dispatchCount == 0)
+ {
+ if(_state == StateFinished)
+ {
+ reap();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+ }
+ }
+
+ public IceInternal.EndpointI endpoint()
+ {
+ return _endpoint; // No mutex protection necessary, _endpoint is immutable.
+ }
+
+ public IceInternal.Connector connector()
+ {
+ return _connector; // No mutex protection necessary, _endpoint is immutable.
+ }
+
+ public void setAdapter(ObjectAdapter adapter)
+ {
+ lock(this)
+ {
+ if(_state <= StateNotValidated || _state >= StateClosing)
+ {
+ return;
+ }
+
+ _adapter = adapter;
+
+ if(_adapter != null)
+ {
+ _servantManager = ((ObjectAdapterI) _adapter).getServantManager();
+ if(_servantManager == null)
+ {
+ _adapter = null;
+ }
+ }
+ else
+ {
+ _servantManager = null;
+ }
+
+ //
+ // We never change the thread pool with which we were initially
+ // registered, even if we add or remove an object adapter.
+ //
+ }
+ }
+
+ public ObjectAdapter getAdapter()
+ {
+ lock(this)
+ {
+ return _adapter;
+ }
+ }
+
+ public Endpoint getEndpoint()
+ {
+ return _endpoint; // No mutex protection necessary, _endpoint is immutable.
+ }
+
+ public ObjectPrx createProxy(Identity ident)
+ {
+ //
+ // Create a reference and return a reverse proxy for this
+ // reference.
+ //
+ return _instance.proxyFactory().referenceToProxy(_instance.referenceFactory().create(ident, this));
+ }
+
+ //
+ // Operations from EventHandler
+ //
+ public override bool startAsync(int operation, IceInternal.AsyncCallback cb, ref bool completedSynchronously)
+ {
+ if(_state >= StateClosed)
+ {
+ return false;
+ }
+
+ try
+ {
+ if((operation & IceInternal.SocketOperation.Write) != 0)
+ {
+ if(_observer != null)
+ {
+ observerStartWrite(_writeStream.getBuffer());
+ }
+
+ bool completed;
+ completedSynchronously = _transceiver.startWrite(_writeStream.getBuffer(), cb, this, out completed);
+ if(completed && _sendStreams.Count > 0)
+ {
+ // The whole message is written, assume it's sent now for at-most-once semantics.
+ _sendStreams.First.Value.isSent = true;
+ }
+ }
+ else if((operation & IceInternal.SocketOperation.Read) != 0)
+ {
+ if(_observer != null && !_readHeader)
+ {
+ observerStartRead(_readStream.getBuffer());
+ }
+
+ completedSynchronously = _transceiver.startRead(_readStream.getBuffer(), cb, this);
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ return false;
+ }
+ return true;
+ }
+
+ public override bool finishAsync(int operation)
+ {
+ try
+ {
+ if((operation & IceInternal.SocketOperation.Write) != 0)
+ {
+ IceInternal.Buffer buf = _writeStream.getBuffer();
+ int start = buf.b.position();
+ _transceiver.finishWrite(buf);
+ if(_instance.traceLevels().network >= 3 && buf.b.position() != start)
+ {
+ StringBuilder s = new StringBuilder("sent ");
+ s.Append(buf.b.position() - start);
+ if(!_endpoint.datagram())
+ {
+ s.Append(" of ");
+ s.Append(buf.b.limit() - start);
+ }
+ s.Append(" bytes via ");
+ s.Append(_endpoint.protocol());
+ s.Append("\n");
+ s.Append(ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+
+ if(_observer != null)
+ {
+ observerFinishWrite(_writeStream.getBuffer());
+ }
+ }
+ else if((operation & IceInternal.SocketOperation.Read) != 0)
+ {
+ IceInternal.Buffer buf = _readStream.getBuffer();
+ int start = buf.b.position();
+ _transceiver.finishRead(buf);
+ if(_instance.traceLevels().network >= 3 && buf.b.position() != start)
+ {
+ StringBuilder s = new StringBuilder("received ");
+ if(_endpoint.datagram())
+ {
+ s.Append(buf.b.limit());
+ }
+ else
+ {
+ s.Append(buf.b.position() - start);
+ s.Append(" of ");
+ s.Append(buf.b.limit() - start);
+ }
+ s.Append(" bytes via ");
+ s.Append(_endpoint.protocol());
+ s.Append("\n");
+ s.Append(ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+
+ if(_observer != null && !_readHeader)
+ {
+ observerFinishRead(_readStream.getBuffer());
+ }
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ }
+ return _state < StateClosed;
+ }
+
+ public override void message(ref IceInternal.ThreadPoolCurrent current)
+ {
+ StartCallback startCB = null;
+ Queue<OutgoingMessage> sentCBs = null;
+ MessageInfo info = new MessageInfo();
+ int dispatchCount = 0;
+
+ IceInternal.ThreadPoolMessage msg = new IceInternal.ThreadPoolMessage(this);
+ try
+ {
+ lock(this)
+ {
+ if(!msg.startIOScope(ref current))
+ {
+ return;
+ }
+
+ if(_state >= StateClosed)
+ {
+ return;
+ }
+
+ int readyOp = current.operation;
+ try
+ {
+ unscheduleTimeout(current.operation);
+
+ int writeOp = IceInternal.SocketOperation.None;
+ int readOp = IceInternal.SocketOperation.None;
+ if((readyOp & IceInternal.SocketOperation.Write) != 0)
+ {
+ if(_observer != null)
+ {
+ observerStartWrite(_writeStream.getBuffer());
+ }
+ writeOp = write(_writeStream.getBuffer());
+ if(_observer != null && (writeOp & IceInternal.SocketOperation.Write) == 0)
+ {
+ observerFinishWrite(_writeStream.getBuffer());
+ }
+ }
+
+ while((readyOp & IceInternal.SocketOperation.Read) != 0)
+ {
+ IceInternal.Buffer buf = _readStream.getBuffer();
+
+ if(_observer != null && !_readHeader)
+ {
+ observerStartRead(buf);
+ }
+
+ readOp = read(buf);
+ if((readOp & IceInternal.SocketOperation.Read) != 0)
+ {
+ break;
+ }
+ if(_observer != null && !_readHeader)
+ {
+ Debug.Assert(!buf.b.hasRemaining());
+ observerFinishRead(buf);
+ }
+
+ if(_readHeader) // Read header if necessary.
+ {
+ _readHeader = false;
+
+ if(_observer != null)
+ {
+ _observer.receivedBytes(IceInternal.Protocol.headerSize);
+ }
+
+ int pos = _readStream.pos();
+ if(pos < IceInternal.Protocol.headerSize)
+ {
+ //
+ // This situation is possible for small UDP packets.
+ //
+ throw new Ice.IllegalMessageSizeException();
+ }
+
+ _readStream.pos(0);
+ byte[] m = new byte[4];
+ m[0] = _readStream.readByte();
+ m[1] = _readStream.readByte();
+ m[2] = _readStream.readByte();
+ m[3] = _readStream.readByte();
+ if(m[0] != IceInternal.Protocol.magic[0] || m[1] != IceInternal.Protocol.magic[1] ||
+ m[2] != IceInternal.Protocol.magic[2] || m[3] != IceInternal.Protocol.magic[3])
+ {
+ Ice.BadMagicException ex = new Ice.BadMagicException();
+ ex.badMagic = m;
+ throw ex;
+ }
+
+ ProtocolVersion pv = new ProtocolVersion();
+ pv.read__(_readStream);
+ IceInternal.Protocol.checkSupportedProtocol(pv);
+ EncodingVersion ev = new EncodingVersion();
+ ev.read__(_readStream);
+ IceInternal.Protocol.checkSupportedProtocolEncoding(ev);
+
+ _readStream.readByte(); // messageType
+ _readStream.readByte(); // compress
+ int size = _readStream.readInt();
+ if(size < IceInternal.Protocol.headerSize)
+ {
+ throw new Ice.IllegalMessageSizeException();
+ }
+ if(size > _messageSizeMax)
+ {
+ IceInternal.Ex.throwMemoryLimitException(size, _messageSizeMax);
+ }
+ if(size > _readStream.size())
+ {
+ _readStream.resize(size, true);
+ }
+ _readStream.pos(pos);
+ }
+
+ if(buf.b.hasRemaining())
+ {
+ if(_endpoint.datagram())
+ {
+ throw new Ice.DatagramLimitException(); // The message was truncated.
+ }
+ continue;
+ }
+ break;
+ }
+
+ int newOp = readOp | writeOp;
+ readyOp &= ~newOp;
+ Debug.Assert(readyOp != 0 || newOp != 0);
+
+ if(_state <= StateNotValidated)
+ {
+ if(newOp != 0)
+ {
+ //
+ // Wait for all the transceiver conditions to be
+ // satisfied before continuing.
+ //
+ scheduleTimeout(newOp);
+ _threadPool.update(this, current.operation, newOp);
+ return;
+ }
+
+ if(_state == StateNotInitialized && !initialize(current.operation))
+ {
+ return;
+ }
+
+ if(_state <= StateNotValidated && !validate(current.operation))
+ {
+ return;
+ }
+
+ _threadPool.unregister(this, current.operation);
+
+ //
+ // We start out in holding state.
+ //
+ setState(StateHolding);
+ if(_startCallback != null)
+ {
+ startCB = _startCallback;
+ _startCallback = null;
+ if(startCB != null)
+ {
+ ++dispatchCount;
+ }
+ }
+ }
+ else
+ {
+ Debug.Assert(_state <= StateClosingPending);
+
+ //
+ // We parse messages first, if we receive a close
+ // connection message we won't send more messages.
+ //
+ if((readyOp & IceInternal.SocketOperation.Read) != 0)
+ {
+ newOp |= parseMessage(ref info);
+ dispatchCount += info.messageDispatchCount;
+ }
+
+ if((readyOp & IceInternal.SocketOperation.Write) != 0)
+ {
+ newOp |= sendNextMessage(out sentCBs);
+ if(sentCBs != null)
+ {
+ ++dispatchCount;
+ }
+ }
+
+ if(_state < StateClosed)
+ {
+ scheduleTimeout(newOp);
+ _threadPool.update(this, current.operation, newOp);
+ }
+ }
+
+ if(_acmLastActivity > -1)
+ {
+ _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis();
+ }
+
+ if(dispatchCount == 0)
+ {
+ return; // Nothing to dispatch we're done!
+ }
+
+ _dispatchCount += dispatchCount;
+
+ msg.completed(ref current);
+ }
+ catch(DatagramLimitException) // Expected.
+ {
+ if(_warnUdp)
+ {
+ _logger.warning("maximum datagram size of " + _readStream.pos() + " exceeded");
+ }
+ _readStream.resize(IceInternal.Protocol.headerSize, true);
+ _readStream.pos(0);
+ _readHeader = true;
+ return;
+ }
+ catch(SocketException ex)
+ {
+ setState(StateClosed, ex);
+ return;
+ }
+ catch(LocalException ex)
+ {
+ if(_endpoint.datagram())
+ {
+ if(_warn)
+ {
+ String s = "datagram connection exception:\n" + ex + '\n' + _desc;
+ _logger.warning(s);
+ }
+ _readStream.resize(IceInternal.Protocol.headerSize, true);
+ _readStream.pos(0);
+ _readHeader = true;
+ }
+ else
+ {
+ setState(StateClosed, ex);
+ }
+ return;
+ }
+
+ IceInternal.ThreadPoolCurrent c = current;
+ _threadPool.dispatch(() =>
+ {
+ dispatch(startCB, sentCBs, info);
+ msg.destroy(ref c);
+ }, this);
+ }
+ }
+ finally
+ {
+ msg.finishIOScope(ref current);
+ }
+
+ }
+
+ private void dispatch(StartCallback startCB, Queue<OutgoingMessage> sentCBs, MessageInfo info)
+ {
+ int dispatchedCount = 0;
+
+ //
+ // Notify the factory that the connection establishment and
+ // validation has completed.
+ //
+ if(startCB != null)
+ {
+ startCB.connectionStartCompleted(this);
+ ++dispatchedCount;
+ }
+
+ //
+ // Notify AMI calls that the message was sent.
+ //
+ if(sentCBs != null)
+ {
+ foreach(OutgoingMessage m in sentCBs)
+ {
+ if(m.sentCallback != null)
+ {
+ m.outAsync.invokeSent(m.sentCallback);
+ }
+ if(m.receivedReply)
+ {
+ IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)m.outAsync;
+ Ice.AsyncCallback cb = outAsync.completed();
+ if(cb != null)
+ {
+ outAsync.invokeCompleted(cb);
+ }
+ }
+ }
+ ++dispatchedCount;
+ }
+
+ //
+ // Asynchronous replies must be handled outside the thread
+ // synchronization, so that nested calls are possible.
+ //
+ if(info.outAsync != null)
+ {
+ info.outAsync.invokeCompleted(info.completedCallback);
+ ++dispatchedCount;
+ }
+
+ if(info.heartbeatCallback != null)
+ {
+ try
+ {
+ info.heartbeatCallback.heartbeat(this);
+ }
+ catch(System.Exception ex)
+ {
+ _logger.error("connection callback exception:\n" + ex + '\n' + _desc);
+ }
+ ++dispatchedCount;
+ }
+
+ //
+ // Method invocation (or multiple invocations for batch messages)
+ // must be done outside the thread synchronization, so that nested
+ // calls are possible.
+ //
+ if(info.invokeNum > 0)
+ {
+ invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager,
+ info.adapter);
+
+ //
+ // Don't increase dispatchedCount, the dispatch count is
+ // decreased when the incoming reply is sent.
+ //
+ }
+
+ //
+ // Decrease dispatch count.
+ //
+ if(dispatchedCount > 0)
+ {
+ lock(this)
+ {
+ _dispatchCount -= dispatchedCount;
+ if(_dispatchCount == 0)
+ {
+ //
+ // Only initiate shutdown if not already done. It
+ // might have already been done if the sent callback
+ // or AMI callback was dispatched when the connection
+ // was already in the closing state.
+ //
+ if(_state == StateClosing)
+ {
+ try
+ {
+ initiateShutdown();
+ }
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ }
+ }
+ else if(_state == StateFinished)
+ {
+ reap();
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+ }
+ }
+
+ public override void finished(ref IceInternal.ThreadPoolCurrent current)
+ {
+ lock(this)
+ {
+ Debug.Assert(_state == StateClosed);
+ unscheduleTimeout(IceInternal.SocketOperation.Read | IceInternal.SocketOperation.Write);
+ }
+
+ //
+ // If there are no callbacks to call, we don't call ioCompleted() since we're not going
+ // to call code that will potentially block (this avoids promoting a new leader and
+ // unecessary thread creation, especially if this is called on shutdown).
+ //
+ if(_startCallback == null && _sendStreams.Count == 0 && _asyncRequests.Count == 0 && _callback == null)
+ {
+ finish();
+ return;
+ }
+
+ //
+ // Unlike C++/Java, this method is called from an IO thread of the .NET thread
+ // pool of from the communicator async IO thread. While it's fine to handle the
+ // non-blocking activity of the connection from these threads, the dispatching
+ // of the message must be taken care of by the Ice thread pool.
+ //
+ _threadPool.dispatch(finish, this);
+ }
+
+ private void finish()
+ {
+ if(!_initialized)
+ {
+ if(_instance.traceLevels().network >= 2)
+ {
+ StringBuilder s = new StringBuilder("failed to ");
+ s.Append(_connector != null ? "establish" : "accept");
+ s.Append(" ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connection\n");
+ s.Append(ToString());
+ s.Append("\n");
+ s.Append(_exception);
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+ }
+ else
+ {
+ if(_instance.traceLevels().network >= 1)
+ {
+ StringBuilder s = new StringBuilder("closed ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connection\n");
+ s.Append(ToString());
+
+ //
+ // Trace the cause of unexpected connection closures
+ //
+ if(!(_exception is CloseConnectionException ||
+ _exception is ForcedCloseConnectionException ||
+ _exception is ConnectionTimeoutException ||
+ _exception is CommunicatorDestroyedException ||
+ _exception is ObjectAdapterDeactivatedException))
+ {
+ s.Append("\n");
+ s.Append(_exception);
+ }
+
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+ }
+
+ if(_startCallback != null)
+ {
+ _startCallback.connectionStartFailed(this, _exception);
+ _startCallback = null;
+ }
+
+ if(_sendStreams.Count > 0)
+ {
+ if(!_writeStream.isEmpty())
+ {
+ //
+ // Return the stream to the outgoing call. This is important for
+ // retriable AMI calls which are not marshalled again.
+ //
+ OutgoingMessage message = _sendStreams.First.Value;
+ _writeStream.swap(message.stream);
+
+ //
+ // The current message might be sent but not yet removed from _sendStreams. If
+ // the response has been received in the meantime, we remove the message from
+ // _sendStreams to not call finished on a message which is already done.
+ //
+ if(message.isSent || message.receivedReply)
+ {
+ if(message.sent() && message.sentCallback != null)
+ {
+ message.outAsync.invokeSent(message.sentCallback);
+ }
+ if(message.receivedReply)
+ {
+ IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)message.outAsync;
+ Ice.AsyncCallback cb = outAsync.completed();
+ if(cb != null)
+ {
+ outAsync.invokeCompleted(cb);
+ }
+ }
+ _sendStreams.RemoveFirst();
+ }
+ }
+
+ foreach(OutgoingMessage m in _sendStreams)
+ {
+ m.completed(_exception);
+ if(m.requestId > 0) // Make sure finished isn't called twice.
+ {
+ _asyncRequests.Remove(m.requestId);
+ }
+ }
+ _sendStreams.Clear();
+ }
+
+ foreach(IceInternal.OutgoingAsyncBase o in _asyncRequests.Values)
+ {
+ Ice.AsyncCallback cb = o.completed(_exception);
+ if(cb != null)
+ {
+ o.invokeCompleted(cb);
+ }
+ }
+ _asyncRequests.Clear();
+
+ if(_callback != null)
+ {
+ try
+ {
+ _callback.closed(this);
+ }
+ catch(System.Exception ex)
+ {
+ _logger.error("connection callback exception:\n" + ex + '\n' + _desc);
+ }
+ _callback = null;
+ }
+
+ //
+ // This must be done last as this will cause waitUntilFinished() to return (and communicator
+ // objects such as the timer might be destroyed too).
+ //
+ lock(this)
+ {
+ setState(StateFinished);
+
+ if(_dispatchCount == 0)
+ {
+ reap();
+ }
+ }
+ }
+
+ public override string ToString()
+ {
+ return _desc; // No mutex lock, _desc is immutable.
+ }
+
+ public void timedOut()
+ {
+ lock(this)
+ {
+ if(_state <= StateNotValidated)
+ {
+ setState(StateClosed, new ConnectTimeoutException());
+ }
+ else if(_state < StateClosing)
+ {
+ setState(StateClosed, new TimeoutException());
+ }
+ else if(_state < StateClosed)
+ {
+ setState(StateClosed, new CloseTimeoutException());
+ }
+ }
+ }
+
+ public string type()
+ {
+ return _type; // No mutex lock, _type is immutable.
+ }
+
+ public int timeout()
+ {
+ return _endpoint.timeout(); // No mutex protection necessary, _endpoint is immutable.
+ }
+
+ public ConnectionInfo getInfo()
+ {
+ lock(this)
+ {
+ if(_state >= StateClosed)
+ {
+ throw _exception;
+ }
+ return initConnectionInfo();
+ }
+ }
+
+ public void setBufferSize(int rcvSize, int sndSize)
+ {
+ lock(this)
+ {
+ if(_state >= StateClosed)
+ {
+ throw _exception;
+ }
+ _transceiver.setBufferSize(rcvSize, sndSize);
+ _info = null; // Invalidate the cached connection info
+ }
+ }
+
+ public string ice_toString_()
+ {
+ return ToString();
+ }
+
+ public void exception(LocalException ex)
+ {
+ lock(this)
+ {
+ setState(StateClosed, ex);
+ }
+ }
+
+ static ConnectionI()
+ {
+ _compressionSupported = IceInternal.BasicStream.compressible();
+ }
+
+ internal ConnectionI(Communicator communicator, IceInternal.Instance instance,
+ IceInternal.ACMMonitor monitor, IceInternal.Transceiver transceiver,
+ IceInternal.Connector connector, IceInternal.EndpointI endpoint, ObjectAdapterI adapter)
+ {
+ _communicator = communicator;
+ _instance = instance;
+ _monitor = monitor;
+ _transceiver = transceiver;
+ _desc = transceiver.ToString();
+ _type = transceiver.protocol();
+ _connector = connector;
+ _endpoint = endpoint;
+ _adapter = adapter;
+ InitializationData initData = instance.initializationData();
+ _logger = initData.logger; // Cached for better performance.
+ _traceLevels = instance.traceLevels(); // Cached for better performance.
+ _timer = instance.timer();
+ _writeTimeout = new TimeoutCallback(this);
+ _writeTimeoutScheduled = false;
+ _readTimeout = new TimeoutCallback(this);
+ _readTimeoutScheduled = false;
+ _warn = initData.properties.getPropertyAsInt("Ice.Warn.Connections") > 0;
+ _warnUdp = initData.properties.getPropertyAsInt("Ice.Warn.Datagrams") > 0;
+ _cacheBuffers = instance.cacheMessageBuffers() > 0;
+ if(_monitor != null && _monitor.getACM().timeout > 0)
+ {
+ _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis();
+ }
+ else
+ {
+ _acmLastActivity = -1;
+ }
+ _nextRequestId = 1;
+ _messageSizeMax = adapter != null ? adapter.messageSizeMax() : instance.messageSizeMax();
+ _batchRequestQueue = new IceInternal.BatchRequestQueue(instance, _endpoint.datagram());
+ _readStream = new IceInternal.BasicStream(instance, Util.currentProtocolEncoding);
+ _readHeader = false;
+ _readStreamPos = -1;
+ _writeStream = new IceInternal.BasicStream(instance, Util.currentProtocolEncoding);
+ _writeStreamPos = -1;
+ _dispatchCount = 0;
+ _state = StateNotInitialized;
+
+ _compressionLevel = initData.properties.getPropertyAsIntWithDefault("Ice.Compression.Level", 1);
+ if(_compressionLevel < 1)
+ {
+ _compressionLevel = 1;
+ }
+ else if(_compressionLevel > 9)
+ {
+ _compressionLevel = 9;
+ }
+
+ if(adapter != null)
+ {
+ _servantManager = adapter.getServantManager();
+ }
+
+ try
+ {
+ if(adapter != null)
+ {
+ _threadPool = adapter.getThreadPool();
+ }
+ else
+ {
+ _threadPool = instance.clientThreadPool();
+ }
+ _threadPool.initialize(this);
+ }
+ catch(LocalException)
+ {
+ throw;
+ }
+ catch(System.Exception ex)
+ {
+ throw new SyscallException(ex);
+ }
+ }
+
+ private const int StateNotInitialized = 0;
+ private const int StateNotValidated = 1;
+ private const int StateActive = 2;
+ private const int StateHolding = 3;
+ private const int StateClosing = 4;
+ private const int StateClosingPending = 5;
+ private const int StateClosed = 6;
+ private const int StateFinished = 7;
+
+ private void setState(int state, LocalException ex)
+ {
+ //
+ // If setState() is called with an exception, then only closed
+ // and closing states are permissible.
+ //
+ Debug.Assert(state >= StateClosing);
+
+ if(_state == state) // Don't switch twice.
+ {
+ return;
+ }
+
+ if(_exception == null)
+ {
+ //
+ // If we are in closed state, an exception must be set.
+ //
+ Debug.Assert(_state != StateClosed);
+
+ _exception = ex;
+
+ //
+ // We don't warn if we are not validated.
+ //
+ if(_warn && _validated)
+ {
+ //
+ // Don't warn about certain expected exceptions.
+ //
+ if(!(_exception is CloseConnectionException ||
+ _exception is ForcedCloseConnectionException ||
+ _exception is ConnectionTimeoutException ||
+ _exception is CommunicatorDestroyedException ||
+ _exception is ObjectAdapterDeactivatedException ||
+ (_exception is ConnectionLostException && _state >= StateClosing)))
+ {
+ warning("connection exception", _exception);
+ }
+ }
+ }
+
+ //
+ // We must set the new state before we notify requests of any
+ // exceptions. Otherwise new requests may retry on a
+ // connection that is not yet marked as closed or closing.
+ //
+ setState(state);
+ }
+
+ private void setState(int state)
+ {
+ //
+ // We don't want to send close connection messages if the endpoint
+ // only supports oneway transmission from client to server.
+ //
+ if(_endpoint.datagram() && state == StateClosing)
+ {
+ state = StateClosed;
+ }
+
+ //
+ // Skip graceful shutdown if we are destroyed before validation.
+ //
+ if(_state <= StateNotValidated && state == StateClosing)
+ {
+ state = StateClosed;
+ }
+
+ if(_state == state) // Don't switch twice.
+ {
+ return;
+ }
+
+ try
+ {
+ switch(state)
+ {
+ case StateNotInitialized:
+ {
+ Debug.Assert(false);
+ break;
+ }
+
+ case StateNotValidated:
+ {
+ if(_state != StateNotInitialized)
+ {
+ Debug.Assert(_state == StateClosed);
+ return;
+ }
+ break;
+ }
+
+ case StateActive:
+ {
+ //
+ // Can only switch from holding or not validated to
+ // active.
+ //
+ if(_state != StateHolding && _state != StateNotValidated)
+ {
+ return;
+ }
+ _threadPool.register(this, IceInternal.SocketOperation.Read);
+ break;
+ }
+
+ case StateHolding:
+ {
+ //
+ // Can only switch from active or not validated to
+ // holding.
+ //
+ if(_state != StateActive && _state != StateNotValidated)
+ {
+ return;
+ }
+ if(_state == StateActive)
+ {
+ _threadPool.unregister(this, IceInternal.SocketOperation.Read);
+ }
+ break;
+ }
+
+ case StateClosing:
+ case StateClosingPending:
+ {
+ //
+ // Can't change back from closing pending.
+ //
+ if(_state >= StateClosingPending)
+ {
+ return;
+ }
+ break;
+ }
+
+ case StateClosed:
+ {
+ if(_state == StateFinished)
+ {
+ return;
+ }
+
+ _batchRequestQueue.destroy(_exception);
+ _threadPool.finish(this);
+ _transceiver.close();
+ break;
+ }
+
+ case StateFinished:
+ {
+ Debug.Assert(_state == StateClosed);
+ _transceiver.destroy();
+ _communicator = null;
+ break;
+ }
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ _logger.error("unexpected connection exception:\n" + ex + "\n" + _transceiver.ToString());
+ }
+
+ //
+ // We only register with the connection monitor if our new state
+ // is StateActive. Otherwise we unregister with the connection
+ // monitor, but only if we were registered before, i.e., if our
+ // old state was StateActive.
+ //
+ if(_monitor != null)
+ {
+ if(state == StateActive)
+ {
+ if(_acmLastActivity > -1)
+ {
+ _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis();
+ }
+ _monitor.add(this);
+ }
+ else if(_state == StateActive)
+ {
+ _monitor.remove(this);
+ }
+ }
+
+ if(_instance.initializationData().observer != null)
+ {
+ ConnectionState oldState = toConnectionState(_state);
+ ConnectionState newState = toConnectionState(state);
+ if(oldState != newState)
+ {
+ _observer = _instance.initializationData().observer.getConnectionObserver(initConnectionInfo(),
+ _endpoint,
+ newState,
+ _observer);
+ if(_observer != null)
+ {
+ _observer.attach();
+ }
+ else
+ {
+ _writeStreamPos = -1;
+ _readStreamPos = -1;
+ }
+ }
+ if(_observer != null && state == StateClosed && _exception != null)
+ {
+ if(!(_exception is CloseConnectionException ||
+ _exception is ForcedCloseConnectionException ||
+ _exception is ConnectionTimeoutException ||
+ _exception is CommunicatorDestroyedException ||
+ _exception is ObjectAdapterDeactivatedException ||
+ (_exception is ConnectionLostException && _state >= StateClosing)))
+ {
+ _observer.failed(_exception.ice_name());
+ }
+ }
+ }
+ _state = state;
+
+ System.Threading.Monitor.PulseAll(this);
+
+ if(_state == StateClosing && _dispatchCount == 0)
+ {
+ try
+ {
+ initiateShutdown();
+ }
+ catch(LocalException ex)
+ {
+ setState(StateClosed, ex);
+ }
+ }
+ }
+
+ private void initiateShutdown()
+ {
+ Debug.Assert(_state == StateClosing);
+ Debug.Assert(_dispatchCount == 0);
+
+ if(_shutdownInitiated)
+ {
+ return;
+ }
+ _shutdownInitiated = true;
+
+ if(!_endpoint.datagram())
+ {
+ //
+ // Before we shut down, we send a close connection message.
+ //
+ IceInternal.BasicStream os = new IceInternal.BasicStream(_instance, Util.currentProtocolEncoding);
+ os.writeBlob(IceInternal.Protocol.magic);
+ Ice.Util.currentProtocol.write__(os);
+ Ice.Util.currentProtocolEncoding.write__(os);
+ os.writeByte(IceInternal.Protocol.closeConnectionMsg);
+ os.writeByte(_compressionSupported ? (byte)1 : (byte)0);
+ os.writeInt(IceInternal.Protocol.headerSize); // Message size.
+
+ if(sendMessage(new OutgoingMessage(os, false, false)))
+ {
+ setState(StateClosingPending);
+
+ //
+ // Notify the the transceiver of the graceful connection closure.
+ //
+ int op = _transceiver.closing(true, _exception);
+ if(op != 0)
+ {
+ scheduleTimeout(op);
+ _threadPool.register(this, op);
+ }
+ }
+ }
+ }
+
+ private void heartbeat()
+ {
+ Debug.Assert(_state == StateActive);
+
+ if(!_endpoint.datagram())
+ {
+ IceInternal.BasicStream os = new IceInternal.BasicStream(_instance, Util.currentProtocolEncoding);
+ os.writeBlob(IceInternal.Protocol.magic);
+ Ice.Util.currentProtocol.write__(os);
+ Ice.Util.currentProtocolEncoding.write__(os);
+ os.writeByte(IceInternal.Protocol.validateConnectionMsg);
+ os.writeByte((byte)0);
+ os.writeInt(IceInternal.Protocol.headerSize); // Message size.
+ try
+ {
+ OutgoingMessage message = new OutgoingMessage(os, false, false);
+ sendMessage(message);
+ }
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ Debug.Assert(_exception != null);
+ }
+ }
+ }
+
+ private bool initialize(int operation)
+ {
+ int s = _transceiver.initialize(_readStream.getBuffer(), _writeStream.getBuffer(), ref _hasMoreData);
+ if(s != IceInternal.SocketOperation.None)
+ {
+ scheduleTimeout(s);
+ _threadPool.update(this, operation, s);
+ return false;
+ }
+
+ //
+ // Update the connection description once the transceiver is initialized.
+ //
+ _desc = _transceiver.ToString();
+ _initialized = true;
+ setState(StateNotValidated);
+
+ return true;
+ }
+
+ private bool validate(int operation)
+ {
+ if(!_endpoint.datagram()) // Datagram connections are always implicitly validated.
+ {
+ if(_adapter != null) // The server side has the active role for connection validation.
+ {
+ if(_writeStream.size() == 0)
+ {
+ _writeStream.writeBlob(IceInternal.Protocol.magic);
+ Ice.Util.currentProtocol.write__(_writeStream);
+ Ice.Util.currentProtocolEncoding.write__(_writeStream);
+ _writeStream.writeByte(IceInternal.Protocol.validateConnectionMsg);
+ _writeStream.writeByte((byte)0); // Compression status (always zero for validate connection).
+ _writeStream.writeInt(IceInternal.Protocol.headerSize); // Message size.
+ IceInternal.TraceUtil.traceSend(_writeStream, _logger, _traceLevels);
+ _writeStream.prepareWrite();
+ }
+
+ if(_observer != null)
+ {
+ observerStartWrite(_writeStream.getBuffer());
+ }
+
+ if(_writeStream.pos() != _writeStream.size())
+ {
+ int op = write(_writeStream.getBuffer());
+ if(op != 0)
+ {
+ scheduleTimeout(op);
+ _threadPool.update(this, operation, op);
+ return false;
+ }
+ }
+
+ if(_observer != null)
+ {
+ observerFinishWrite(_writeStream.getBuffer());
+ }
+ }
+ else // The client side has the passive role for connection validation.
+ {
+ if(_readStream.size() == 0)
+ {
+ _readStream.resize(IceInternal.Protocol.headerSize, true);
+ _readStream.pos(0);
+ }
+
+ if(_observer != null)
+ {
+ observerStartRead(_readStream.getBuffer());
+ }
+
+ if(_readStream.pos() != _readStream.size())
+ {
+ int op = read(_readStream.getBuffer());
+ if(op != 0)
+ {
+ scheduleTimeout(op);
+ _threadPool.update(this, operation, op);
+ return false;
+ }
+ }
+
+ if(_observer != null)
+ {
+ observerFinishRead(_readStream.getBuffer());
+ }
+
+ Debug.Assert(_readStream.pos() == IceInternal.Protocol.headerSize);
+ _readStream.pos(0);
+ byte[] m = _readStream.readBlob(4);
+ if(m[0] != IceInternal.Protocol.magic[0] || m[1] != IceInternal.Protocol.magic[1] ||
+ m[2] != IceInternal.Protocol.magic[2] || m[3] != IceInternal.Protocol.magic[3])
+ {
+ BadMagicException ex = new BadMagicException();
+ ex.badMagic = m;
+ throw ex;
+ }
+
+ ProtocolVersion pv = new ProtocolVersion();
+ pv.read__(_readStream);
+ IceInternal.Protocol.checkSupportedProtocol(pv);
+
+ EncodingVersion ev = new EncodingVersion();
+ ev.read__(_readStream);
+ IceInternal.Protocol.checkSupportedProtocolEncoding(ev);
+
+ byte messageType = _readStream.readByte();
+ if(messageType != IceInternal.Protocol.validateConnectionMsg)
+ {
+ throw new ConnectionNotValidatedException();
+ }
+ _readStream.readByte(); // Ignore compression status for validate connection.
+ int size = _readStream.readInt();
+ if(size != IceInternal.Protocol.headerSize)
+ {
+ throw new IllegalMessageSizeException();
+ }
+ IceInternal.TraceUtil.traceRecv(_readStream, _logger, _traceLevels);
+
+ _validated = true;
+ }
+ }
+
+ _writeStream.resize(0, false);
+ _writeStream.pos(0);
+
+ _readStream.resize(IceInternal.Protocol.headerSize, true);
+ _readStream.pos(0);
+ _readHeader = true;
+
+ if(_instance.traceLevels().network >= 1)
+ {
+ StringBuilder s = new StringBuilder();
+ if(_endpoint.datagram())
+ {
+ s.Append("starting to ");
+ s.Append(_connector != null ? "send" : "receive");
+ s.Append(" ");
+ s.Append(_endpoint.protocol());
+ s.Append(" messages\n");
+ s.Append(_transceiver.toDetailedString());
+ }
+ else
+ {
+ s.Append(_connector != null ? "established" : "accepted");
+ s.Append(" ");
+ s.Append(_endpoint.protocol());
+ s.Append(" connection\n");
+ s.Append(ToString());
+ }
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+
+ return true;
+ }
+
+ private int sendNextMessage(out Queue<OutgoingMessage> callbacks)
+ {
+ callbacks = null;
+
+ if(_sendStreams.Count == 0)
+ {
+ return IceInternal.SocketOperation.None;
+ }
+ else if(_state == StateClosingPending && _writeStream.pos() == 0)
+ {
+ // Message wasn't sent, empty the _writeStream, we're not going to send more data.
+ OutgoingMessage message = _sendStreams.First.Value;
+ _writeStream.swap(message.stream);
+ return IceInternal.SocketOperation.None;
+ }
+
+ Debug.Assert(!_writeStream.isEmpty() && _writeStream.pos() == _writeStream.size());
+ try
+ {
+ while(true)
+ {
+ //
+ // Notify the message that it was sent.
+ //
+ OutgoingMessage message = _sendStreams.First.Value;
+ _writeStream.swap(message.stream);
+ if(message.sent())
+ {
+ if(callbacks == null)
+ {
+ callbacks = new Queue<OutgoingMessage>();
+ }
+ callbacks.Enqueue(message);
+ }
+ _sendStreams.RemoveFirst();
+
+ //
+ // If there's nothing left to send, we're done.
+ //
+ if(_sendStreams.Count == 0)
+ {
+ break;
+ }
+
+ //
+ // If we are in the closed state or if the close is
+ // pending, don't continue sending.
+ //
+ // This can occur if parseMessage (called before
+ // sendNextMessage by message()) closes the connection.
+ //
+ if(_state >= StateClosingPending)
+ {
+ return IceInternal.SocketOperation.None;
+ }
+
+ //
+ // Otherwise, prepare the next message stream for writing.
+ //
+ message = _sendStreams.First.Value;
+ Debug.Assert(!message.prepared);
+ IceInternal.BasicStream stream = message.stream;
+
+ message.stream = doCompress(message.stream, message.compress);
+ message.stream.prepareWrite();
+ message.prepared = true;
+
+ if(message.outAsync != null)
+ {
+ IceInternal.TraceUtil.trace("sending asynchronous request", stream, _logger, _traceLevels);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceSend(stream, _logger, _traceLevels);
+ }
+ _writeStream.swap(message.stream);
+
+ //
+ // Send the message.
+ //
+ if(_observer != null)
+ {
+ observerStartWrite(_writeStream.getBuffer());
+ }
+ if(_writeStream.pos() != _writeStream.size())
+ {
+ int op = write(_writeStream.getBuffer());
+ if(op != 0)
+ {
+ return op;
+ }
+ }
+ if(_observer != null)
+ {
+ observerFinishWrite(_writeStream.getBuffer());
+ }
+ }
+
+ //
+ // If all the messages were sent and we are in the closing state, we schedule
+ // the close timeout to wait for the peer to close the connection.
+ //
+ if(_state == StateClosing && _shutdownInitiated)
+ {
+ setState(StateClosingPending);
+ int op = _transceiver.closing(true, _exception);
+ if(op != 0)
+ {
+ return op;
+ }
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ }
+ return IceInternal.SocketOperation.None;
+ }
+
+ private bool sendMessage(OutgoingMessage message)
+ {
+ Debug.Assert(_state < StateClosed);
+
+ if(_sendStreams.Count > 0)
+ {
+ message.adopt();
+ _sendStreams.AddLast(message);
+ return false;
+ }
+
+ //
+ // Attempt to send the message without blocking. If the send blocks, we use
+ // asynchronous I/O or we request the caller to call finishSendMessage() outside
+ // the synchronization.
+ //
+
+ Debug.Assert(!message.prepared);
+
+ IceInternal.BasicStream stream = message.stream;
+
+ message.stream = doCompress(stream, message.compress);
+ message.stream.prepareWrite();
+ message.prepared = true;
+
+ if(message.outAsync != null)
+ {
+ IceInternal.TraceUtil.trace("sending asynchronous request", stream, _logger, _traceLevels);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceSend(stream, _logger, _traceLevels);
+ }
+
+ //
+ // Send the message without blocking.
+ //
+ if(_observer != null)
+ {
+ observerStartWrite(message.stream.getBuffer());
+ }
+ int op = write(message.stream.getBuffer());
+ if(op == 0)
+ {
+ if(_observer != null)
+ {
+ observerFinishWrite(message.stream.getBuffer());
+ }
+
+ message.sent();
+
+ if(_acmLastActivity > -1)
+ {
+ _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis();
+ }
+ return true;
+ }
+
+ message.adopt();
+
+ _writeStream.swap(message.stream);
+ _sendStreams.AddLast(message);
+ scheduleTimeout(op);
+ _threadPool.register(this, op);
+ return false;
+ }
+
+ private IceInternal.BasicStream doCompress(IceInternal.BasicStream uncompressed, bool compress)
+ {
+ if(_compressionSupported)
+ {
+ if(compress && uncompressed.size() >= 100)
+ {
+ //
+ // Do compression.
+ //
+ IceInternal.BasicStream cstream = null;
+ if(uncompressed.compress(ref cstream, IceInternal.Protocol.headerSize, _compressionLevel))
+ {
+ //
+ // Set compression status.
+ //
+ cstream.pos(9);
+ cstream.writeByte((byte)2);
+
+ //
+ // Write the size of the compressed stream into the header.
+ //
+ cstream.pos(10);
+ cstream.writeInt(cstream.size());
+
+ //
+ // Write the compression status and size of the compressed stream into the header of the
+ // uncompressed stream -- we need this to trace requests correctly.
+ //
+ uncompressed.pos(9);
+ uncompressed.writeByte((byte)2);
+ uncompressed.writeInt(cstream.size());
+
+ return cstream;
+ }
+ }
+ }
+
+ uncompressed.pos(9);
+ uncompressed.writeByte((byte)((_compressionSupported && compress) ? 1 : 0));
+
+ //
+ // Not compressed, fill in the message size.
+ //
+ uncompressed.pos(10);
+ uncompressed.writeInt(uncompressed.size());
+
+ return uncompressed;
+ }
+
+ private struct MessageInfo
+ {
+ public IceInternal.BasicStream stream;
+ public int invokeNum;
+ public int requestId;
+ public byte compress;
+ public IceInternal.ServantManager servantManager;
+ public ObjectAdapter adapter;
+ public IceInternal.OutgoingAsyncBase outAsync;
+ public Ice.AsyncCallback completedCallback;
+ public ConnectionCallback heartbeatCallback;
+ public int messageDispatchCount;
+ }
+
+ private int parseMessage(ref MessageInfo info)
+ {
+ Debug.Assert(_state > StateNotValidated && _state < StateClosed);
+
+ info.stream = new IceInternal.BasicStream(_instance, Util.currentProtocolEncoding);
+ _readStream.swap(info.stream);
+ _readStream.resize(IceInternal.Protocol.headerSize, true);
+ _readStream.pos(0);
+ _readHeader = true;
+
+ Debug.Assert(info.stream.pos() == info.stream.size());
+
+ //
+ // Connection is validated on first message. This is only used by
+ // setState() to check wether or not we can print a connection
+ // warning (a client might close the connection forcefully if the
+ // connection isn't validated).
+ //
+ _validated = true;
+
+ try
+ {
+ //
+ // The magic and version fields have already been checked.
+ //
+ info.stream.pos(8);
+ byte messageType = info.stream.readByte();
+ info.compress = info.stream.readByte();
+ if(info.compress == (byte)2)
+ {
+ if(_compressionSupported)
+ {
+ info.stream = info.stream.uncompress(IceInternal.Protocol.headerSize, _messageSizeMax);
+ }
+ else
+ {
+ FeatureNotSupportedException ex = new FeatureNotSupportedException();
+ ex.unsupportedFeature = "Cannot uncompress compressed message: bzip2 DLL not found";
+ throw ex;
+ }
+ }
+ info.stream.pos(IceInternal.Protocol.headerSize);
+
+ switch(messageType)
+ {
+ case IceInternal.Protocol.closeConnectionMsg:
+ {
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
+ if(_endpoint.datagram())
+ {
+ if(_warn)
+ {
+ _logger.warning("ignoring close connection message for datagram connection:\n" + _desc);
+ }
+ }
+ else
+ {
+ setState(StateClosingPending, new CloseConnectionException());
+
+ //
+ // Notify the the transceiver of the graceful connection closure.
+ //
+ int op = _transceiver.closing(false, _exception);
+ if(op != 0)
+ {
+ return op;
+ }
+ setState(StateClosed);
+ }
+ break;
+ }
+
+ case IceInternal.Protocol.requestMsg:
+ {
+ if(_state >= StateClosing)
+ {
+ IceInternal.TraceUtil.trace("received request during closing\n" +
+ "(ignored by server, client will retry)", info.stream, _logger,
+ _traceLevels);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
+ info.requestId = info.stream.readInt();
+ info.invokeNum = 1;
+ info.servantManager = _servantManager;
+ info.adapter = _adapter;
+ ++info.messageDispatchCount;
+ }
+ break;
+ }
+
+ case IceInternal.Protocol.requestBatchMsg:
+ {
+ if(_state >= StateClosing)
+ {
+ IceInternal.TraceUtil.trace("received batch request during closing\n" +
+ "(ignored by server, client will retry)", info.stream, _logger,
+ _traceLevels);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
+ info.invokeNum = info.stream.readInt();
+ if(info.invokeNum < 0)
+ {
+ info.invokeNum = 0;
+ throw new UnmarshalOutOfBoundsException();
+ }
+ info.servantManager = _servantManager;
+ info.adapter = _adapter;
+ info.messageDispatchCount += info.invokeNum;
+ }
+ break;
+ }
+
+ case IceInternal.Protocol.replyMsg:
+ {
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
+ info.requestId = info.stream.readInt();
+ IceInternal.OutgoingAsyncBase outAsync = null;
+ if(_asyncRequests.TryGetValue(info.requestId, out outAsync))
+ {
+ _asyncRequests.Remove(info.requestId);
+
+ outAsync.getIs().swap(info.stream);
+
+ //
+ // If we just received the reply for a request which isn't acknowledge as
+ // sent yet, we queue the reply instead of processing it right away. It
+ // will be processed once the write callback is invoked for the message.
+ //
+ OutgoingMessage message = _sendStreams.Count > 0 ? _sendStreams.First.Value : null;
+ if(message != null && message.outAsync == outAsync)
+ {
+ message.receivedReply = true;
+ }
+ else
+ {
+ info.completedCallback = outAsync.completed();
+ if(info.completedCallback != null)
+ {
+ info.outAsync = outAsync;
+ ++info.messageDispatchCount;
+ }
+ }
+ System.Threading.Monitor.PulseAll(this); // Notify threads blocked in close(false)
+ }
+ break;
+ }
+
+ case IceInternal.Protocol.validateConnectionMsg:
+ {
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
+ if(_callback != null)
+ {
+ info.heartbeatCallback = _callback;
+ ++info.messageDispatchCount;
+ }
+ break;
+ }
+
+ default:
+ {
+ IceInternal.TraceUtil.trace("received unknown message\n(invalid, closing connection)",
+ info.stream, _logger, _traceLevels);
+ throw new UnknownMessageException();
+ }
+ }
+ }
+ catch(LocalException ex)
+ {
+ if(_endpoint.datagram())
+ {
+ if(_warn)
+ {
+ _logger.warning("datagram connection exception:\n" + ex.ToString() + "\n" + _desc);
+ }
+ }
+ else
+ {
+ setState(StateClosed, ex);
+ }
+ }
+
+ return _state == StateHolding ? IceInternal.SocketOperation.None : IceInternal.SocketOperation.Read;
+ }
+
+ private void invokeAll(IceInternal.BasicStream stream, int invokeNum, int requestId, byte compress,
+ IceInternal.ServantManager servantManager, ObjectAdapter adapter)
+ {
+ //
+ // Note: In contrast to other private or protected methods, this
+ // operation must be called *without* the mutex locked.
+ //
+
+ IceInternal.Incoming inc = null;
+ try
+ {
+ while(invokeNum > 0)
+ {
+ //
+ // Prepare the invocation.
+ //
+ bool response = !_endpoint.datagram() && requestId != 0;
+ Debug.Assert(!response || invokeNum == 1);
+
+ inc = getIncoming(adapter, response, compress, requestId);
+
+ //
+ // Dispatch the invocation.
+ //
+ inc.invoke(servantManager, stream);
+
+ --invokeNum;
+
+ reclaimIncoming(inc);
+ inc = null;
+ }
+
+ stream.clear();
+ }
+ catch(LocalException ex)
+ {
+ invokeException(requestId, ex, invokeNum, false);
+ }
+ finally
+ {
+ if(inc != null)
+ {
+ reclaimIncoming(inc);
+ }
+ }
+ }
+
+ private void scheduleTimeout(int status)
+ {
+ int timeout;
+ if(_state < StateActive)
+ {
+ IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideConnectTimeout)
+ {
+ timeout = defaultsAndOverrides.overrideConnectTimeoutValue;
+ }
+ else
+ {
+ timeout = _endpoint.timeout();
+ }
+ }
+ else if(_state < StateClosingPending)
+ {
+ if(_readHeader) // No timeout for reading the header.
+ {
+ status &= ~IceInternal.SocketOperation.Read;
+ }
+ timeout = _endpoint.timeout();
+ }
+ else
+ {
+ IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideCloseTimeout)
+ {
+ timeout = defaultsAndOverrides.overrideCloseTimeoutValue;
+ }
+ else
+ {
+ timeout = _endpoint.timeout();
+ }
+ }
+
+ if(timeout < 0)
+ {
+ return;
+ }
+
+ if((status & IceInternal.SocketOperation.Read) != 0)
+ {
+ if(_readTimeoutScheduled)
+ {
+ _timer.cancel(_readTimeout);
+ }
+ _timer.schedule(_readTimeout, timeout);
+ _readTimeoutScheduled = true;
+ }
+ if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0)
+ {
+ if(_writeTimeoutScheduled)
+ {
+ _timer.cancel(_writeTimeout);
+ }
+ _timer.schedule(_writeTimeout, timeout);
+ _writeTimeoutScheduled = true;
+ }
+ }
+
+ private void unscheduleTimeout(int status)
+ {
+ if((status & IceInternal.SocketOperation.Read) != 0 && _readTimeoutScheduled)
+ {
+ _timer.cancel(_readTimeout);
+ _readTimeoutScheduled = false;
+ }
+ if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0 &&
+ _writeTimeoutScheduled)
+ {
+ _timer.cancel(_writeTimeout);
+ _writeTimeoutScheduled = false;
+ }
+ }
+
+ private ConnectionInfo initConnectionInfo()
+ {
+ if(_info != null)
+ {
+ return _info;
+ }
+
+ ConnectionInfo info = _transceiver.getInfo();
+ info.connectionId = _endpoint.connectionId();
+ info.adapterName = _adapter != null ? _adapter.getName() : "";
+ info.incoming = _connector == null;
+ if(_state > StateNotInitialized)
+ {
+ _info = info; // Cache the connection information only if initialized.
+ }
+ return info;
+ }
+
+ private void reap()
+ {
+ if(_monitor != null)
+ {
+ _monitor.reap(this);
+ }
+ if(_observer != null)
+ {
+ _observer.detach();
+ }
+ }
+
+ ConnectionState toConnectionState(int state)
+ {
+ return connectionStateMap[state];
+ }
+
+ private void warning(string msg, System.Exception ex)
+ {
+ _logger.warning(msg + ":\n" + ex + "\n" + _transceiver.ToString());
+ }
+
+ private void observerStartRead(IceInternal.Buffer buf)
+ {
+ if(_readStreamPos >= 0)
+ {
+ Debug.Assert(!buf.empty());
+ _observer.receivedBytes(buf.b.position() - _readStreamPos);
+ }
+ _readStreamPos = buf.empty() ? -1 : buf.b.position();
+ }
+
+ private void observerFinishRead(IceInternal.Buffer buf)
+ {
+ if(_readStreamPos == -1)
+ {
+ return;
+ }
+ Debug.Assert(buf.b.position() >= _readStreamPos);
+ _observer.receivedBytes(buf.b.position() - _readStreamPos);
+ _readStreamPos = -1;
+ }
+
+ private void observerStartWrite(IceInternal.Buffer buf)
+ {
+ if(_writeStreamPos >= 0)
+ {
+ Debug.Assert(!buf.empty());
+ _observer.sentBytes(buf.b.position() - _writeStreamPos);
+ }
+ _writeStreamPos = buf.empty() ? -1 : buf.b.position();
+ }
+
+ private void observerFinishWrite(IceInternal.Buffer buf)
+ {
+ if(_writeStreamPos == -1)
+ {
+ return;
+ }
+ if(buf.b.position() > _writeStreamPos)
+ {
+ _observer.sentBytes(buf.b.position() - _writeStreamPos);
+ }
+ _writeStreamPos = -1;
+ }
+
+ private IceInternal.Incoming getIncoming(ObjectAdapter adapter, bool response, byte compress, int requestId)
+ {
+ IceInternal.Incoming inc = null;
+
+ if(_cacheBuffers)
+ {
+ lock(_incomingCacheMutex)
+ {
+ if(_incomingCache == null)
+ {
+ inc = new IceInternal.Incoming(_instance, this, this, adapter, response, compress, requestId);
+ }
+ else
+ {
+ inc = _incomingCache;
+ _incomingCache = _incomingCache.next;
+ inc.reset(_instance, this, this, adapter, response, compress, requestId);
+ inc.next = null;
+ }
+ }
+ }
+ else
+ {
+ inc = new IceInternal.Incoming(_instance, this, this, adapter, response, compress, requestId);
+ }
+
+ return inc;
+ }
+
+ private void reclaimIncoming(IceInternal.Incoming inc)
+ {
+ if(_cacheBuffers)
+ {
+ lock(_incomingCacheMutex)
+ {
+ inc.next = _incomingCache;
+ _incomingCache = inc;
+ //
+ // Clear references to Ice objects as soon as possible.
+ //
+ _incomingCache.reclaim();
+ }
+ }
+ }
+
+ private int read(IceInternal.Buffer buf)
+ {
+ int start = buf.b.position();
+ int op = _transceiver.read(buf, ref _hasMoreData);
+ if(_instance.traceLevels().network >= 3 && buf.b.position() != start)
+ {
+ StringBuilder s = new StringBuilder("received ");
+ if(_endpoint.datagram())
+ {
+ s.Append(buf.b.limit());
+ }
+ else
+ {
+ s.Append(buf.b.position() - start);
+ s.Append(" of ");
+ s.Append(buf.b.limit() - start);
+ }
+ s.Append(" bytes via ");
+ s.Append(_endpoint.protocol());
+ s.Append("\n");
+ s.Append(ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+ return op;
+ }
+
+ private int write(IceInternal.Buffer buf)
+ {
+ int start = buf.b.position();
+ int op = _transceiver.write(buf);
+ if(_instance.traceLevels().network >= 3 && buf.b.position() != start)
+ {
+ StringBuilder s = new StringBuilder("sent ");
+ s.Append(buf.b.position() - start);
+ if(!_endpoint.datagram())
+ {
+ s.Append(" of ");
+ s.Append(buf.b.limit() - start);
+ }
+ s.Append(" bytes via ");
+ s.Append(_endpoint.protocol());
+ s.Append("\n");
+ s.Append(ToString());
+ _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.ToString());
+ }
+ return op;
+ }
+
+ private class OutgoingMessage
+ {
+ internal OutgoingMessage(IceInternal.BasicStream stream, bool compress, bool adopt)
+ {
+ this.stream = stream;
+ this.compress = compress;
+ this._adopt = adopt;
+ this.isSent = false;
+ this.requestId = 0;
+ }
+
+ internal OutgoingMessage(IceInternal.OutgoingAsyncBase outAsync, IceInternal.BasicStream stream,
+ bool compress, int requestId)
+ {
+ this.stream = stream;
+ this.compress = compress;
+ this.outAsync = outAsync;
+ this.requestId = requestId;
+ this.isSent = false;
+ }
+
+ internal void canceled()
+ {
+ Debug.Assert(outAsync != null);
+ outAsync = null;
+ }
+
+ internal void adopt()
+ {
+ if(_adopt)
+ {
+ IceInternal.BasicStream stream = new IceInternal.BasicStream(this.stream.instance(),
+ Util.currentProtocolEncoding);
+ stream.swap(this.stream);
+ this.stream = stream;
+ _adopt = false;
+ }
+ }
+
+ internal bool sent()
+ {
+ if(outAsync != null)
+ {
+ sentCallback = outAsync.sent();
+ }
+ return sentCallback != null || receivedReply;
+ }
+
+ internal void completed(LocalException ex)
+ {
+ if(outAsync != null)
+ {
+ Ice.AsyncCallback cb = outAsync.completed(ex);
+ if(cb != null)
+ {
+ outAsync.invokeCompleted(cb);
+ }
+ }
+ }
+
+ internal IceInternal.BasicStream stream;
+ internal IceInternal.OutgoingAsyncBase outAsync;
+ internal bool receivedReply;
+ internal bool compress;
+ internal int requestId;
+ internal bool _adopt;
+ internal bool prepared;
+ internal bool isSent;
+ internal Ice.AsyncCallback sentCallback = null;
+ }
+
+ private Communicator _communicator;
+ private IceInternal.Instance _instance;
+ private IceInternal.ACMMonitor _monitor;
+ private IceInternal.Transceiver _transceiver;
+ private string _desc;
+ private string _type;
+ private IceInternal.Connector _connector;
+ private IceInternal.EndpointI _endpoint;
+
+ private ObjectAdapter _adapter;
+ private IceInternal.ServantManager _servantManager;
+
+ private Logger _logger;
+ private IceInternal.TraceLevels _traceLevels;
+ private IceInternal.ThreadPool _threadPool;
+
+ private IceInternal.Timer _timer;
+ private IceInternal.TimerTask _writeTimeout;
+ private bool _writeTimeoutScheduled;
+ private IceInternal.TimerTask _readTimeout;
+ private bool _readTimeoutScheduled;
+
+ private StartCallback _startCallback = null;
+
+ private bool _warn;
+ private bool _warnUdp;
+
+ private long _acmLastActivity;
+
+ private int _compressionLevel;
+
+ private int _nextRequestId;
+
+ private Dictionary<int, IceInternal.OutgoingAsyncBase> _asyncRequests =
+ new Dictionary<int, IceInternal.OutgoingAsyncBase>();
+
+ private LocalException _exception;
+
+ private readonly int _messageSizeMax;
+ private IceInternal.BatchRequestQueue _batchRequestQueue;
+
+ private LinkedList<OutgoingMessage> _sendStreams = new LinkedList<OutgoingMessage>();
+
+ private IceInternal.BasicStream _readStream;
+ private bool _readHeader;
+ private IceInternal.BasicStream _writeStream;
+
+ private ConnectionObserver _observer;
+ private int _readStreamPos;
+ private int _writeStreamPos;
+
+ private int _dispatchCount;
+
+ private int _state; // The current state.
+ private bool _shutdownInitiated = false;
+ private bool _initialized = false;
+ private bool _validated = false;
+
+ private IceInternal.Incoming _incomingCache;
+ private object _incomingCacheMutex = new object();
+
+ private static bool _compressionSupported;
+
+ private bool _cacheBuffers;
+
+ private Ice.ConnectionInfo _info;
+
+ private Ice.ConnectionCallback _callback;
+
+ private static ConnectionState[] connectionStateMap = new ConnectionState[] {
+ ConnectionState.ConnectionStateValidating, // StateNotInitialized
+ ConnectionState.ConnectionStateValidating, // StateNotValidated
+ ConnectionState.ConnectionStateActive, // StateActive
+ ConnectionState.ConnectionStateHolding, // StateHolding
+ ConnectionState.ConnectionStateClosing, // StateClosing
+ ConnectionState.ConnectionStateClosing, // StateClosingPending
+ ConnectionState.ConnectionStateClosed, // StateClosed
+ ConnectionState.ConnectionStateClosed, // StateFinished
+ };
+ }
+}
diff --git a/csharp/src/Ice/ConnectionRequestHandler.cs b/csharp/src/Ice/ConnectionRequestHandler.cs
new file mode 100644
index 00000000000..8ddcca74e02
--- /dev/null
+++ b/csharp/src/Ice/ConnectionRequestHandler.cs
@@ -0,0 +1,77 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Ice.Instrumentation;
+
+namespace IceInternal
+{
+ public class ConnectionRequestHandler : RequestHandler
+ {
+ public RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler)
+ {
+ try
+ {
+ if(previousHandler == this)
+ {
+ return newHandler;
+ }
+ else if(previousHandler.getConnection() == _connection)
+ {
+ //
+ // If both request handlers point to the same connection, we also
+ // update the request handler. See bug ICE-5489 for reasons why
+ // this can be useful.
+ //
+ return newHandler;
+ }
+ }
+ catch(Ice.Exception)
+ {
+ // Ignore
+ }
+ return this;
+ }
+
+ public bool sendAsyncRequest(ProxyOutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback)
+ {
+ return outAsync.invokeRemote(_connection, _compress, _response, out sentCallback);
+ }
+
+ public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
+ {
+ _connection.asyncRequestCanceled(outAsync, ex);
+ }
+
+ public Reference getReference()
+ {
+ return _reference;
+ }
+
+ public Ice.ConnectionI getConnection()
+ {
+ return _connection;
+ }
+
+ public ConnectionRequestHandler(Reference @ref, Ice.ConnectionI connection, bool compress)
+ {
+ _reference = @ref;
+ _response = _reference.getMode() == Reference.Mode.ModeTwoway;
+ _connection = connection;
+ _compress = compress;
+ }
+
+ private Reference _reference;
+ private bool _response;
+ private Ice.ConnectionI _connection;
+ private bool _compress;
+ }
+}
diff --git a/csharp/src/Ice/Connector.cs b/csharp/src/Ice/Connector.cs
new file mode 100644
index 00000000000..84046ad4dcd
--- /dev/null
+++ b/csharp/src/Ice/Connector.cs
@@ -0,0 +1,27 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System;
+ using System.Net.Sockets;
+
+ public interface Connector
+ {
+ //
+ // Create a transceiver without blocking. The transceiver may not be fully connected
+ // until its initialize method is called.
+ //
+ Transceiver connect();
+
+ short type();
+ }
+
+}
diff --git a/csharp/src/Ice/DefaultsAndOverrides.cs b/csharp/src/Ice/DefaultsAndOverrides.cs
new file mode 100644
index 00000000000..cfe64b77076
--- /dev/null
+++ b/csharp/src/Ice/DefaultsAndOverrides.cs
@@ -0,0 +1,229 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Net;
+using System.Text;
+
+namespace IceInternal
+{
+
+ public sealed class DefaultsAndOverrides
+ {
+ internal DefaultsAndOverrides(Ice.Properties properties, Ice.Logger logger)
+ {
+ string val;
+
+ defaultProtocol = properties.getPropertyWithDefault("Ice.Default.Protocol", "tcp");
+
+ val = properties.getProperty("Ice.Default.Host");
+ if(val.Length != 0)
+ {
+ defaultHost = val;
+ }
+ else
+ {
+ defaultHost = null;
+ }
+
+ val = properties.getProperty("Ice.Default.SourceAddress");
+ if(val.Length > 0)
+ {
+ defaultSourceAddress = Network.getNumericAddress(val);
+ if(defaultSourceAddress == null)
+ {
+ throw new Ice.InitializationException("invalid IP address set for Ice.Default.SourceAddress: `" +
+ val + "'");
+ }
+ }
+ else
+ {
+ defaultSourceAddress = null;
+ }
+
+ val = properties.getProperty("Ice.Override.Timeout");
+ if(val.Length > 0)
+ {
+ overrideTimeout = true;
+ overrideTimeoutValue = properties.getPropertyAsInt("Ice.Override.Timeout");
+ if(overrideTimeoutValue < 1 && overrideTimeoutValue != -1)
+ {
+ overrideTimeoutValue = -1;
+ StringBuilder msg = new StringBuilder("invalid value for Ice.Override.Timeout `");
+ msg.Append(properties.getProperty("Ice.Override.Timeout"));
+ msg.Append("': defaulting to -1");
+ logger.warning(msg.ToString());
+ }
+ }
+ else
+ {
+ overrideTimeout = false;
+ overrideTimeoutValue = -1;
+ }
+
+ val = properties.getProperty("Ice.Override.ConnectTimeout");
+ if(val.Length > 0)
+ {
+ overrideConnectTimeout = true;
+ overrideConnectTimeoutValue = properties.getPropertyAsInt("Ice.Override.ConnectTimeout");
+ if(overrideConnectTimeoutValue < 1 && overrideConnectTimeoutValue != -1)
+ {
+ overrideConnectTimeoutValue = -1;
+ StringBuilder msg = new StringBuilder("invalid value for Ice.Override.ConnectTimeout `");
+ msg.Append(properties.getProperty("Ice.Override.ConnectTimeout"));
+ msg.Append("': defaulting to -1");
+ logger.warning(msg.ToString());
+ }
+ }
+ else
+ {
+ overrideConnectTimeout = false;
+ overrideConnectTimeoutValue = -1;
+ }
+
+ val = properties.getProperty("Ice.Override.CloseTimeout");
+ if(val.Length > 0)
+ {
+ overrideCloseTimeout = true;
+ overrideCloseTimeoutValue = properties.getPropertyAsInt("Ice.Override.CloseTimeout");
+ if(overrideCloseTimeoutValue < 1 && overrideCloseTimeoutValue != -1)
+ {
+ overrideCloseTimeoutValue = -1;
+ StringBuilder msg = new StringBuilder("invalid value for Ice.Override.CloseTimeout `");
+ msg.Append(properties.getProperty("Ice.Override.CloseTimeout"));
+ msg.Append("': defaulting to -1");
+ logger.warning(msg.ToString());
+ }
+ }
+ else
+ {
+ overrideCloseTimeout = false;
+ overrideCloseTimeoutValue = -1;
+ }
+
+#if COMPACT
+ overrideCompress = false;
+ overrideCompressValue = false;
+#else
+ val = properties.getProperty("Ice.Override.Compress");
+ if(val.Length > 0)
+ {
+ overrideCompress = true;
+ overrideCompressValue = properties.getPropertyAsInt("Ice.Override.Compress") > 0;
+ if(!BasicStream.compressible() && overrideCompressValue)
+ {
+ string lib = AssemblyUtil.runtime_ == AssemblyUtil.Runtime.Mono ? "bzip2 library" : "bzip2.dll";
+ Console.Error.WriteLine("warning: " + lib + " not found, Ice.Override.Compress ignored.");
+ overrideCompressValue = false;
+ }
+ }
+ else
+ {
+ overrideCompress = !BasicStream.compressible();
+ overrideCompressValue = false;
+ }
+#endif
+
+ val = properties.getProperty("Ice.Override.Secure");
+ if(val.Length > 0)
+ {
+ overrideSecure = true;
+ overrideSecureValue = properties.getPropertyAsInt("Ice.Override.Secure") > 0;
+ }
+ else
+ {
+ overrideSecure = false;
+ overrideSecureValue = false;
+ }
+
+ defaultCollocationOptimization =
+ properties.getPropertyAsIntWithDefault("Ice.Default.CollocationOptimized", 1) > 0;
+
+ val = properties.getPropertyWithDefault("Ice.Default.EndpointSelection", "Random");
+ if(val.Equals("Random"))
+ {
+ defaultEndpointSelection = Ice.EndpointSelectionType.Random;
+ }
+ else if(val.Equals("Ordered"))
+ {
+ defaultEndpointSelection = Ice.EndpointSelectionType.Ordered;
+ }
+ else
+ {
+ Ice.EndpointSelectionTypeParseException ex = new Ice.EndpointSelectionTypeParseException();
+ ex.str = "illegal value `" + val + "'; expected `Random' or `Ordered'";
+ throw ex;
+ }
+
+ defaultTimeout = properties.getPropertyAsIntWithDefault("Ice.Default.Timeout", 60000);
+ if(defaultTimeout < 1 && defaultTimeout != -1)
+ {
+ defaultTimeout = 60000;
+ StringBuilder msg = new StringBuilder("invalid value for Ice.Default.Timeout `");
+ msg.Append(properties.getProperty("Ice.Default.Timeout"));
+ msg.Append("': defaulting to 60000");
+ logger.warning(msg.ToString());
+ }
+
+ defaultLocatorCacheTimeout = properties.getPropertyAsIntWithDefault("Ice.Default.LocatorCacheTimeout", -1);
+ if(defaultLocatorCacheTimeout < -1)
+ {
+ defaultLocatorCacheTimeout = -1;
+ StringBuilder msg = new StringBuilder("invalid value for Ice.Default.LocatorCacheTimeout `");
+ msg.Append(properties.getProperty("Ice.Default.LocatorCacheTimeout"));
+ msg.Append("': defaulting to -1");
+ logger.warning(msg.ToString());
+ }
+
+ defaultInvocationTimeout = properties.getPropertyAsIntWithDefault("Ice.Default.InvocationTimeout", -1);
+ if(defaultInvocationTimeout < 1 && defaultInvocationTimeout != -1 && defaultInvocationTimeout != -2)
+ {
+ defaultInvocationTimeout = -1;
+ StringBuilder msg = new StringBuilder("invalid value for Ice.Default.InvocationTimeout `");
+ msg.Append(properties.getProperty("Ice.Default.InvocationTimeout"));
+ msg.Append("': defaulting to -1");
+ logger.warning(msg.ToString());
+ }
+
+ defaultPreferSecure = properties.getPropertyAsIntWithDefault("Ice.Default.PreferSecure", 0) > 0;
+
+ val = properties.getPropertyWithDefault("Ice.Default.EncodingVersion",
+ Ice.Util.encodingVersionToString(Ice.Util.currentEncoding));
+ defaultEncoding = Ice.Util.stringToEncodingVersion(val);
+ Protocol.checkSupportedEncoding(defaultEncoding);
+
+ bool slicedFormat = properties.getPropertyAsIntWithDefault("Ice.Default.SlicedFormat", 0) > 0;
+ defaultFormat = slicedFormat ? Ice.FormatType.SlicedFormat : Ice.FormatType.CompactFormat;
+ }
+
+ public string defaultHost;
+ public EndPoint defaultSourceAddress;
+ public string defaultProtocol;
+ public bool defaultCollocationOptimization;
+ public Ice.EndpointSelectionType defaultEndpointSelection;
+ public int defaultTimeout;
+ public int defaultLocatorCacheTimeout;
+ public int defaultInvocationTimeout;
+ public bool defaultPreferSecure;
+ public Ice.EncodingVersion defaultEncoding;
+ public Ice.FormatType defaultFormat;
+
+ public bool overrideTimeout;
+ public int overrideTimeoutValue;
+ public bool overrideConnectTimeout;
+ public int overrideConnectTimeoutValue;
+ public bool overrideCloseTimeout;
+ public int overrideCloseTimeoutValue;
+ public bool overrideCompress;
+ public bool overrideCompressValue;
+ public bool overrideSecure;
+ public bool overrideSecureValue;
+ }
+
+}
diff --git a/csharp/src/Ice/DictionaryBase.cs b/csharp/src/Ice/DictionaryBase.cs
new file mode 100644
index 00000000000..ed3b8f28d1a
--- /dev/null
+++ b/csharp/src/Ice/DictionaryBase.cs
@@ -0,0 +1,355 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections.Generic;
+
+namespace IceInternal
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public abstract class DictionaryBase<KT, VT> : System.Collections.IDictionary
+ {
+ protected Dictionary<KT, VT> dict_;
+
+ public DictionaryBase()
+ {
+ dict_ = new Dictionary<KT, VT>();
+ }
+
+ public int Count
+ {
+ get
+ {
+ return dict_.Count;
+ }
+ }
+
+ public void Clear()
+ {
+ dict_.Clear();
+ }
+
+ public void CopyTo(System.Array a__, int index)
+ {
+ if(a__ == null)
+ {
+ throw new ArgumentNullException("a__", "Cannot copy to null array");
+ }
+ if(index < 0)
+ {
+ throw new ArgumentException("Array index cannot be less than zero", "index");
+ }
+ if(index >= a__.Length)
+ {
+ throw new ArgumentException("Array index must less than array length");
+ }
+ if(dict_.Count > a__.Length - index)
+ {
+ throw new ArgumentException("Insufficient room in target array beyond index");
+ }
+ if(a__.Rank > 1)
+ {
+ throw new ArgumentException("Cannot copy to multidimensional array", "a__");
+ }
+ Type t = a__.GetType().GetElementType();
+ if(!t.IsAssignableFrom(typeof(System.Collections.DictionaryEntry)))
+ {
+ throw new ArgumentException("Cannot assign DictionaryEntry to target array", "a__");
+ }
+
+ IEnumerator<KeyValuePair<KT, VT>> e = dict_.GetEnumerator();
+ while(e.MoveNext())
+ {
+ a__.SetValue(new System.Collections.DictionaryEntry(e.Current.Key, e.Current.Value), index++);
+ }
+ }
+
+ public override bool Equals(object other)
+ {
+ if(object.ReferenceEquals(this, other))
+ {
+ return true;
+ }
+ if(other == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ DictionaryBase<KT, VT> d2 = (DictionaryBase<KT, VT>)other;
+
+ if(dict_.Count != d2.dict_.Count)
+ {
+ return false;
+ }
+ if(Count == 0)
+ {
+ return true;
+ }
+
+ //
+ // Compare both sets of keys. Keys are unique and non-null.
+ //
+ Dictionary<KT, VT>.KeyCollection keys1 = dict_.Keys;
+ Dictionary<KT, VT>.KeyCollection keys2 = d2.dict_.Keys;
+ KT[] ka1 = new KT[dict_.Count];
+ KT[] ka2 = new KT[d2.dict_.Count];
+ keys1.CopyTo(ka1, 0);
+ keys2.CopyTo(ka2, 0);
+ Array.Sort(ka1);
+ Array.Sort(ka2);
+
+ for(int i = 0; i < ka1.Length; ++i)
+ {
+ if(!Equals(ka1[i], ka2[i]))
+ {
+ return false;
+ }
+ if(!Equals(dict_[ka1[i]], d2.dict_[ka1[i]]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+ }
+
+ public static bool operator==(DictionaryBase<KT, VT> lhs__, DictionaryBase<KT, VT> rhs__)
+ {
+ return Equals(lhs__, rhs__);
+ }
+
+ public static bool operator!=(DictionaryBase<KT, VT> lhs__, DictionaryBase<KT, VT> rhs__)
+ {
+ return !Equals(lhs__, rhs__);
+ }
+
+ public override int GetHashCode()
+ {
+ int h = 5381;
+ foreach(KeyValuePair<KT, VT> kvp in dict_)
+ {
+ IceInternal.HashUtil.hashAdd(ref h, kvp.Key);
+ IceInternal.HashUtil.hashAdd(ref h, kvp.Value);
+ }
+ return h;
+ }
+
+ public class CEnumerator : System.Collections.IDictionaryEnumerator
+ {
+ public CEnumerator(IEnumerator<KeyValuePair<KT, VT>> e)
+ {
+ _e = e;
+ }
+
+ public bool MoveNext()
+ {
+ return _e.MoveNext();
+ }
+
+ public object Current
+ {
+ get
+ {
+ return new System.Collections.DictionaryEntry(_e.Current.Key, _e.Current.Value);
+ }
+ }
+
+ public System.Collections.DictionaryEntry Entry
+ {
+ get
+ {
+ return new System.Collections.DictionaryEntry(_e.Current.Key, _e.Current.Value);
+ }
+ }
+
+ public object Key
+ {
+ get
+ {
+ return _e.Current.Key;
+ }
+ }
+
+ public object Value
+ {
+ get
+ {
+ return _e.Current.Value;
+ }
+ }
+
+ public void Reset()
+ {
+ _e.Reset();
+ }
+
+ private IEnumerator<KeyValuePair<KT, VT>> _e;
+ }
+
+ public System.Collections.IEnumerator GetEnumerator()
+ {
+ return new CEnumerator(dict_.GetEnumerator());
+ }
+
+ public bool IsFixedSize
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool IsSynchronized
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public object SyncRoot
+ {
+ get
+ {
+ return this;
+ }
+ }
+
+ public VT this[KT key]
+ {
+ get
+ {
+ return dict_[key];
+ }
+ set
+ {
+ dict_[key] = value;
+ }
+ }
+
+ public System.Collections.ICollection Keys
+ {
+ get
+ {
+ return dict_.Keys;
+ }
+ }
+
+ public System.Collections.ICollection Values
+ {
+ get
+ {
+ return dict_.Values;
+ }
+ }
+
+ public void Add(KT key, VT value)
+ {
+ try
+ {
+ dict_.Add(key, value);
+ }
+ catch(ArgumentException)
+ {
+ // Ignore.
+ }
+ }
+
+ public void Remove(KT key)
+ {
+ dict_.Remove(key);
+ }
+
+ public bool Contains(KT key)
+ {
+ return dict_.ContainsKey(key);
+ }
+
+ public void Add(object key, object value)
+ {
+ checkKeyType(key);
+ checkValueType(value);
+ Add((KT)key, (VT)value);
+ }
+
+ public void Remove(object key)
+ {
+ checkKeyType(key);
+ Remove((KT)key);
+ }
+
+ public bool Contains(object key)
+ {
+ return dict_.ContainsKey((KT)key);
+ }
+
+ System.Collections.IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator()
+ {
+ return new CEnumerator(dict_.GetEnumerator());
+ }
+
+ public object this[object key]
+ {
+ get
+ {
+ checkKeyType(key);
+ return dict_[(KT)key];
+ }
+ set
+ {
+ checkKeyType(key);
+ checkValueType(value);
+ dict_[(KT)key] = (VT)value;
+ }
+ }
+
+ private void checkKeyType(object o)
+ {
+ if(o != null && !(o is KT))
+ {
+ throw new ArgumentException("Cannot use a key of type " + o.GetType().ToString()
+ + " for a dictionary with key type " + typeof(KT).ToString());
+ }
+ }
+
+ private void checkValueType(object o)
+ {
+ if(o != null && !(o is KT))
+ {
+ throw new ArgumentException("Cannot use a value of type " + o.GetType().ToString()
+ + " for a dictionary with value type " + typeof(VT).ToString());
+ }
+ }
+ }
+}
+
+namespace Ice
+{
+ [Obsolete("This class is deprecated.")]
+ public abstract class DictionaryBase<KT, VT> : IceInternal.DictionaryBase<KT, VT>
+ {
+ }
+}
diff --git a/csharp/src/Ice/DispatchInterceptor.cs b/csharp/src/Ice/DispatchInterceptor.cs
new file mode 100644
index 00000000000..d5a1cc9260f
--- /dev/null
+++ b/csharp/src/Ice/DispatchInterceptor.cs
@@ -0,0 +1,68 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Diagnostics;
+
+namespace Ice
+{
+ /// <summary>
+ /// Base class that allows a server intercept incoming requests.
+ /// The application must derive a concrete class from DispatchInterceptor
+ /// that implements the DispatchInterceptor.dispatch operation. An instance of this derived
+ /// class can be registered with an object adapter like any other servant.
+ /// A dispatch interceptor is useful particularly to automatically retry requests
+ /// that have failed due to a recoverable error condition.
+ /// </summary>
+ public abstract class DispatchInterceptor : Ice.ObjectImpl
+ {
+ /// <summary>
+ /// Called by the Ice run time to dispatch an incoming request. The implementation
+ /// of <code>dispatch</code> must dispatch the request to the actual servant.
+ /// </summary>
+ /// <param name="request">The details of the incoming request.</param>
+ /// <returns>For synchronous dispatch, the return value must be whatever is
+ /// returned ice_dispatch. For asynchronous dispatch, the return
+ /// value must be DispatchAsync.</returns>
+ public abstract DispatchStatus
+ dispatch(Request request);
+
+ public override DispatchStatus
+ dispatch__(IceInternal.Incoming inc, Current current)
+ {
+ try
+ {
+ DispatchStatus status = dispatch(inc);
+ if(status != DispatchStatus.DispatchAsync)
+ {
+ //
+ // Make sure 'inc' owns the connection etc.
+ //
+ inc.killAsync();
+ }
+ return status;
+ }
+ catch(ResponseSentException)
+ {
+ return DispatchStatus.DispatchAsync;
+ }
+ catch(System.Exception)
+ {
+ try
+ {
+ inc.killAsync();
+ throw;
+ }
+ catch(ResponseSentException)
+ {
+ return DispatchStatus.DispatchAsync;
+ }
+ }
+ }
+ }
+}
diff --git a/csharp/src/Ice/EndpointFactory.cs b/csharp/src/Ice/EndpointFactory.cs
new file mode 100644
index 00000000000..d1fd14312fa
--- /dev/null
+++ b/csharp/src/Ice/EndpointFactory.cs
@@ -0,0 +1,25 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Collections.Generic;
+
+ public interface EndpointFactory
+ {
+ short type();
+ string protocol();
+ EndpointI create(List<string> args, bool oaEndpoint);
+ EndpointI read(BasicStream s);
+ void destroy();
+
+ EndpointFactory clone(ProtocolInstance instance);
+ }
+
+}
diff --git a/csharp/src/Ice/EndpointFactoryManager.cs b/csharp/src/Ice/EndpointFactoryManager.cs
new file mode 100644
index 00000000000..1f52ffeb605
--- /dev/null
+++ b/csharp/src/Ice/EndpointFactoryManager.cs
@@ -0,0 +1,203 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Text.RegularExpressions;
+
+ public sealed class EndpointFactoryManager
+ {
+ internal EndpointFactoryManager(Instance instance)
+ {
+ instance_ = instance;
+ _factories = new List<EndpointFactory>();
+ }
+
+ public void add(EndpointFactory factory)
+ {
+ lock(this)
+ {
+ for(int i = 0; i < _factories.Count; i++)
+ {
+ EndpointFactory f = (EndpointFactory)_factories[i];
+ if(f.type() == factory.type())
+ {
+ Debug.Assert(false);
+ }
+ }
+ _factories.Add(factory);
+ }
+ }
+
+ public EndpointFactory get(short type)
+ {
+ lock(this)
+ {
+ for(int i = 0; i < _factories.Count; i++)
+ {
+ EndpointFactory f = (EndpointFactory)_factories[i];
+ if(f.type() == type)
+ {
+ return f;
+ }
+ }
+ return null;
+ }
+ }
+
+ public EndpointI create(string str, bool oaEndpoint)
+ {
+ string[] arr = IceUtilInternal.StringUtil.splitString(str, " \t\r\n");
+ if(arr == null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "mismatched quote";
+ throw e;
+ }
+
+ if(arr.Length == 0)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "value has no non-whitespace characters";
+ throw e;
+ }
+
+ List<string> v = new List<string>(arr);
+ string protocol = v[0];
+ v.RemoveAt(0);
+
+ if(protocol.Equals("default"))
+ {
+ protocol = instance_.defaultsAndOverrides().defaultProtocol;
+ }
+
+ EndpointFactory factory = null;
+
+ lock(this)
+ {
+ for(int i = 0; i < _factories.Count; i++)
+ {
+ EndpointFactory f = _factories[i];
+ if(f.protocol().Equals(protocol))
+ {
+ factory = f;
+ }
+ }
+ }
+
+ if(factory != null)
+ {
+ EndpointI e = factory.create(v, oaEndpoint);
+ if(v.Count > 0)
+ {
+ Ice.EndpointParseException ex = new Ice.EndpointParseException();
+ ex.str = "unrecognized argument `" + v[0] + "' in endpoint `" + str + "'";
+ throw ex;
+ }
+ return e;
+
+ // Code below left in place for debugging.
+
+ /*
+ EndpointI e = f.create(s.Substring(m.Index + m.Length), oaEndpoint);
+ BasicStream bs = new BasicStream(instance_, true);
+ e.streamWrite(bs);
+ Buffer buf = bs.getBuffer();
+ buf.b.position(0);
+ short type = bs.readShort();
+ EndpointI ue = new IceInternal.OpaqueEndpointI(type, bs);
+ System.Console.Error.WriteLine("Normal: " + e);
+ System.Console.Error.WriteLine("Opaque: " + ue);
+ return e;
+ */
+ }
+
+ //
+ // If the stringified endpoint is opaque, create an unknown endpoint,
+ // then see whether the type matches one of the known endpoints.
+ //
+ if(protocol.Equals("opaque"))
+ {
+ EndpointI ue = new OpaqueEndpointI(v);
+ if(v.Count > 0)
+ {
+ Ice.EndpointParseException ex = new Ice.EndpointParseException();
+ ex.str = "unrecognized argument `" + v[0] + "' in endpoint `" + str + "'";
+ throw ex;
+ }
+ factory = get(ue.type());
+ if(factory != null)
+ {
+ //
+ // Make a temporary stream, write the opaque endpoint data into the stream,
+ // and ask the factory to read the endpoint data from that stream to create
+ // the actual endpoint.
+ //
+ BasicStream bs = new BasicStream(instance_, Ice.Util.currentProtocolEncoding);
+ bs.writeShort(ue.type());
+ ue.streamWrite(bs);
+ Buffer buf = bs.getBuffer();
+ buf.b.position(0);
+ buf.b.limit(buf.size());
+ bs.readShort(); // type
+ bs.startReadEncaps();
+ EndpointI e = factory.read(bs);
+ bs.endReadEncaps();
+ return e;
+ }
+ return ue; // Endpoint is opaque, but we don't have a factory for its type.
+ }
+
+ return null;
+ }
+
+ public EndpointI read(BasicStream s)
+ {
+ lock(this)
+ {
+ short type = s.readShort();
+
+ EndpointFactory factory = get(type);
+ EndpointI e = null;
+
+ s.startReadEncaps();
+
+ if(factory != null)
+ {
+ e = factory.read(s);
+ }
+ else
+ {
+ e = new OpaqueEndpointI(type, s);
+ }
+
+ s.endReadEncaps();
+
+ return e;
+ }
+ }
+
+ internal void destroy()
+ {
+ for(int i = 0; i < _factories.Count; i++)
+ {
+ EndpointFactory f = (EndpointFactory)_factories[i];
+ f.destroy();
+ }
+ _factories.Clear();
+ }
+
+ private readonly Instance instance_;
+ private readonly List<EndpointFactory> _factories;
+ }
+
+}
diff --git a/csharp/src/Ice/EndpointHostResolver.cs b/csharp/src/Ice/EndpointHostResolver.cs
new file mode 100644
index 00000000000..d34edbed66a
--- /dev/null
+++ b/csharp/src/Ice/EndpointHostResolver.cs
@@ -0,0 +1,292 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#if !SILVERLIGHT
+namespace IceInternal
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Threading;
+
+ public class EndpointHostResolver
+ {
+ internal EndpointHostResolver(Instance instance)
+ {
+ _instance = instance;
+ _protocol = instance.protocolSupport();
+ _preferIPv6 = instance.preferIPv6();
+ _thread = new HelperThread(this);
+ updateObserver();
+ if(instance.initializationData().properties.getProperty("Ice.ThreadPriority").Length > 0)
+ {
+ ThreadPriority priority = IceInternal.Util.stringToThreadPriority(
+ instance.initializationData().properties.getProperty("Ice.ThreadPriority"));
+ _thread.Start(priority);
+ }
+ else
+ {
+ _thread.Start(ThreadPriority.Normal);
+ }
+ }
+
+ public void resolve(string host, int port, Ice.EndpointSelectionType selType, IPEndpointI endpoint,
+ EndpointI_connectors callback)
+ {
+ //
+ // Try to get the addresses without DNS lookup. If this doesn't work, we queue a resolve
+ // entry and the thread will take care of getting the endpoint addresses.
+ //
+ NetworkProxy networkProxy = _instance.networkProxy();
+ if(networkProxy == null)
+ {
+ try
+ {
+ List<EndPoint> addrs = Network.getAddresses(host, port, _protocol, selType, _preferIPv6, false);
+ if(addrs.Count > 0)
+ {
+ callback.connectors(endpoint.connectors(addrs, null));
+ return;
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ callback.exception(ex);
+ return;
+ }
+ }
+
+ lock(this)
+ {
+ Debug.Assert(!_destroyed);
+
+ ResolveEntry entry = new ResolveEntry();
+ entry.host = host;
+ entry.port = port;
+ entry.selType = selType;
+ entry.endpoint = endpoint;
+ entry.callback = callback;
+
+ Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer;
+ if(obsv != null)
+ {
+ entry.observer = obsv.getEndpointLookupObserver(endpoint);
+ if(entry.observer != null)
+ {
+ entry.observer.attach();
+ }
+ }
+
+ _queue.AddLast(entry);
+ System.Threading.Monitor.Pulse(this);
+ }
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ Debug.Assert(!_destroyed);
+ _destroyed = true;
+ System.Threading.Monitor.Pulse(this);
+ }
+ }
+
+ public void joinWithThread()
+ {
+ if(_thread != null)
+ {
+ _thread.Join();
+ }
+ }
+
+ public void run()
+ {
+ while(true)
+ {
+ ResolveEntry r;
+ Ice.Instrumentation.ThreadObserver threadObserver;
+
+ lock(this)
+ {
+ while(!_destroyed && _queue.Count == 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ if(_destroyed)
+ {
+ break;
+ }
+
+ r = _queue.First.Value;
+ _queue.RemoveFirst();
+ threadObserver = _observer;
+ }
+
+ if(threadObserver != null)
+ {
+ threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle,
+ Ice.Instrumentation.ThreadState.ThreadStateInUseForOther);
+ }
+
+ try
+ {
+
+ NetworkProxy networkProxy = _instance.networkProxy();
+ int protocol = _protocol;
+ if(networkProxy != null)
+ {
+ networkProxy = networkProxy.resolveHost(protocol);
+ if(networkProxy != null)
+ {
+ protocol = networkProxy.getProtocolSupport();
+ }
+ }
+
+ r.callback.connectors(r.endpoint.connectors(Network.getAddresses(r.host,
+ r.port,
+ protocol,
+ r.selType,
+ _preferIPv6,
+ true),
+ networkProxy));
+ }
+ catch(Ice.LocalException ex)
+ {
+ if(r.observer != null)
+ {
+ r.observer.failed(ex.ice_name());
+ }
+ r.callback.exception(ex);
+ }
+ finally
+ {
+ if(threadObserver != null)
+ {
+ threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForOther,
+ Ice.Instrumentation.ThreadState.ThreadStateIdle);
+ }
+ if(r.observer != null)
+ {
+ r.observer.detach();
+ }
+ }
+ }
+
+ foreach(ResolveEntry entry in _queue)
+ {
+ Ice.CommunicatorDestroyedException ex = new Ice.CommunicatorDestroyedException();
+ if(entry.observer != null)
+ {
+ entry.observer.failed(ex.ice_name());
+ entry.observer.detach();
+ }
+ entry.callback.exception(ex);
+ }
+ _queue.Clear();
+
+ if(_observer != null)
+ {
+ _observer.detach();
+ }
+ }
+
+ public void
+ updateObserver()
+ {
+ lock(this)
+ {
+ Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer;
+ if(obsv != null)
+ {
+ _observer = obsv.getThreadObserver("Communicator",
+ _thread.getName(),
+ Ice.Instrumentation.ThreadState.ThreadStateIdle,
+ _observer);
+ if(_observer != null)
+ {
+ _observer.attach();
+ }
+ }
+ }
+ }
+
+ private class ResolveEntry
+ {
+ internal string host;
+ internal int port;
+ internal Ice.EndpointSelectionType selType;
+ internal IPEndpointI endpoint;
+ internal EndpointI_connectors callback;
+ internal Ice.Instrumentation.Observer observer;
+ }
+
+ private readonly Instance _instance;
+ private readonly int _protocol;
+ private readonly bool _preferIPv6;
+ private bool _destroyed;
+ private LinkedList<ResolveEntry> _queue = new LinkedList<ResolveEntry>();
+ private Ice.Instrumentation.ThreadObserver _observer;
+
+ private sealed class HelperThread
+ {
+ internal HelperThread(EndpointHostResolver resolver)
+ {
+ _resolver = resolver;
+ _name = _resolver._instance.initializationData().properties.getProperty("Ice.ProgramName");
+ if(_name.Length > 0)
+ {
+ _name += "-";
+ }
+ _name += "Ice.HostResolver";
+ }
+
+ public void Join()
+ {
+ _thread.Join();
+ }
+
+ public void Start(ThreadPriority priority)
+ {
+ _thread = new Thread(new ThreadStart(Run));
+ _thread.IsBackground = true;
+ _thread.Name = _name;
+ _thread.Priority = priority;
+ _thread.Start();
+ }
+
+ public void Run()
+ {
+ try
+ {
+ _resolver.run();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception in endpoint host resolver thread " + _name + ":\n" + ex;
+ _resolver._instance.initializationData().logger.error(s);
+ }
+ }
+
+ public string getName()
+ {
+ return _name;
+ }
+
+ private EndpointHostResolver _resolver;
+ private string _name;
+ private Thread _thread;
+ }
+
+ private HelperThread _thread;
+ }
+}
+#endif
diff --git a/csharp/src/Ice/EndpointI.cs b/csharp/src/Ice/EndpointI.cs
new file mode 100644
index 00000000000..4f02c43daa4
--- /dev/null
+++ b/csharp/src/Ice/EndpointI.cs
@@ -0,0 +1,209 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Net;
+ using System;
+
+ public interface EndpointI_connectors
+ {
+ void connectors(List<Connector> connectors);
+ void exception(Ice.LocalException ex);
+ }
+
+ public abstract class EndpointI : Ice.Endpoint, System.IComparable<EndpointI>
+ {
+ public override string ToString()
+ {
+ return ice_toString_();
+ }
+
+ public virtual string ice_toString_()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ return protocol() + options();
+ }
+
+ public abstract Ice.EndpointInfo getInfo();
+
+ public override bool Equals(object obj)
+ {
+ if(!(obj is EndpointI))
+ {
+ return false;
+ }
+ return CompareTo((EndpointI)obj) == 0;
+ }
+
+ public override int GetHashCode() // Avoids a compiler warning.
+ {
+ Debug.Assert(false);
+ return 0;
+ }
+
+ //
+ // Marshal the endpoint.
+ //
+ public abstract void streamWrite(BasicStream s);
+
+ //
+ // Return the endpoint type.
+ //
+ public abstract short type();
+
+ //
+ // Return the protocol name.
+ //
+ public abstract string protocol();
+
+ //
+ // Return the timeout for the endpoint in milliseconds. 0 means
+ // non-blocking, -1 means no timeout.
+ //
+ public abstract int timeout();
+
+ //
+ // Return a new endpoint with a different timeout value, provided
+ // that timeouts are supported by the endpoint. Otherwise the same
+ // endpoint is returned.
+ //
+ public abstract EndpointI timeout(int t);
+
+ //
+ // Return the connection ID.
+ //
+ public abstract string connectionId();
+
+ //
+ // Return a new endpoint with a different connection id.
+ //
+ public abstract EndpointI connectionId(string connectionId);
+
+ //
+ // Return true if the endpoints support bzip2 compress, or false
+ // otherwise.
+ //
+ public abstract bool compress();
+
+ //
+ // Return a new endpoint with a different compression value,
+ // provided that compression is supported by the
+ // endpoint. Otherwise the same endpoint is returned.
+ //
+ public abstract EndpointI compress(bool co);
+
+ //
+ // Return true if the endpoint is datagram-based.
+ //
+ public abstract bool datagram();
+
+ //
+ // Return true if the endpoint is secure.
+ //
+ public abstract bool secure();
+
+ //
+ // Return a server side transceiver for this endpoint, or null if a
+ // transceiver can only be created by an acceptor.
+ //
+ public abstract Transceiver transceiver();
+
+ //
+ // Return a connector for this endpoint, or empty list if no connector
+ // is available.
+ //
+ public abstract void connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback);
+
+ //
+ // Return an acceptor for this endpoint, or null if no acceptors
+ // is available.
+ //
+ public abstract Acceptor acceptor(string adapterName);
+
+ //
+ // Expand endpoint out in to separate endpoints for each local
+ // host if listening on INADDR_ANY on server side or if no host
+ // was specified on client side.
+ //
+ public abstract List<EndpointI> expand();
+
+ //
+ // Check whether the endpoint is equivalent to another one.
+ //
+ public abstract bool equivalent(EndpointI endpoint);
+
+ public abstract int CompareTo(EndpointI obj);
+
+ public abstract string options();
+
+ public virtual void initWithOptions(List<string> args)
+ {
+ List<string> unknown = new List<string>();
+
+ string str = "`" + protocol() + " ";
+ foreach(string p in args)
+ {
+ if(IceUtilInternal.StringUtil.findFirstOf(p, " \t\n\r") != -1)
+ {
+ str += " \"" + p + "\"";
+ }
+ else
+ {
+ str += " " + p;
+ }
+ }
+ str += "'";
+
+ for(int n = 0; n < args.Count; ++n)
+ {
+ string option = args[n];
+ if(option.Length < 2 || option[0] != '-')
+ {
+ unknown.Add(option);
+ continue;
+ }
+
+ string argument = null;
+ if(n + 1 < args.Count && args[n + 1][0] != '-')
+ {
+ argument = args[++n];
+ }
+
+ if(!checkOption(option, argument, str))
+ {
+ unknown.Add(option);
+ if(argument != null)
+ {
+ unknown.Add(argument);
+ }
+ }
+ }
+
+ args.Clear();
+ args.AddRange(unknown);
+ }
+
+ protected virtual bool checkOption(string option, string argument, string endpoint)
+ {
+ // Must be overridden to check for options.
+ return false;
+ }
+ }
+
+}
diff --git a/csharp/src/Ice/EventHandler.cs b/csharp/src/Ice/EventHandler.cs
new file mode 100644
index 00000000000..8cb8371df40
--- /dev/null
+++ b/csharp/src/Ice/EventHandler.cs
@@ -0,0 +1,43 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+using System;
+
+public abstract class EventHandler
+{
+ //
+ // Called to start a new asynchronous read or write operation.
+ //
+ abstract public bool startAsync(int op, AsyncCallback cb, ref bool completedSynchronously);
+
+ abstract public bool finishAsync(int op);
+
+ //
+ // Called when there's a message ready to be processed.
+ //
+ abstract public void message(ref ThreadPoolCurrent op);
+
+ //
+ // Called when the event handler is unregistered.
+ //
+ abstract public void finished(ref ThreadPoolCurrent op);
+
+ internal int _ready = 0;
+ internal int _pending = 0;
+ internal int _started = 0;
+ internal bool _finish = false;
+
+ internal bool _hasMoreData = false;
+ internal int _registered = 0;
+}
+
+}
diff --git a/csharp/src/Ice/Exception.cs b/csharp/src/Ice/Exception.cs
new file mode 100644
index 00000000000..34612f73722
--- /dev/null
+++ b/csharp/src/Ice/Exception.cs
@@ -0,0 +1,274 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.Serialization;
+
+namespace IceInternal
+{
+ public class Ex
+ {
+ public static void throwUOE(string expectedType, string actualType)
+ {
+ throw new Ice.UnexpectedObjectException(
+ "expected element of type `" + expectedType + "' but received '" + actualType,
+ actualType, expectedType);
+ }
+
+ public static void throwMemoryLimitException(int requested, int maximum)
+ {
+ throw new Ice.MemoryLimitException("requested " + requested + " bytes, maximum allowed is " + maximum +
+ " bytes (see Ice.MessageSizeMax)");
+ }
+ }
+}
+
+namespace Ice
+{
+ /// <summary>
+ /// Base class for Ice exceptions.
+ /// </summary>
+#if !SILVERLIGHT
+ [System.Serializable]
+#endif
+ public abstract class Exception : System.Exception, System.ICloneable
+ {
+ /// <summary>
+ /// Creates and returns a copy of this exception.
+ /// </summary>
+ /// <returns>A copy of this exception.</returns>
+ public object Clone()
+ {
+ return MemberwiseClone();
+ }
+
+ /// <summary>
+ /// Creates a default-initialized exception.
+ /// </summary>
+ public Exception() {}
+
+ /// <summary>
+ /// Creates a default-initialized exception and sets the InnerException
+ /// property to the passed exception.
+ /// </summary>
+ /// <param name="ex">The inner exception.</param>
+ public Exception(System.Exception ex) : base("", ex) {}
+
+#if !SILVERLIGHT
+ /// <summary>
+ /// Initializes a new instance of the exception with serialized data.
+ /// </summary>
+ /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
+ /// <param name="context">Contains contextual information about the source or destination.</param>
+ protected Exception(SerializationInfo info, StreamingContext context) : base(info, context) {}
+#endif
+
+ /// <summary>
+ /// Returns the name of this exception.
+ /// </summary>
+ /// <returns>The name of this exception.</returns>
+ public abstract string ice_name();
+
+ /// <summary>
+ /// Returns a string representation of this exception, including
+ /// any inner exceptions.
+ /// </summary>
+ /// <returns>The string representation of this exception.</returns>
+ public override string ToString()
+ {
+ //
+ // This prints the exception Java style. That is, the outermost
+ // exception, "Caused by:" to the innermost exception. The
+ // stack trace is not nicely indented as with Java, but
+ // without string parsing (perhaps tokenize on "\n"), it
+ // doesn't appear to be possible to reformat it.
+ //
+ System.IO.StringWriter sw = new System.IO.StringWriter(CultureInfo.CurrentCulture);
+ IceUtilInternal.OutputBase op = new IceUtilInternal.OutputBase(sw);
+ op.setUseTab(false);
+ op.print(GetType().FullName);
+ op.inc();
+ IceInternal.ValueWriter.write(this, op);
+ sw.Write("\n");
+ sw.Write(StackTrace);
+
+ System.Exception curr = InnerException;
+ while(curr != null)
+ {
+ sw.Write("\nCaused by: ");
+ sw.Write(curr.GetType().FullName);
+ if(!(curr is Ice.Exception))
+ {
+ sw.Write(": ");
+ sw.Write(curr.Message);
+ }
+ sw.Write("\n");
+ sw.Write(curr.StackTrace);
+ curr = curr.InnerException;
+ }
+
+ return sw.ToString();
+ }
+ }
+
+ /// <summary>
+ /// Base class for local exceptions.
+ /// </summary>
+#if !SILVERLIGHT
+ [System.Serializable]
+#endif
+ public abstract class LocalException : Exception
+ {
+ /// <summary>
+ /// Creates a default-initialized local exception.
+ /// </summary>
+ public LocalException() {}
+
+ /// <summary>
+ /// Creates a default-initialized local exception and sets the InnerException
+ /// property to the passed exception.
+ /// </summary>
+ /// <param name="ex">The inner exception.</param>
+ public LocalException(System.Exception ex) : base(ex) {}
+
+#if !SILVERLIGHT
+ /// <summary>
+ /// Initializes a new instance of the exception with serialized data.
+ /// </summary>
+ /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
+ /// <param name="context">Contains contextual information about the source or destination.</param>
+ protected LocalException(SerializationInfo info, StreamingContext context) : base(info, context) {}
+#endif
+ }
+
+ /// <summary>
+ /// Base class for Ice run-time exceptions.
+ /// </summary>
+#if !SILVERLIGHT
+ [System.Serializable]
+#endif
+ public abstract class SystemException : Exception
+ {
+ /// <summary>
+ /// Creates a default-initialized run-time exception.
+ /// </summary>
+ public SystemException() {}
+
+ /// <summary>
+ /// Creates a default-initialized run-time exception and sets the InnerException
+ /// property to the passed exception.
+ /// </summary>
+ /// <param name="ex">The inner exception.</param>
+ public SystemException(System.Exception ex) : base(ex) {}
+
+#if !SILVERLIGHT
+ /// <summary>
+ /// Initializes a new instance of the exception with serialized data.
+ /// </summary>
+ /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
+ /// <param name="context">Contains contextual information about the source or destination.</param>
+ protected SystemException(SerializationInfo info, StreamingContext context) : base(info, context) {}
+#endif
+ }
+
+ /// <summary>
+ /// Base class for Slice user exceptions.
+ /// </summary>
+#if !SILVERLIGHT
+ [System.Serializable]
+#endif
+ public abstract class UserException : Exception
+ {
+ /// <summary>
+ /// Creates a default-initialized user exception.
+ /// </summary>
+ public UserException() {}
+
+ /// <summary>
+ /// Creates a default-initialized user exception and sets the InnerException
+ /// property to the passed exception.
+ /// </summary>
+ /// <param name="ex">The inner exception.</param>
+ public UserException(System.Exception ex) : base(ex) {}
+
+#if !SILVERLIGHT
+ /// <summary>
+ /// Initializes a new instance of the exception with serialized data.
+ /// </summary>
+ /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
+ /// <param name="context">Contains contextual information about the source or destination.</param>
+ protected UserException(SerializationInfo info, StreamingContext context) : base(info, context) {}
+#endif
+
+ public virtual void write__(IceInternal.BasicStream os__)
+ {
+ os__.startWriteException(null);
+ writeImpl__(os__);
+ os__.endWriteException();
+ }
+
+ public virtual void read__(IceInternal.BasicStream is__)
+ {
+ is__.startReadException();
+ readImpl__(is__);
+ is__.endReadException(false);
+ }
+
+ public virtual void write__(OutputStream os__)
+ {
+ os__.startException(null);
+ writeImpl__(os__);
+ os__.endException();
+ }
+
+ public virtual void read__(InputStream is__)
+ {
+ is__.startException();
+ readImpl__(is__);
+ is__.endException(false);
+ }
+
+ public virtual bool usesClasses__()
+ {
+ return false;
+ }
+
+ protected abstract void writeImpl__(IceInternal.BasicStream os__);
+ protected abstract void readImpl__(IceInternal.BasicStream is__);
+
+ protected virtual void writeImpl__(OutputStream os__)
+ {
+ throw new MarshalException("exception was not generated with stream support");
+ }
+
+ protected virtual void readImpl__(InputStream is__)
+ {
+ throw new MarshalException("exception was not generated with stream support");
+ }
+ }
+}
+
+namespace IceInternal
+{
+ public class RetryException : System.Exception
+ {
+ public RetryException(Ice.LocalException ex)
+ {
+ _ex = ex;
+ }
+
+ public Ice.LocalException get()
+ {
+ return _ex;
+ }
+
+ private Ice.LocalException _ex;
+ }
+}
diff --git a/csharp/src/Ice/FormatType.cs b/csharp/src/Ice/FormatType.cs
new file mode 100644
index 00000000000..f4cb664b793
--- /dev/null
+++ b/csharp/src/Ice/FormatType.cs
@@ -0,0 +1,21 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ /// <summary>
+ /// This enumeration describes the possible formats for classes and exceptions.
+ /// </summary>
+ public enum FormatType
+ {
+ DefaultFormat,
+ CompactFormat,
+ SlicedFormat
+ }
+}
diff --git a/csharp/src/Ice/HashSet.cs b/csharp/src/Ice/HashSet.cs
new file mode 100644
index 00000000000..813633d69b7
--- /dev/null
+++ b/csharp/src/Ice/HashSet.cs
@@ -0,0 +1,114 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#if COMPACT
+
+//
+// System.Collections.Generic.HashSet is not available in the .NET Compact Framework.
+// This class is a minimal implementation that provides only the methods required by
+// Ice internals.
+//
+using System;
+using System.Collections.Generic;
+
+namespace IceInternal
+{
+ public class HashSet<T> : ICollection<T>
+ {
+ public HashSet()
+ {
+ entries_ = new Dictionary<T, bool>();
+ }
+
+ public HashSet(int capacity)
+ {
+ entries_ = new Dictionary<T, bool>(capacity);
+ }
+
+ void ICollection<T>.Add(T item)
+ {
+ try
+ {
+ entries_.Add(item, false);
+ }
+ catch(ArgumentException)
+ {
+ // Item already present.
+ }
+ }
+
+ public bool Add(T item)
+ {
+ try
+ {
+ entries_.Add(item, false);
+ }
+ catch(ArgumentException)
+ {
+ return false; // Item already present.
+ }
+ return true;
+ }
+
+ public void Clear()
+ {
+ entries_.Clear();
+ }
+
+ public bool Contains(T item)
+ {
+ return entries_.ContainsKey(item);
+ }
+
+ public void CopyTo(T[] a, int idx)
+ {
+ entries_.Keys.CopyTo(a, idx);
+ }
+
+ public void CopyTo(T[] a)
+ {
+ entries_.Keys.CopyTo(a, 0);
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return entries_.Keys.GetEnumerator();
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ return entries_.Keys.GetEnumerator();
+ }
+
+ public bool Remove(T item)
+ {
+ return entries_.Remove(item);
+ }
+
+ public int Count
+ {
+ get
+ {
+ return entries_.Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ private Dictionary<T, bool> entries_;
+ }
+}
+
+#endif
diff --git a/csharp/src/Ice/HttpParser.cs b/csharp/src/Ice/HttpParser.cs
new file mode 100644
index 00000000000..32399400e34
--- /dev/null
+++ b/csharp/src/Ice/HttpParser.cs
@@ -0,0 +1,774 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Collections.Generic;
+ using System.Text;
+
+ internal sealed class WebSocketException : System.Exception
+ {
+ internal WebSocketException() :
+ base("", null)
+ {
+ }
+
+ internal WebSocketException(string message) :
+ base(message, null)
+ {
+ }
+
+ internal WebSocketException(string message, System.Exception cause) :
+ base(message, cause)
+ {
+ }
+
+ internal WebSocketException(System.Exception cause) :
+ base("", cause)
+ {
+ }
+ }
+
+ internal sealed class HttpParser
+ {
+ internal HttpParser()
+ {
+ _type = Type.Unknown;
+ _versionMajor = 0;
+ _versionMinor = 0;
+ _status = 0;
+ _state = State.Init;
+ }
+
+ internal enum Type
+ {
+ Unknown,
+ Request,
+ Response
+ };
+
+ internal int isCompleteMessage(IceInternal.ByteBuffer buf, int begin, int end)
+ {
+ byte[] raw = buf.rawBytes();
+ int p = begin;
+
+ //
+ // Skip any leading CR-LF characters.
+ //
+ while(p < end)
+ {
+ byte ch = raw[p];
+ if(ch != (byte)'\r' && ch != (byte)'\n')
+ {
+ break;
+ }
+ ++p;
+ }
+
+ //
+ // Look for adjacent CR-LF/CR-LF or LF/LF.
+ //
+ bool seenFirst = false;
+ while(p < end)
+ {
+ byte ch = raw[p++];
+ if(ch == (byte)'\n')
+ {
+ if(seenFirst)
+ {
+ return p;
+ }
+ else
+ {
+ seenFirst = true;
+ }
+ }
+ else if(ch != (byte)'\r')
+ {
+ seenFirst = false;
+ }
+ }
+
+ return -1;
+ }
+
+ internal bool parse(IceInternal.ByteBuffer buf, int begin, int end)
+ {
+ byte[] raw = buf.rawBytes();
+ int p = begin;
+ int start = 0;
+ const char CR = '\r';
+ const char LF = '\n';
+
+ if(_state == State.Complete)
+ {
+ _state = State.Init;
+ }
+
+ while(p != end && _state != State.Complete)
+ {
+ char c = (char)raw[p];
+
+ switch(_state)
+ {
+ case State.Init:
+ {
+ _method = new StringBuilder();
+ _uri = new StringBuilder();
+ _versionMajor = -1;
+ _versionMinor = -1;
+ _status = -1;
+ _reason = "";
+ _headers.Clear();
+ _state = State.Type;
+ continue;
+ }
+ case State.Type:
+ {
+ if(c == CR || c == LF)
+ {
+ break;
+ }
+ else if(c == 'H')
+ {
+ //
+ // Could be the start of "HTTP/1.1" or "HEAD".
+ //
+ _state = State.TypeCheck;
+ break;
+ }
+ else
+ {
+ _state = State.Request;
+ continue;
+ }
+ }
+ case State.TypeCheck:
+ {
+ if(c == 'T') // Continuing "H_T_TP/1.1"
+ {
+ _state = State.Response;
+ }
+ else if(c == 'E') // Expecting "HEAD"
+ {
+ _state = State.Request;
+ _method.Append('H');
+ _method.Append('E');
+ }
+ else
+ {
+ throw new WebSocketException("malformed request or response");
+ }
+ break;
+ }
+ case State.Request:
+ {
+ _type = Type.Request;
+ _state = State.RequestMethod;
+ continue;
+ }
+ case State.RequestMethod:
+ {
+ if(c == ' ' || c == CR || c == LF)
+ {
+ _state = State.RequestMethodSP;
+ continue;
+ }
+ _method.Append(c);
+ break;
+ }
+ case State.RequestMethodSP:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+ else if(c == CR || c == LF)
+ {
+ throw new WebSocketException("malformed request");
+ }
+ _state = State.RequestURI;
+ continue;
+ }
+ case State.RequestURI:
+ {
+ if(c == ' ' || c == CR || c == LF)
+ {
+ _state = State.RequestURISP;
+ continue;
+ }
+ _uri.Append(c);
+ break;
+ }
+ case State.RequestURISP:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+ else if(c == CR || c == LF)
+ {
+ throw new WebSocketException("malformed request");
+ }
+ _state = State.Version;
+ continue;
+ }
+ case State.RequestLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed request");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ case State.HeaderFieldStart:
+ {
+ //
+ // We've already seen a LF to reach this state.
+ //
+ // Another CR or LF indicates the end of the header fields.
+ //
+ if(c == CR)
+ {
+ _state = State.HeaderFieldEndLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ _state = State.Complete;
+ break;
+ }
+ else if(c == ' ')
+ {
+ //
+ // Could be a continuation line.
+ //
+ _state = State.HeaderFieldContStart;
+ break;
+ }
+
+ _state = State.HeaderFieldNameStart;
+ continue;
+ }
+ case State.HeaderFieldContStart:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+
+ _state = State.HeaderFieldCont;
+ start = p;
+ continue;
+ }
+ case State.HeaderFieldCont:
+ {
+ if(c == CR || c == LF)
+ {
+ if(p > start)
+ {
+ if(_headerName.Length == 0)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ Debug.Assert(_headers.ContainsKey(_headerName));
+ string s = _headers[_headerName];
+ StringBuilder newValue = new StringBuilder(s);
+ newValue.Append(' ');
+ for(int i = start; i < p; ++i)
+ {
+ newValue.Append((char)raw[i]);
+ }
+ _headers[_headerName] = newValue.ToString();
+ _state = c == CR ? State.HeaderFieldLF : State.HeaderFieldStart;
+ }
+ else
+ {
+ //
+ // Could mark the end of the header fields.
+ //
+ _state = c == CR ? State.HeaderFieldEndLF : State.Complete;
+ }
+ }
+
+ break;
+ }
+ case State.HeaderFieldNameStart:
+ {
+ Debug.Assert(c != ' ');
+ start = p;
+ _headerName = "";
+ _state = State.HeaderFieldName;
+ continue;
+ }
+ case State.HeaderFieldName:
+ {
+ if(c == ' ' || c == ':')
+ {
+ _state = State.HeaderFieldNameEnd;
+ continue;
+ }
+ else if(c == CR || c == LF)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ break;
+ }
+ case State.HeaderFieldNameEnd:
+ {
+ if(_headerName.Length == 0)
+ {
+ StringBuilder str = new StringBuilder();
+ for(int i = start; i < p; ++i)
+ {
+ str.Append((char)raw[i]);
+ }
+ _headerName = str.ToString().ToLower();
+ //
+ // Add a placeholder entry if necessary.
+ //
+ if(!_headers.ContainsKey(_headerName))
+ {
+ _headers[_headerName] = "";
+ _headerNames[_headerName] = str.ToString();
+ }
+ }
+
+ if(c == ' ')
+ {
+ break;
+ }
+ else if(c != ':' || p == start)
+ {
+ throw new WebSocketException("malformed header");
+ }
+
+ _state = State.HeaderFieldValueStart;
+ break;
+ }
+ case State.HeaderFieldValueStart:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+
+ //
+ // Check for "Name:\r\n"
+ //
+ if(c == CR)
+ {
+ _state = State.HeaderFieldLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ _state = State.HeaderFieldStart;
+ break;
+ }
+
+ start = p;
+ _state = State.HeaderFieldValue;
+ continue;
+ }
+ case State.HeaderFieldValue:
+ {
+ if(c == CR || c == LF)
+ {
+ _state = State.HeaderFieldValueEnd;
+ continue;
+ }
+ break;
+ }
+ case State.HeaderFieldValueEnd:
+ {
+ Debug.Assert(c == CR || c == LF);
+ if(p > start)
+ {
+ StringBuilder str = new StringBuilder();
+ for(int i = start; i < p; ++i)
+ {
+ str.Append((char)raw[i]);
+ }
+ string s = null;
+ if(!_headers.TryGetValue(_headerName, out s) || s.Length == 0)
+ {
+ _headers[_headerName] = str.ToString();
+ }
+ else
+ {
+ _headers[_headerName] = s + ", " + str.ToString();
+ }
+ }
+
+ if(c == CR)
+ {
+ _state = State.HeaderFieldLF;
+ }
+ else
+ {
+ _state = State.HeaderFieldStart;
+ }
+ break;
+ }
+ case State.HeaderFieldLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ case State.HeaderFieldEndLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed header");
+ }
+ _state = State.Complete;
+ break;
+ }
+ case State.Version:
+ {
+ if(c != 'H')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionH;
+ break;
+ }
+ case State.VersionH:
+ {
+ if(c != 'T')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionHT;
+ break;
+ }
+ case State.VersionHT:
+ {
+ if(c != 'T')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionHTT;
+ break;
+ }
+ case State.VersionHTT:
+ {
+ if(c != 'P')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionHTTP;
+ break;
+ }
+ case State.VersionHTTP:
+ {
+ if(c != '/')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionMajor;
+ break;
+ }
+ case State.VersionMajor:
+ {
+ if(c == '.')
+ {
+ if(_versionMajor == -1)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.VersionMinor;
+ break;
+ }
+ else if(c < '0' || c > '9')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ if(_versionMajor == -1)
+ {
+ _versionMajor = 0;
+ }
+ _versionMajor *= 10;
+ _versionMajor += (int)(c - '0');
+ break;
+ }
+ case State.VersionMinor:
+ {
+ if(c == CR)
+ {
+ if(_versionMinor == -1 || _type != Type.Request)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.RequestLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ if(_versionMinor == -1 || _type != Type.Request)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ else if(c == ' ')
+ {
+ if(_versionMinor == -1 || _type != Type.Response)
+ {
+ throw new WebSocketException("malformed version");
+ }
+ _state = State.ResponseVersionSP;
+ break;
+ }
+ else if(c < '0' || c > '9')
+ {
+ throw new WebSocketException("malformed version");
+ }
+ if(_versionMinor == -1)
+ {
+ _versionMinor = 0;
+ }
+ _versionMinor *= 10;
+ _versionMinor += (int)(c - '0');
+ break;
+ }
+ case State.Response:
+ {
+ _type = Type.Response;
+ _state = State.VersionHT;
+ continue;
+ }
+ case State.ResponseVersionSP:
+ {
+ if(c == ' ')
+ {
+ break;
+ }
+
+ _state = State.ResponseStatus;
+ continue;
+ }
+ case State.ResponseStatus:
+ {
+ // TODO: Is reason string optional?
+ if(c == CR)
+ {
+ if(_status == -1)
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ _state = State.ResponseLF;
+ break;
+ }
+ else if(c == LF)
+ {
+ if(_status == -1)
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ else if(c == ' ')
+ {
+ if(_status == -1)
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ _state = State.ResponseReasonStart;
+ break;
+ }
+ else if(c < '0' || c > '9')
+ {
+ throw new WebSocketException("malformed response status");
+ }
+ if(_status == -1)
+ {
+ _status = 0;
+ }
+ _status *= 10;
+ _status += (int)(c - '0');
+ break;
+ }
+ case State.ResponseReasonStart:
+ {
+ //
+ // Skip leading spaces.
+ //
+ if(c == ' ')
+ {
+ break;
+ }
+
+ _state = State.ResponseReason;
+ start = p;
+ continue;
+ }
+ case State.ResponseReason:
+ {
+ if(c == CR || c == LF)
+ {
+ if(p > start)
+ {
+ StringBuilder str = new StringBuilder();
+ for(int i = start; i < p; ++i)
+ {
+ str.Append((char)raw[i]);
+ }
+ _reason = str.ToString();
+ }
+ _state = c == CR ? State.ResponseLF : State.HeaderFieldStart;
+ }
+
+ break;
+ }
+ case State.ResponseLF:
+ {
+ if(c != LF)
+ {
+ throw new WebSocketException("malformed status line");
+ }
+ _state = State.HeaderFieldStart;
+ break;
+ }
+ case State.Complete:
+ {
+ Debug.Assert(false); // Shouldn't reach
+ break;
+ }
+ }
+
+ ++p;
+ }
+
+ return _state == State.Complete;
+ }
+
+ internal Type type()
+ {
+ return _type;
+ }
+
+ internal string method()
+ {
+ Debug.Assert(_type == Type.Request);
+ return _method.ToString();
+ }
+
+ internal string uri()
+ {
+ Debug.Assert(_type == Type.Request);
+ return _uri.ToString();
+ }
+
+ internal int versionMajor()
+ {
+ return _versionMajor;
+ }
+
+ internal int versionMinor()
+ {
+ return _versionMinor;
+ }
+
+ internal int status()
+ {
+ return _status;
+ }
+
+ internal string reason()
+ {
+ return _reason;
+ }
+
+ internal string getHeader(string name, bool toLower)
+ {
+ string s = null;
+ if(_headers.TryGetValue(name.ToLower(), out s))
+ {
+ return toLower ? s.Trim().ToLower() : s.Trim();
+ }
+
+ return null;
+ }
+
+ internal Dictionary<string, string> getHeaders()
+ {
+ Dictionary<string, string> dict = new Dictionary<string, string>();
+ foreach(KeyValuePair<string, string> e in _headers)
+ {
+ dict[_headerNames[e.Key]] = e.Value.Trim();
+ }
+ return dict;
+ }
+
+ private Type _type;
+
+ private StringBuilder _method = new StringBuilder();
+ private StringBuilder _uri = new StringBuilder();
+
+ private Dictionary<string, string> _headers = new Dictionary<string, string>();
+ private Dictionary<string, string> _headerNames = new Dictionary<string, string>();
+ private string _headerName = "";
+
+ private int _versionMajor;
+ private int _versionMinor;
+
+ private int _status;
+ private string _reason;
+
+ private enum State
+ {
+ Init,
+ Type,
+ TypeCheck,
+ Request,
+ RequestMethod,
+ RequestMethodSP,
+ RequestURI,
+ RequestURISP,
+ RequestLF,
+ HeaderFieldStart,
+ HeaderFieldContStart,
+ HeaderFieldCont,
+ HeaderFieldNameStart,
+ HeaderFieldName,
+ HeaderFieldNameEnd,
+ HeaderFieldValueStart,
+ HeaderFieldValue,
+ HeaderFieldValueEnd,
+ HeaderFieldLF,
+ HeaderFieldEndLF,
+ Version,
+ VersionH,
+ VersionHT,
+ VersionHTT,
+ VersionHTTP,
+ VersionMajor,
+ VersionMinor,
+ Response,
+ ResponseVersionSP,
+ ResponseStatus,
+ ResponseReasonStart,
+ ResponseReason,
+ ResponseLF,
+ Complete
+ };
+ private State _state;
+ }
+}
diff --git a/csharp/src/Ice/IPEndpointI.cs b/csharp/src/Ice/IPEndpointI.cs
new file mode 100644
index 00000000000..7741670b615
--- /dev/null
+++ b/csharp/src/Ice/IPEndpointI.cs
@@ -0,0 +1,407 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.Net;
+ using System;
+
+ public abstract class IPEndpointI : EndpointI
+ {
+ public IPEndpointI(ProtocolInstance instance, string host, int port, EndPoint sourceAddr, string connectionId)
+ {
+ instance_ = instance;
+ host_ = host;
+ port_ = port;
+ sourceAddr_ = sourceAddr;
+ connectionId_ = connectionId;
+ _hashInitialized = false;
+ }
+
+ public IPEndpointI(ProtocolInstance instance)
+ {
+ instance_ = instance;
+ host_ = null;
+ port_ = 0;
+ sourceAddr_ = null;
+ connectionId_ = "";
+ _hashInitialized = false;
+ }
+
+ public IPEndpointI(ProtocolInstance instance, BasicStream s)
+ {
+ instance_ = instance;
+ host_ = s.readString();
+ port_ = s.readInt();
+ sourceAddr_ = null;
+ connectionId_ = "";
+ _hashInitialized = false;
+ }
+
+ private sealed class InfoI : Ice.IPEndpointInfo
+ {
+ public InfoI(IPEndpointI e)
+ {
+ _endpoint = e;
+ }
+
+ override public short type()
+ {
+ return _endpoint.type();
+ }
+
+ override public bool datagram()
+ {
+ return _endpoint.datagram();;
+ }
+
+ override public bool secure()
+ {
+ return _endpoint.secure();
+ }
+
+ private IPEndpointI _endpoint;
+ }
+
+ public override Ice.EndpointInfo getInfo()
+ {
+ InfoI info = new InfoI(this);
+ fillEndpointInfo(info);
+ return info;
+ }
+
+ public override void streamWrite(BasicStream s)
+ {
+ s.startWriteEncaps();
+ streamWriteImpl(s);
+ s.endWriteEncaps();
+ }
+
+ public override short type()
+ {
+ return instance_.type();
+ }
+
+ public override string protocol()
+ {
+ return instance_.protocol();
+ }
+
+ public override bool secure()
+ {
+ return instance_.secure();
+ }
+
+ public override string connectionId()
+ {
+ return connectionId_;
+ }
+
+ public override EndpointI connectionId(string connectionId)
+ {
+ if(connectionId.Equals(connectionId_))
+ {
+ return this;
+ }
+ else
+ {
+ return createEndpoint(host_, port_, connectionId);
+ }
+ }
+
+ public override void connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback)
+ {
+#if SILVERLIGHT
+ callback.connectors(connectors(selType));
+#else
+ instance_.resolve(host_, port_, selType, this, callback);
+#endif
+ }
+
+ public override List<EndpointI> expand()
+ {
+ List<EndpointI> endps = new List<EndpointI>();
+ List<string> hosts = Network.getHostsForEndpointExpand(host_, instance_.protocolSupport(), false);
+ if(hosts == null || hosts.Count == 0)
+ {
+ endps.Add(this);
+ }
+ else
+ {
+ foreach(string h in hosts)
+ {
+ endps.Add(createEndpoint(h, port_, connectionId_));
+ }
+ }
+ return endps;
+ }
+
+ public override bool equivalent(EndpointI endpoint)
+ {
+ if(!(endpoint is IPEndpointI))
+ {
+ return false;
+ }
+ IPEndpointI ipEndpointI = (IPEndpointI)endpoint;
+ return ipEndpointI.type() == type() && ipEndpointI.host_.Equals(host_) && ipEndpointI.port_ == port_ &&
+ Network.addressEquals(ipEndpointI.sourceAddr_, sourceAddr_);
+ }
+
+ public virtual List<Connector> connectors(List<EndPoint> addresses, NetworkProxy proxy)
+ {
+ List<Connector> connectors = new List<Connector>();
+ foreach(EndPoint p in addresses)
+ {
+ connectors.Add(createConnector(p, proxy));
+ }
+ return connectors;
+ }
+
+#if SILVERLIGHT
+ public List<Connector> connectors(Ice.EndpointSelectionType selType)
+ {
+ return connectors(Network.getAddresses(host_, port_, instance_.protocolSupport(), selType,
+ instance_.preferIPv6(), false),
+ instance_.networkProxy());
+ }
+#endif
+
+ public override string options()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ string s = "";
+
+ if(host_ != null && host_.Length > 0)
+ {
+ s += " -h ";
+ bool addQuote = host_.IndexOf(':') != -1;
+ if(addQuote)
+ {
+ s += "\"";
+ }
+ s += host_;
+ if(addQuote)
+ {
+ s += "\"";
+ }
+ }
+
+ s += " -p " + port_;
+
+ if(sourceAddr_ != null)
+ {
+ s += " --sourceAddress " + Network.endpointAddressToString(sourceAddr_);
+ }
+
+ return s;
+ }
+
+ public override int GetHashCode()
+ {
+ if(!_hashInitialized)
+ {
+ _hashValue = 5381;
+ HashUtil.hashAdd(ref _hashValue, type());
+ hashInit(ref _hashValue);
+ _hashInitialized = true;
+ }
+ return _hashValue;
+ }
+
+ public override int CompareTo(EndpointI obj)
+ {
+ if(!(obj is IPEndpointI))
+ {
+ return type() < obj.type() ? -1 : 1;
+ }
+
+ IPEndpointI p = (IPEndpointI)obj;
+ if(this == p)
+ {
+ return 0;
+ }
+
+ int v = string.Compare(host_, p.host_, StringComparison.Ordinal);
+ if(v != 0)
+ {
+ return v;
+ }
+
+ if(port_ < p.port_)
+ {
+ return -1;
+ }
+ else if(p.port_ < port_)
+ {
+ return 1;
+ }
+
+ int rc = string.Compare(Network.endpointAddressToString(sourceAddr_),
+ Network.endpointAddressToString(p.sourceAddr_), StringComparison.Ordinal);
+ if(rc != 0)
+ {
+ return rc;
+ }
+
+ return string.Compare(connectionId_, p.connectionId_, StringComparison.Ordinal);
+ }
+
+ public string host()
+ {
+ return host_;
+ }
+
+ public int port()
+ {
+ return port_;
+ }
+
+ public virtual void streamWriteImpl(BasicStream s)
+ {
+ s.writeString(host_);
+ s.writeInt(port_);
+ }
+
+ public virtual void hashInit(ref int h)
+ {
+ HashUtil.hashAdd(ref h, host_);
+ HashUtil.hashAdd(ref h, port_);
+ if(sourceAddr_ != null)
+ {
+ HashUtil.hashAdd(ref h, sourceAddr_);
+ }
+ HashUtil.hashAdd(ref h, connectionId_);
+ }
+
+ public virtual void fillEndpointInfo(Ice.IPEndpointInfo info)
+ {
+ info.host = host_;
+ info.port = port_;
+ info.sourceAddress = Network.endpointAddressToString(sourceAddr_);
+ }
+
+ public virtual void initWithOptions(List<string> args, bool oaEndpoint)
+ {
+ base.initWithOptions(args);
+
+ if(host_ == null || host_.Length == 0)
+ {
+ host_ = instance_.defaultHost();
+ }
+ else if(host_.Equals("*"))
+ {
+ if(oaEndpoint)
+ {
+ host_ = "";
+ }
+ else
+ {
+ throw new Ice.EndpointParseException("`-h *' not valid for proxy endpoint `" + ToString() + "'");
+ }
+ }
+
+ if(host_ == null)
+ {
+ host_ = "";
+ }
+
+ if(sourceAddr_ != null)
+ {
+ if(oaEndpoint)
+ {
+ throw new Ice.EndpointParseException("`--sourceAddress' not valid for object adapter endpoint `" +
+ ToString() + "'");
+ }
+ }
+ else if(!oaEndpoint)
+ {
+ sourceAddr_ = instance_.defaultSourceAddress();
+ }
+ }
+
+ protected override bool checkOption(string option, string argument, string endpoint)
+ {
+ if(option.Equals("-h"))
+ {
+ if(argument == null)
+ {
+ throw new Ice.EndpointParseException("no argument provided for -h option in endpoint " +
+ endpoint);
+ }
+ host_ = argument;
+ }
+ else if(option.Equals("-p"))
+ {
+ if(argument == null)
+ {
+ throw new Ice.EndpointParseException("no argument provided for -p option in endpoint " +
+ endpoint);
+ }
+
+ try
+ {
+ port_ = System.Int32.Parse(argument, CultureInfo.InvariantCulture);
+ }
+ catch(System.FormatException ex)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException(ex);
+ e.str = "invalid port value `" + argument + "' in endpoint " + endpoint;
+ throw e;
+ }
+
+ if(port_ < 0 || port_ > 65535)
+ {
+ throw new Ice.EndpointParseException("port value `" + argument +
+ "' out of range in endpoint " + endpoint);
+ }
+ }
+ else if(option.Equals("--sourceAddress"))
+ {
+ if(argument == null)
+ {
+ throw new Ice.EndpointParseException("no argument provided for --sourceAddress option in endpoint " +
+ endpoint);
+ }
+ sourceAddr_ = Network.getNumericAddress(argument);
+ if(sourceAddr_ == null)
+ {
+ throw new Ice.EndpointParseException(
+ "invalid IP address provided for --sourceAddress option in endpoint " + endpoint);
+ }
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ }
+
+ protected abstract Connector createConnector(EndPoint addr, NetworkProxy proxy);
+ protected abstract IPEndpointI createEndpoint(string host, int port, string connectionId);
+
+ protected ProtocolInstance instance_;
+ protected string host_;
+ protected int port_;
+ protected EndPoint sourceAddr_;
+ protected string connectionId_;
+ private bool _hashInitialized;
+ private int _hashValue;
+ }
+
+}
diff --git a/csharp/src/Ice/Ice.dll.config b/csharp/src/Ice/Ice.dll.config
new file mode 100644
index 00000000000..7cf597f8b6f
--- /dev/null
+++ b/csharp/src/Ice/Ice.dll.config
@@ -0,0 +1,3 @@
+<configuration>
+ <dllmap dll="bzip2.dll" target="libbz2.so.1"/>
+</configuration>
diff --git a/csharp/src/Ice/ImplicitContextI.cs b/csharp/src/Ice/ImplicitContextI.cs
new file mode 100644
index 00000000000..ba830f89115
--- /dev/null
+++ b/csharp/src/Ice/ImplicitContextI.cs
@@ -0,0 +1,409 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Threading;
+
+ //
+ // The base class for all ImplicitContext implementations
+ //
+ public abstract class ImplicitContextI : ImplicitContext
+ {
+ public static ImplicitContextI create(string kind)
+ {
+ if(kind.Equals("None") || kind.Length == 0)
+ {
+ return null;
+ }
+ else if(kind.Equals("Shared"))
+ {
+ return new SharedImplicitContext();
+ }
+ else if(kind.Equals("PerThread"))
+ {
+ return new PerThreadImplicitContext();
+ }
+ else
+ {
+ throw new Ice.InitializationException(
+ "'" + kind + "' is not a valid value for Ice.ImplicitContext");
+ }
+ }
+
+ public abstract Dictionary<string, string> getContext();
+ public abstract void setContext(Dictionary<string, string> newContext);
+ public abstract bool containsKey(string key);
+ public abstract string get(string key);
+ public abstract string put(string key, string value);
+ public abstract string remove(string key);
+
+ abstract public void write(Dictionary<string, string> prxContext,
+ IceInternal.BasicStream os);
+ abstract internal Dictionary<string, string> combine(Dictionary<string, string> prxContext);
+ }
+
+
+ internal class SharedImplicitContext : ImplicitContextI
+ {
+ public override Dictionary<string, string> getContext()
+ {
+ lock(this)
+ {
+ return new Dictionary<string, string>(_context);
+ }
+ }
+
+ public override void setContext(Dictionary<string, string> context)
+ {
+ lock(this)
+ {
+ if(context != null && context.Count != 0)
+ {
+ _context = new Dictionary<string, string>(context);
+ }
+ else
+ {
+ _context.Clear();
+ }
+ }
+ }
+
+ public override bool containsKey(string key)
+ {
+ lock(this)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+
+ return _context.ContainsKey(key);
+ }
+ }
+
+ public override string get(string key)
+ {
+ lock(this)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+
+ string val = _context[key];
+ if(val == null)
+ {
+ val = "";
+ }
+ return val;
+ }
+ }
+
+
+ public override string put(string key, string value)
+ {
+ lock(this)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+ if(value == null)
+ {
+ value = "";
+ }
+
+ string oldVal;
+ _context.TryGetValue(key, out oldVal);
+ if(oldVal == null)
+ {
+ oldVal = "";
+ }
+ _context[key] = value;
+
+ return oldVal;
+ }
+ }
+
+ public override string remove(string key)
+ {
+ lock(this)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+
+ string val = _context[key];
+
+ if(val == null)
+ {
+ val = "";
+ }
+ else
+ {
+ _context.Remove(key);
+ }
+
+ return val;
+ }
+ }
+
+ public override void write(Dictionary<string, string> prxContext, IceInternal.BasicStream os)
+ {
+ if(prxContext.Count == 0)
+ {
+ lock(this)
+ {
+ ContextHelper.write(os, _context);
+ }
+ }
+ else
+ {
+ Dictionary<string, string> ctx = null;
+ lock(this)
+ {
+ ctx = _context.Count == 0 ? prxContext : combine(prxContext);
+ }
+ ContextHelper.write(os, ctx);
+ }
+ }
+
+ internal override Dictionary<string, string> combine(Dictionary<string, string> prxContext)
+ {
+ lock(this)
+ {
+ Dictionary<string, string> combined = new Dictionary<string, string>(prxContext);
+ foreach(KeyValuePair<string, string> e in _context)
+ {
+ try
+ {
+ combined.Add(e.Key, e.Value);
+ }
+ catch(System.ArgumentException)
+ {
+ // Ignore.
+ }
+ }
+ return combined;
+ }
+ }
+
+ private Dictionary<string, string> _context = new Dictionary<string, string>();
+ }
+
+ internal class PerThreadImplicitContext : ImplicitContextI
+ {
+ public override Dictionary<string, string> getContext()
+ {
+ Dictionary<string, string> threadContext = null;
+ Thread currentThread = Thread.CurrentThread;
+ lock(this)
+ {
+ if(_map.ContainsKey(currentThread))
+ {
+ threadContext = (Dictionary<string, string>)_map[currentThread];
+ }
+ }
+
+ if(threadContext == null)
+ {
+ threadContext = new Dictionary<string, string>();
+ }
+ return threadContext;
+ }
+
+ public override void setContext(Dictionary<string, string> context)
+ {
+ if(context == null || context.Count == 0)
+ {
+ lock(this)
+ {
+ _map.Remove(Thread.CurrentThread);
+ }
+ }
+ else
+ {
+ Dictionary<string, string> threadContext = new Dictionary<string, string>(context);
+
+ lock(this)
+ {
+ _map.Add(Thread.CurrentThread, threadContext);
+ }
+ }
+ }
+
+ public override bool containsKey(string key)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+
+ Dictionary<string, string> threadContext = null;
+ lock(this)
+ {
+ if(!_map.TryGetValue(Thread.CurrentThread, out threadContext))
+ {
+ return false;
+ }
+ }
+
+ return threadContext.ContainsKey(key);
+ }
+
+ public override string get(string key)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+
+ Dictionary<string, string> threadContext = null;
+ lock(this)
+ {
+ if(!_map.TryGetValue(Thread.CurrentThread, out threadContext))
+ {
+ return "";
+ }
+ }
+
+ string val = threadContext[key];
+ if(val == null)
+ {
+ val = "";
+ }
+ return val;
+ }
+
+ public override string put(string key, string value)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+ if(value == null)
+ {
+ value = "";
+ }
+
+ Dictionary<string, string> threadContext = null;
+ lock(this)
+ {
+ if(!_map.TryGetValue(Thread.CurrentThread, out threadContext))
+ {
+ threadContext = new Dictionary<string, string>();
+ _map.Add(Thread.CurrentThread, threadContext);
+ }
+ }
+
+ string oldVal;
+ if(!threadContext.TryGetValue(key, out oldVal))
+ {
+ oldVal = "";
+ }
+
+ threadContext[key] = value;
+ return oldVal;
+ }
+
+ public override string remove(string key)
+ {
+ if(key == null)
+ {
+ key = "";
+ }
+
+ Dictionary<string, string> threadContext = null;
+ lock(this)
+ {
+ if(!_map.TryGetValue(Thread.CurrentThread, out threadContext))
+ {
+ return "";
+ }
+ }
+
+
+ string val = null;
+ if(!threadContext.TryGetValue(key, out val))
+ {
+ val = "";
+ }
+ else
+ {
+ threadContext.Remove(key);
+ }
+ return val;
+ }
+
+ public override void write(Dictionary<string, string> prxContext, IceInternal.BasicStream os)
+ {
+ Dictionary<string, string> threadContext = null;
+ lock(this)
+ {
+ _map.TryGetValue(Thread.CurrentThread, out threadContext);
+ }
+
+ if(threadContext == null || threadContext.Count == 0)
+ {
+ ContextHelper.write(os, prxContext);
+ }
+ else if(prxContext.Count == 0)
+ {
+ ContextHelper.write(os, threadContext);
+ }
+ else
+ {
+ Dictionary<string, string> combined = new Dictionary<string, string>(prxContext);
+ foreach(KeyValuePair<string, string> e in threadContext)
+ {
+ try
+ {
+ combined.Add(e.Key, e.Value);
+ }
+ catch(System.ArgumentException)
+ {
+ // Ignore.
+ }
+ }
+ ContextHelper.write(os, combined);
+ }
+ }
+
+ internal override Dictionary<string, string> combine(Dictionary<string, string> prxContext)
+ {
+ Dictionary<string, string> threadContext = null;
+ lock(this)
+ {
+ if(!_map.TryGetValue(Thread.CurrentThread, out threadContext))
+ {
+ return new Dictionary<string, string>(prxContext);
+ }
+ }
+
+ Dictionary<string, string> combined = new Dictionary<string, string>(prxContext);
+ foreach(KeyValuePair<string, string> e in threadContext)
+ {
+ combined.Add(e.Key, e.Value);
+ }
+ return combined;
+ }
+
+ //
+ // map Thread -> Context
+ //
+ private Dictionary<Thread, Dictionary<string, string> > _map =
+ new Dictionary<Thread, Dictionary<string, string> >();
+ }
+}
+
+
diff --git a/csharp/src/Ice/Incoming.cs b/csharp/src/Ice/Incoming.cs
new file mode 100644
index 00000000000..1033b0a9083
--- /dev/null
+++ b/csharp/src/Ice/Incoming.cs
@@ -0,0 +1,936 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Globalization;
+
+ public class IncomingBase
+ {
+ protected internal IncomingBase(Instance instance, ResponseHandler handler, Ice.ConnectionI connection,
+ Ice.ObjectAdapter adapter, bool response, byte compress, int requestId)
+ {
+ instance_ = instance;
+ responseHandler_ = handler;
+ response_ = response;
+ compress_ = compress;
+ if(response_)
+ {
+ os_ = new BasicStream(instance, Ice.Util.currentProtocolEncoding);
+ }
+
+ current_ = new Ice.Current();
+ current_.id = new Ice.Identity();
+ current_.adapter = adapter;
+ current_.con = connection;
+ current_.requestId = requestId;
+
+ cookie_ = null;
+ }
+
+ protected internal IncomingBase(IncomingBase inc) // Adopts the argument. It must not be used afterwards.
+ {
+ //
+ // We don't change current_ as it's exposed by Ice::Request.
+ //
+ current_ = inc.current_;
+
+ //
+ // Deep copy
+ //
+ if(inc.interceptorAsyncCallbackList_ != null)
+ {
+ //
+ // Copy, not just reference
+ //
+ interceptorAsyncCallbackList_ =
+ new List<Ice.DispatchInterceptorAsyncCallback>(inc.interceptorAsyncCallbackList_);
+ }
+
+ adopt(inc);
+ }
+
+ internal void
+ adopt(IncomingBase inc)
+ {
+ instance_ = inc.instance_;
+ //inc.instance_ = null; // Don't reset instance_.
+
+ observer_ = inc.observer_;
+ inc.observer_ = null;
+
+ servant_ = inc.servant_;
+ inc.servant_ = null;
+
+ locator_ = inc.locator_;
+ inc.locator_ = null;
+
+ cookie_ = inc.cookie_;
+ inc.cookie_ = null;
+
+ response_ = inc.response_;
+ inc.response_ = false;
+
+ compress_ = inc.compress_;
+ inc.compress_ = 0;
+
+ //
+ // Adopt the stream - it creates less garbage.
+ //
+ os_ = inc.os_;
+ inc.os_ = null;
+
+ responseHandler_ = inc.responseHandler_;
+ inc.responseHandler_ = null;
+ }
+
+ public BasicStream startWriteParams__(Ice.FormatType format)
+ {
+ if(!response_)
+ {
+ throw new Ice.MarshalException("can't marshal out parameters for oneway dispatch");
+ }
+
+ Debug.Assert(os_.size() == Protocol.headerSize + 4); // Reply status position.
+ os_.writeByte((byte)0);
+ os_.startWriteEncaps(current_.encoding, format);
+ return os_;
+ }
+
+ public void endWriteParams__(bool ok)
+ {
+ if(!ok && observer_ != null)
+ {
+ observer_.userException();
+ }
+
+ if(response_)
+ {
+ int save = os_.pos();
+ os_.pos(Protocol.headerSize + 4); // Reply status position.
+ os_.writeByte(ok ? ReplyStatus.replyOK : ReplyStatus.replyUserException);
+ os_.pos(save);
+ os_.endWriteEncaps();
+ }
+ }
+
+ public void writeEmptyParams__()
+ {
+ if(response_)
+ {
+ Debug.Assert(os_.size() == Protocol.headerSize + 4); // Reply status position.
+ os_.writeByte(ReplyStatus.replyOK);
+ os_.writeEmptyEncaps(current_.encoding);
+ }
+ }
+
+ public void writeParamEncaps__(byte[] v, bool ok)
+ {
+ if(!ok && observer_ != null)
+ {
+ observer_.userException();
+ }
+
+ if(response_)
+ {
+ Debug.Assert(os_.size() == Protocol.headerSize + 4); // Reply status position.
+ os_.writeByte(ok ? ReplyStatus.replyOK : ReplyStatus.replyUserException);
+ if(v == null || v.Length == 0)
+ {
+ os_.writeEmptyEncaps(current_.encoding);
+ }
+ else
+ {
+ os_.writeEncaps(v);
+ }
+ }
+ }
+
+ public void writeUserException__(Ice.UserException ex, Ice.FormatType format)
+ {
+ BasicStream os__ = startWriteParams__(format);
+ os__.writeUserException(ex);
+ endWriteParams__(false);
+ }
+
+ //
+ // These functions allow this object to be reused, rather than reallocated.
+ //
+ public virtual void reset(Instance instance, ResponseHandler handler, Ice.ConnectionI connection,
+ Ice.ObjectAdapter adapter, bool response, byte compress, int requestId)
+ {
+ instance_ = instance;
+
+ //
+ // Don't recycle the Current object, because servants may keep a reference to it.
+ //
+ current_ = new Ice.Current();
+ current_.id = new Ice.Identity();
+ current_.adapter = adapter;
+ current_.con = connection;
+ current_.requestId = requestId;
+
+ Debug.Assert(cookie_ == null);
+
+ response_ = response;
+
+ compress_ = compress;
+
+ if(response_ && os_ == null)
+ {
+ os_ = new BasicStream(instance, Ice.Util.currentProtocolEncoding);
+ }
+
+ responseHandler_ = handler;
+ interceptorAsyncCallbackList_ = null;
+ }
+
+ public virtual void reclaim()
+ {
+ servant_ = null;
+
+ locator_ = null;
+
+ cookie_ = null;
+
+ observer_ = null;
+
+ if(os_ != null)
+ {
+ os_.reset();
+ }
+
+ interceptorAsyncCallbackList_ = null;
+ }
+
+ protected internal void warning__(System.Exception ex)
+ {
+ Debug.Assert(instance_ != null);
+
+ using(StringWriter sw = new StringWriter(CultureInfo.CurrentCulture))
+ {
+ IceUtilInternal.OutputBase output = new IceUtilInternal.OutputBase(sw);
+ output.setUseTab(false);
+ output.print("dispatch exception:");
+ output.print("\nidentity: " + instance_.identityToString(current_.id));
+ output.print("\nfacet: " + IceUtilInternal.StringUtil.escapeString(current_.facet, ""));
+ output.print("\noperation: " + current_.operation);
+ if(current_.con != null)
+ {
+ Ice.ConnectionInfo connInfo = current_.con.getInfo();
+ if(connInfo is Ice.IPConnectionInfo)
+ {
+ Ice.IPConnectionInfo ipConnInfo = (Ice.IPConnectionInfo)connInfo;
+ output.print("\nremote host: " + ipConnInfo.remoteAddress + " remote port: " +
+ ipConnInfo.remotePort.ToString());
+ }
+ }
+ output.print("\n");
+ output.print(ex.ToString());
+ instance_.initializationData().logger.warning(sw.ToString());
+ }
+ }
+
+ protected bool servantLocatorFinished__(bool amd)
+ {
+ Debug.Assert(locator_ != null && servant_ != null);
+ try
+ {
+ locator_.finished(current_, servant_, cookie_);
+ return true;
+ }
+ catch(Ice.UserException ex)
+ {
+ Debug.Assert(responseHandler_ != null);
+
+ if(observer_ != null)
+ {
+ observer_.userException();
+ }
+
+ //
+ // The operation may have already marshaled a reply; we must overwrite that reply.
+ //
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ os_.writeByte(ReplyStatus.replyUserException);
+ os_.startWriteEncaps();
+ os_.writeUserException(ex);
+ os_.endWriteEncaps();
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ responseHandler_ = null;
+ }
+ catch(System.Exception ex)
+ {
+ handleException__(ex, amd);
+ }
+ return false;
+ }
+
+ protected internal void handleException__(System.Exception exc, bool amd)
+ {
+ Debug.Assert(responseHandler_ != null);
+
+ try
+ {
+ throw exc;
+ }
+ catch(Ice.RequestFailedException ex)
+ {
+ if(ex.id == null || ex.id.name == null || ex.id.name.Length == 0)
+ {
+ ex.id = current_.id;
+ }
+
+ if(ex.facet == null || ex.facet.Length == 0)
+ {
+ ex.facet = current_.facet;
+ }
+
+ if(ex.operation == null || ex.operation.Length == 0)
+ {
+ ex.operation = current_.operation;
+ }
+
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1)
+ {
+ warning__(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.failed(ex.ice_name());
+ }
+
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ if(ex is Ice.ObjectNotExistException)
+ {
+ os_.writeByte(ReplyStatus.replyObjectNotExist);
+ }
+ else if(ex is Ice.FacetNotExistException)
+ {
+ os_.writeByte(ReplyStatus.replyFacetNotExist);
+ }
+ else if(ex is Ice.OperationNotExistException)
+ {
+ os_.writeByte(ReplyStatus.replyOperationNotExist);
+ }
+ else
+ {
+ Debug.Assert(false);
+ }
+ ex.id.write__(os_);
+
+ //
+ // For compatibility with the old FacetPath.
+ //
+ if(ex.facet == null || ex.facet.Length == 0)
+ {
+ os_.writeStringSeq(null);
+ }
+ else
+ {
+ string[] facetPath2 = { ex.facet };
+ os_.writeStringSeq(facetPath2);
+ }
+
+ os_.writeString(ex.operation);
+
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+ }
+ catch(Ice.UnknownLocalException ex)
+ {
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0)
+ {
+ warning__(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.failed(ex.ice_name());
+ }
+
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ os_.writeByte(ReplyStatus.replyUnknownLocalException);
+ os_.writeString(ex.unknown);
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+ }
+ catch(Ice.UnknownUserException ex)
+ {
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0)
+ {
+ warning__(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.failed(ex.ice_name());
+ }
+
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ os_.writeByte(ReplyStatus.replyUnknownUserException);
+ os_.writeString(ex.unknown);
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+ }
+ catch(Ice.UnknownException ex)
+ {
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0)
+ {
+ warning__(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.failed(ex.ice_name());
+ }
+
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ os_.writeByte(ReplyStatus.replyUnknownException);
+ os_.writeString(ex.unknown);
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+ }
+ catch(Ice.UserException ex)
+ {
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0)
+ {
+ warning__(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.failed(ex.ice_name());
+ }
+
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ os_.writeByte(ReplyStatus.replyUnknownUserException);
+ os_.writeString(ex.ice_name() + "\n" + ex.StackTrace);
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+ }
+ catch(Ice.Exception ex)
+ {
+ if(ex is Ice.SystemException)
+ {
+ if(responseHandler_.systemException(current_.requestId, (Ice.SystemException)ex, amd))
+ {
+ return;
+ }
+ }
+
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0)
+ {
+ warning__(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.failed(ex.ice_name());
+ }
+
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ os_.writeByte(ReplyStatus.replyUnknownLocalException);
+ os_.writeString(ex.ice_name() + "\n" + ex.StackTrace);
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+ }
+ catch(System.Exception ex)
+ {
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0)
+ {
+ warning__(ex);
+ }
+
+ if(observer_ != null)
+ {
+ observer_.failed(ex.GetType().FullName);
+ }
+
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false); // Reply status position.
+ os_.writeByte(ReplyStatus.replyUnknownException);
+ os_.writeString(ex.ToString());
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, amd);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+ }
+
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ responseHandler_ = null;
+ }
+
+ protected internal Instance instance_;
+ protected internal Ice.Current current_;
+ protected internal Ice.Object servant_;
+ protected internal Ice.ServantLocator locator_;
+ protected internal System.Object cookie_;
+ protected internal Ice.Instrumentation.DispatchObserver observer_;
+
+ protected internal bool response_;
+ protected internal byte compress_;
+
+ protected internal BasicStream os_;
+
+ protected ResponseHandler responseHandler_;
+
+ protected List<Ice.DispatchInterceptorAsyncCallback> interceptorAsyncCallbackList_;
+ }
+
+ sealed public class Incoming : IncomingBase, Ice.Request
+ {
+ public Incoming(Instance instance, ResponseHandler handler, Ice.ConnectionI connection,
+ Ice.ObjectAdapter adapter, bool response, byte compress, int requestId)
+ : base(instance, handler, connection, adapter, response, compress, requestId)
+ {
+ //
+ // Prepare the response if necessary.
+ //
+ if(response)
+ {
+ os_.writeBlob(IceInternal.Protocol.replyHdr);
+
+ //
+ // Add the request ID.
+ //
+ os_.writeInt(requestId);
+ }
+ }
+
+ public Ice.Current
+ getCurrent()
+ {
+ return current_;
+ }
+
+ //
+ // These functions allow this object to be reused, rather than reallocated.
+ //
+ public override void reset(Instance instance, ResponseHandler handler, Ice.ConnectionI connection,
+ Ice.ObjectAdapter adapter, bool response, byte compress, int requestId)
+ {
+ _cb = null;
+ _inParamPos = -1;
+
+ base.reset(instance, handler, connection, adapter, response, compress, requestId);
+
+ //
+ // Prepare the response if necessary.
+ //
+ if(response)
+ {
+ os_.writeBlob(IceInternal.Protocol.replyHdr);
+
+ //
+ // Add the request ID.
+ //
+ os_.writeInt(requestId);
+ }
+ }
+
+ public override void reclaim()
+ {
+ _cb = null;
+ _inParamPos = -1;
+
+ base.reclaim();
+ }
+
+ public void invoke(ServantManager servantManager, BasicStream stream)
+ {
+ _is = stream;
+
+ int start = _is.pos();
+
+ //
+ // Read the current.
+ //
+ current_.id.read__(_is);
+
+ //
+ // For compatibility with the old FacetPath.
+ //
+ string[] facetPath = _is.readStringSeq();
+ if(facetPath.Length > 0)
+ {
+ if(facetPath.Length > 1)
+ {
+ throw new Ice.MarshalException();
+ }
+ current_.facet = facetPath[0];
+ }
+ else
+ {
+ current_.facet = "";
+ }
+
+ current_.operation = _is.readString();
+ current_.mode = (Ice.OperationMode)(int)_is.readByte();
+ current_.ctx = new Dictionary<string, string>();
+ int sz = _is.readSize();
+ while(sz-- > 0)
+ {
+ string first = _is.readString();
+ string second = _is.readString();
+ current_.ctx[first] = second;
+ }
+
+ Ice.Instrumentation.CommunicatorObserver obsv = instance_.initializationData().observer;
+ if(obsv != null)
+ {
+ // Read the encapsulation size.
+ int size = _is.readInt();
+ _is.pos(_is.pos() - 4);
+
+ observer_ = obsv.getDispatchObserver(current_, _is.pos() - start + size);
+ if(observer_ != null)
+ {
+ observer_.attach();
+ }
+ }
+
+ //
+ // Don't put the code above into the try block below. Exceptions
+ // in the code above are considered fatal, and must propagate to
+ // the caller of this operation.
+ //
+
+ if(servantManager != null)
+ {
+ servant_ = servantManager.findServant(current_.id, current_.facet);
+ if(servant_ == null)
+ {
+ locator_ = servantManager.findServantLocator(current_.id.category);
+ if(locator_ == null && current_.id.category.Length > 0)
+ {
+ locator_ = servantManager.findServantLocator("");
+ }
+
+ if(locator_ != null)
+ {
+ try
+ {
+ servant_ = locator_.locate(current_, out cookie_);
+ }
+ catch(Ice.UserException ex)
+ {
+ Ice.EncodingVersion encoding = _is.skipEncaps(); // Required for batch requests.
+
+ if(observer_ != null)
+ {
+ observer_.userException();
+ }
+
+ if(response_)
+ {
+ os_.writeByte(ReplyStatus.replyUserException);
+ os_.startWriteEncaps(encoding, Ice.FormatType.DefaultFormat);
+ os_.writeUserException(ex);
+ os_.endWriteEncaps();
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, false);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ responseHandler_ = null;
+ return;
+ }
+ catch(System.Exception ex)
+ {
+ _is.skipEncaps(); // Required for batch requests.
+ handleException__(ex, false);
+ return;
+ }
+ }
+ }
+ }
+
+ try
+ {
+ if(servant_ != null)
+ {
+ //
+ // DispatchAsync is a "pseudo dispatch status", used internally only
+ // to indicate async dispatch.
+ //
+ if(servant_.dispatch__(this, current_) == Ice.DispatchStatus.DispatchAsync)
+ {
+ //
+ // If this was an asynchronous dispatch, we're done here.
+ //
+ return;
+ }
+
+ if(locator_ != null && !servantLocatorFinished__(false))
+ {
+ return;
+ }
+ }
+ else
+ {
+ //
+ // Skip the input parameters, this is required for reading
+ // the next batch request if dispatching batch requests.
+ //
+ _is.skipEncaps();
+
+ if(servantManager != null && servantManager.hasServant(current_.id))
+ {
+ throw new Ice.FacetNotExistException(current_.id, current_.facet, current_.operation);
+ }
+ else
+ {
+ throw new Ice.ObjectNotExistException(current_.id, current_.facet, current_.operation);
+ }
+ }
+ }
+ catch(System.Exception ex)
+ {
+ if(servant_ != null && locator_ != null && !servantLocatorFinished__(false))
+ {
+ return;
+ }
+ handleException__(ex, false);
+ return;
+ }
+
+ //
+ // Don't put the code below into the try block above. Exceptions
+ // in the code below are considered fatal, and must propagate to
+ // the caller of this operation.
+ //
+
+ Debug.Assert(responseHandler_ != null);
+
+ if(response_)
+ {
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, false);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ responseHandler_ = null;
+ }
+
+ public void push(Ice.DispatchInterceptorAsyncCallback cb)
+ {
+ if(interceptorAsyncCallbackList_ == null)
+ {
+ interceptorAsyncCallbackList_ = new List<Ice.DispatchInterceptorAsyncCallback>();
+ }
+
+ interceptorAsyncCallbackList_.Insert(0, cb);
+ }
+
+ public void pop()
+ {
+ Debug.Assert(interceptorAsyncCallbackList_ != null);
+ interceptorAsyncCallbackList_.RemoveAt(0);
+ }
+
+ public void startOver()
+ {
+ if(_inParamPos == -1)
+ {
+ //
+ // That's the first startOver, so almost nothing to do
+ //
+ _inParamPos = _is.pos();
+ }
+ else
+ {
+ killAsync();
+
+ //
+ // Let's rewind _is and clean-up os_
+ //
+ _is.pos(_inParamPos);
+ if(response_)
+ {
+ os_.resize(Protocol.headerSize + 4, false);
+ }
+ }
+ }
+
+ public void killAsync()
+ {
+ //
+ // Always runs in the dispatch thread
+ //
+ if(_cb != null)
+ {
+ //
+ // May raise ResponseSentException
+ //
+ _cb.deactivate__(this);
+ _cb = null;
+ }
+ }
+
+ public BasicStream startReadParams()
+ {
+ //
+ // Remember the encoding used by the input parameters, we'll
+ // encode the response parameters with the same encoding.
+ //
+ current_.encoding = _is.startReadEncaps();
+ return _is;
+ }
+
+ public void endReadParams()
+ {
+ _is.endReadEncaps();
+ }
+
+ public void readEmptyParams()
+ {
+ current_.encoding = _is.skipEmptyEncaps();
+ }
+
+ public byte[] readParamEncaps()
+ {
+ return _is.readEncaps(out current_.encoding);
+ }
+
+ internal void setActive(IncomingAsync cb)
+ {
+ Debug.Assert(_cb == null);
+ _cb = cb;
+ }
+
+ internal bool isRetriable()
+ {
+ return _inParamPos != -1;
+ }
+
+ public Incoming next; // For use by Connection.
+
+ private BasicStream _is;
+
+ private IncomingAsync _cb;
+ private int _inParamPos = -1;
+ }
+
+}
diff --git a/csharp/src/Ice/IncomingAsync.cs b/csharp/src/Ice/IncomingAsync.cs
new file mode 100644
index 00000000000..5f9205c027e
--- /dev/null
+++ b/csharp/src/Ice/IncomingAsync.cs
@@ -0,0 +1,247 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Diagnostics;
+
+ public class IncomingAsync : IncomingBase, Ice.AMDCallback
+ {
+ public IncomingAsync(Incoming inc)
+ : base(inc)
+ {
+ _retriable = inc.isRetriable();
+ if(_retriable)
+ {
+ inc.setActive(this);
+ _active = true;
+ }
+ }
+
+ virtual public void ice_exception(System.Exception ex)
+ {
+ //
+ // Only call exception__ if this incoming is not retriable or if
+ // all the interceptors return true and no response has been sent
+ // yet.
+ //
+
+ if(_retriable)
+ {
+ try
+ {
+ if(interceptorAsyncCallbackList_ != null)
+ {
+ foreach(Ice.DispatchInterceptorAsyncCallback cb in interceptorAsyncCallbackList_)
+ {
+ if(cb.exception(ex) == false)
+ {
+ return;
+ }
+ }
+ }
+ }
+ catch(System.Exception)
+ {
+ return;
+ }
+
+ lock(this)
+ {
+ if(!_active)
+ {
+ return;
+ }
+ _active = false;
+ }
+ }
+
+ if(responseHandler_ != null)
+ {
+ exception__(ex);
+ }
+ else
+ {
+ //
+ // Response has already been sent.
+ //
+ if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0)
+ {
+ warning__(ex);
+ }
+ }
+ }
+
+ internal void deactivate__(Incoming inc)
+ {
+ Debug.Assert(_retriable);
+
+ lock(this)
+ {
+ if(!_active)
+ {
+ //
+ // Since __deactivate can only be called on an active object,
+ // this means the response has already been sent (see validateXXX below)
+ //
+ throw new Ice.ResponseSentException();
+ }
+ _active = false;
+ }
+ inc.adopt(this);
+ }
+
+ protected void response__()
+ {
+ try
+ {
+ if(locator_ != null && !servantLocatorFinished__(true))
+ {
+ return;
+ }
+
+ Debug.Assert(responseHandler_ != null);
+
+ if(response_)
+ {
+ if(observer_ != null)
+ {
+ observer_.reply(os_.size() - Protocol.headerSize - 4);
+ }
+ responseHandler_.sendResponse(current_.requestId, os_, compress_, true);
+ }
+ else
+ {
+ responseHandler_.sendNoResponse();
+ }
+
+ if(observer_ != null)
+ {
+ observer_.detach();
+ observer_ = null;
+ }
+ responseHandler_ = null;
+ }
+ catch(Ice.LocalException ex)
+ {
+ responseHandler_.invokeException(current_.requestId, ex, 1, true);
+ }
+ }
+
+ protected internal void exception__(System.Exception exc)
+ {
+ try
+ {
+ if(locator_ != null && !servantLocatorFinished__(true))
+ {
+ return;
+ }
+
+ handleException__(exc, true);
+ }
+ catch(Ice.LocalException ex)
+ {
+ responseHandler_.invokeException(current_.requestId, ex, 1, true);
+ }
+ }
+
+ protected internal BasicStream getOs__()
+ {
+ return os_;
+ }
+
+ protected bool validateResponse__(bool ok)
+ {
+ //
+ // Only returns true if this incoming is not retriable or if all
+ // the interceptors return true and no response has been sent
+ // yet. Upon getting a true return value, the caller should send
+ // the response.
+ //
+
+ if(_retriable)
+ {
+ try
+ {
+ if(interceptorAsyncCallbackList_ != null)
+ {
+ foreach(Ice.DispatchInterceptorAsyncCallback cb in interceptorAsyncCallbackList_)
+ {
+ if(cb.response(ok) == false)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+
+ lock(this)
+ {
+ if(!_active)
+ {
+ return false;
+ }
+ _active = false;
+ }
+ }
+ return true;
+ }
+
+ private readonly bool _retriable;
+ private bool _active = false; // only meaningful when _retriable == true
+ }
+}
+
+namespace Ice
+{
+
+ /// <summary>
+ /// Callback interface for Blobject AMD servants.
+ /// </summary>
+ public interface AMD_Object_ice_invoke : Ice.AMDCallback
+ {
+ /// <summary>
+ /// Indicates to the Ice run time that an operation
+ /// completed.
+ /// </summary>
+ /// <param name="ok">True indicates that the operation
+ /// completed successfully; false indicates that the
+ /// operation raised a user exception.</param>
+ /// <param name="outEncaps">The encoded out-parameters for the operation or,
+ /// if ok is false, the encoded user exception.</param>
+ void ice_response(bool ok, byte[] outEncaps);
+ }
+
+ sealed class _AMD_Object_ice_invoke : IceInternal.IncomingAsync, AMD_Object_ice_invoke
+ {
+ public _AMD_Object_ice_invoke(IceInternal.Incoming inc)
+ : base(inc)
+ {
+ }
+
+ public void ice_response(bool ok, byte[] outEncaps)
+ {
+ try
+ {
+ writeParamEncaps__(outEncaps, ok);
+ }
+ catch(Ice.LocalException ex)
+ {
+ exception__(ex);
+ return;
+ }
+ response__();
+ }
+ }
+}
diff --git a/csharp/src/Ice/Instance.cs b/csharp/src/Ice/Instance.cs
new file mode 100644
index 00000000000..8dd99f3860f
--- /dev/null
+++ b/csharp/src/Ice/Instance.cs
@@ -0,0 +1,1581 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Text;
+ using System.Threading;
+ using System;
+
+ public sealed class BufSizeWarnInfo
+ {
+ // Whether send size warning has been emitted
+ public bool sndWarn;
+
+ // The send size for which the warning wwas emitted
+ public int sndSize;
+
+ // Whether receive size warning has been emitted
+ public bool rcvWarn;
+
+ // The receive size for which the warning wwas emitted
+ public int rcvSize;
+ }
+
+ public sealed class Instance
+ {
+ private class ObserverUpdaterI : Ice.Instrumentation.ObserverUpdater
+ {
+ public ObserverUpdaterI(Instance instance)
+ {
+ _instance = instance;
+ }
+
+ public void updateConnectionObservers()
+ {
+ _instance.updateConnectionObservers();
+ }
+
+ public void updateThreadObservers()
+ {
+ _instance.updateThreadObservers();
+ }
+
+ private Instance _instance;
+ }
+
+ public bool destroyed()
+ {
+ return _state == StateDestroyed;
+ }
+
+ public Ice.InitializationData initializationData()
+ {
+ //
+ // No check for destruction. It must be possible to access the
+ // initialization data after destruction.
+ //
+ // No mutex lock, immutable.
+ //
+ return _initData;
+ }
+
+ public TraceLevels traceLevels()
+ {
+ // No mutex lock, immutable.
+ Debug.Assert(_traceLevels != null);
+ return _traceLevels;
+ }
+
+ public DefaultsAndOverrides defaultsAndOverrides()
+ {
+ // No mutex lock, immutable.
+ Debug.Assert(_defaultsAndOverrides != null);
+ return _defaultsAndOverrides;
+ }
+
+#if COMPACT || SILVERLIGHT
+ public string[] factoryAssemblies()
+ {
+ return _factoryAssemblies;
+ }
+#endif
+
+ public RouterManager routerManager()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_routerManager != null);
+ return _routerManager;
+ }
+ }
+
+ public LocatorManager locatorManager()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_locatorManager != null);
+ return _locatorManager;
+ }
+ }
+
+ public ReferenceFactory referenceFactory()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_referenceFactory != null);
+ return _referenceFactory;
+ }
+ }
+
+ public RequestHandlerFactory requestHandlerFactory()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_requestHandlerFactory != null);
+ return _requestHandlerFactory;
+ }
+ }
+
+ public ProxyFactory proxyFactory()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_proxyFactory != null);
+ return _proxyFactory;
+ }
+ }
+
+ public OutgoingConnectionFactory outgoingConnectionFactory()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_outgoingConnectionFactory != null);
+ return _outgoingConnectionFactory;
+ }
+ }
+
+ public ObjectFactoryManager servantFactoryManager()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_servantFactoryManager != null);
+ return _servantFactoryManager;
+ }
+ }
+
+ public ObjectAdapterFactory objectAdapterFactory()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_objectAdapterFactory != null);
+ return _objectAdapterFactory;
+ }
+ }
+
+ public int protocolSupport()
+ {
+ return _protocolSupport;
+ }
+
+ public bool preferIPv6()
+ {
+ return _preferIPv6;
+ }
+
+ public NetworkProxy networkProxy()
+ {
+ return _networkProxy;
+ }
+
+ public ThreadPool clientThreadPool()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_clientThreadPool != null);
+ return _clientThreadPool;
+ }
+ }
+
+ public ThreadPool serverThreadPool()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(_serverThreadPool == null) // Lazy initialization.
+ {
+ if(_state == StateDestroyInProgress)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+ int timeout = _initData.properties.getPropertyAsInt("Ice.ServerIdleTime");
+ _serverThreadPool = new ThreadPool(this, "Ice.ThreadPool.Server", timeout);
+ }
+
+ return _serverThreadPool;
+ }
+ }
+
+ public AsyncIOThread
+ asyncIOThread()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(_asyncIOThread == null) // Lazy initialization.
+ {
+ _asyncIOThread = new AsyncIOThread(this);
+ }
+
+ return _asyncIOThread;
+ }
+ }
+
+#if !SILVERLIGHT
+ public EndpointHostResolver endpointHostResolver()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_endpointHostResolver != null);
+ return _endpointHostResolver;
+ }
+ }
+#endif
+ public RetryQueue
+ retryQueue()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_retryQueue != null);
+ return _retryQueue;
+ }
+ }
+
+ public Timer
+ timer()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_timer != null);
+ return _timer;
+ }
+ }
+
+ public EndpointFactoryManager endpointFactoryManager()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_endpointFactoryManager != null);
+ return _endpointFactoryManager;
+ }
+ }
+
+ public Ice.PluginManager pluginManager()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Debug.Assert(_pluginManager != null);
+ return _pluginManager;
+ }
+ }
+
+ public int messageSizeMax()
+ {
+ // No mutex lock, immutable.
+ return _messageSizeMax;
+ }
+
+ public int batchAutoFlushSize()
+ {
+ // No mutex lock, immutable.
+ return _batchAutoFlushSize;
+ }
+
+ public int cacheMessageBuffers()
+ {
+ // No mutex lock, immutable.
+ return _cacheMessageBuffers;
+ }
+
+ public ACMConfig clientACM()
+ {
+ // No mutex lock, immutable.
+ return _clientACM;
+ }
+
+ public ACMConfig serverACM()
+ {
+ // No mutex lock, immutable.
+ return _serverACM;
+ }
+
+ public Ice.ImplicitContextI getImplicitContext()
+ {
+ return _implicitContext;
+ }
+
+ public Ice.Identity stringToIdentity(string s)
+ {
+ return Ice.Util.stringToIdentity(s);
+ }
+
+ public string identityToString(Ice.Identity ident)
+ {
+ return Ice.Util.identityToString(ident);
+ }
+
+
+ public Ice.ObjectPrx
+ createAdmin(Ice.ObjectAdapter adminAdapter, Ice.Identity adminIdentity)
+ {
+ bool createAdapter = (adminAdapter == null);
+
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(adminIdentity == null || string.IsNullOrEmpty(adminIdentity.name))
+ {
+ throw new Ice.IllegalIdentityException(adminIdentity);
+ }
+
+ if(_adminAdapter != null)
+ {
+ throw new Ice.InitializationException("Admin already created");
+ }
+
+ if(!_adminEnabled)
+ {
+ throw new Ice.InitializationException("Admin is disabled");
+ }
+
+ if(createAdapter)
+ {
+ if(_initData.properties.getProperty("Ice.Admin.Endpoints").Length > 0)
+ {
+ adminAdapter = _objectAdapterFactory.createObjectAdapter("Ice.Admin", null);
+ }
+ else
+ {
+ throw new Ice.InitializationException("Ice.Admin.Endpoints is not set");
+ }
+ }
+
+ _adminIdentity = adminIdentity;
+ _adminAdapter = adminAdapter;
+ addAllAdminFacets();
+ }
+
+ if(createAdapter)
+ {
+ try
+ {
+ adminAdapter.activate();
+ }
+ catch(Ice.LocalException)
+ {
+ //
+ // We cleanup _adminAdapter, however this error is not recoverable
+ // (can't call again getAdmin() after fixing the problem)
+ // since all the facets (servants) in the adapter are lost
+ //
+ adminAdapter.destroy();
+ lock(this)
+ {
+ _adminAdapter = null;
+ }
+ throw;
+ }
+ }
+ setServerProcessProxy(adminAdapter, adminIdentity);
+ return adminAdapter.createProxy(adminIdentity);
+ }
+
+ public Ice.ObjectPrx
+ getAdmin()
+ {
+ Ice.ObjectAdapter adminAdapter;
+ Ice.Identity adminIdentity;
+
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(_adminAdapter != null)
+ {
+ return _adminAdapter.createProxy(_adminIdentity);
+ }
+ else if(_adminEnabled)
+ {
+ if(_initData.properties.getProperty("Ice.Admin.Endpoints").Length > 0)
+ {
+ adminAdapter = _objectAdapterFactory.createObjectAdapter("Ice.Admin", null);
+ }
+ else
+ {
+ return null;
+ }
+ adminIdentity = new Ice.Identity("admin", _initData.properties.getProperty("Ice.Admin.InstanceName"));
+ if(adminIdentity.category.Length == 0)
+ {
+ adminIdentity.category = System.Guid.NewGuid().ToString();
+ }
+
+ _adminIdentity = adminIdentity;
+ _adminAdapter = adminAdapter;
+ addAllAdminFacets();
+ // continue below outside synchronization
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ try
+ {
+ adminAdapter.activate();
+ }
+ catch(Ice.LocalException)
+ {
+ //
+ // We cleanup _adminAdapter, however this error is not recoverable
+ // (can't call again getAdmin() after fixing the problem)
+ // since all the facets (servants) in the adapter are lost
+ //
+ adminAdapter.destroy();
+ lock(this)
+ {
+ _adminAdapter = null;
+ }
+ throw;
+ }
+
+ setServerProcessProxy(adminAdapter, adminIdentity);
+ return adminAdapter.createProxy(adminIdentity);
+ }
+
+ public void
+ addAdminFacet(Ice.Object servant, string facet)
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(_adminAdapter == null || (_adminFacetFilter.Count > 0 && !_adminFacetFilter.Contains(facet)))
+ {
+ if(_adminFacets.ContainsKey(facet))
+ {
+ throw new Ice.AlreadyRegisteredException("facet", facet);
+ }
+ _adminFacets.Add(facet, servant);
+ }
+ else
+ {
+ _adminAdapter.addFacet(servant, _adminIdentity, facet);
+ }
+ }
+ }
+
+ public Ice.Object
+ removeAdminFacet(string facet)
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Ice.Object result = null;
+ if(_adminAdapter == null || (_adminFacetFilter.Count > 0 && !_adminFacetFilter.Contains(facet)))
+ {
+ try
+ {
+ result = _adminFacets[facet];
+ }
+ catch(KeyNotFoundException)
+ {
+ throw new Ice.NotRegisteredException("facet", facet);
+ }
+
+ _adminFacets.Remove(facet);
+ }
+ else
+ {
+ result = _adminAdapter.removeFacet(_adminIdentity, facet);
+ }
+ return result;
+ }
+ }
+
+ public Ice.Object
+ findAdminFacet(string facet)
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Ice.Object result = null;
+ if(_adminAdapter == null || (_adminFacetFilter.Count > 0 && !_adminFacetFilter.Contains(facet)))
+ {
+ try
+ {
+ result = _adminFacets[facet];
+ }
+ catch(KeyNotFoundException)
+ {
+ }
+ }
+ else
+ {
+ result = _adminAdapter.findFacet(_adminIdentity, facet);
+ }
+ return result;
+ }
+ }
+
+ public Dictionary<string, Ice.Object>
+ findAllAdminFacets()
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(_adminAdapter == null)
+ {
+ return new Dictionary<string, Ice.Object>(_adminFacets);
+ }
+ else
+ {
+ Dictionary<string, Ice.Object> result = _adminAdapter.findAllFacets(_adminIdentity);
+ if(_adminFacets.Count > 0)
+ {
+ foreach(KeyValuePair<string, Ice.Object> p in _adminFacets)
+ {
+ result.Add(p.Key, p.Value);
+ }
+ }
+ return result;
+ }
+ }
+ }
+
+ public void
+ setDefaultLocator(Ice.LocatorPrx locator)
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ _referenceFactory = _referenceFactory.setDefaultLocator(locator);
+ }
+ }
+
+ public void
+ setDefaultRouter(Ice.RouterPrx router)
+ {
+ lock(this)
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ _referenceFactory = _referenceFactory.setDefaultRouter(router);
+ }
+ }
+
+ public void
+ setLogger(Ice.Logger logger)
+ {
+ //
+ // No locking, as it can only be called during plug-in loading
+ //
+ _initData.logger = logger;
+ }
+
+ public void
+ setThreadHook(Ice.ThreadNotification threadHook)
+ {
+ //
+ // No locking, as it can only be called during plug-in loading
+ //
+ _initData.threadHook = threadHook;
+ }
+
+ //
+ // Only for use by Ice.CommunicatorI
+ //
+ public Instance(Ice.Communicator communicator, Ice.InitializationData initData)
+ {
+ _state = StateActive;
+ _initData = initData;
+
+ try
+ {
+ if(_initData.properties == null)
+ {
+ _initData.properties = Ice.Util.createProperties();
+ }
+#if !SILVERLIGHT && !UNITY
+ lock(_staticLock)
+ {
+ if(!_oneOfDone)
+ {
+ string stdOut = _initData.properties.getProperty("Ice.StdOut");
+ string stdErr = _initData.properties.getProperty("Ice.StdErr");
+
+ System.IO.StreamWriter outStream = null;
+
+ if(stdOut.Length > 0)
+ {
+ try
+ {
+ outStream = System.IO.File.AppendText(stdOut);
+ }
+ catch(System.IO.IOException ex)
+ {
+ Ice.FileException fe = new Ice.FileException(ex);
+ fe.path = stdOut;
+ throw fe;
+ }
+ outStream.AutoFlush = true;
+ System.Console.Out.Close();
+ System.Console.SetOut(outStream);
+ }
+ if(stdErr.Length > 0)
+ {
+ if(stdErr.Equals(stdOut))
+ {
+ System.Console.SetError(outStream);
+ }
+ else
+ {
+ System.IO.StreamWriter errStream = null;
+ try
+ {
+ errStream = System.IO.File.AppendText(stdErr);
+ }
+ catch(System.IO.IOException ex)
+ {
+ Ice.FileException fe = new Ice.FileException(ex);
+ fe.path = stdErr;
+ throw fe;
+ }
+ errStream.AutoFlush = true;
+ System.Console.Error.Close();
+ System.Console.SetError(errStream);
+ }
+ }
+
+ _oneOfDone = true;
+ }
+ }
+#endif
+
+ if(_initData.logger == null)
+ {
+#if !SILVERLIGHT && !UNITY
+ string logfile = _initData.properties.getProperty("Ice.LogFile");
+ if(_initData.properties.getPropertyAsInt("Ice.UseSyslog") > 0 &&
+ AssemblyUtil.platform_ != AssemblyUtil.Platform.Windows)
+ {
+ if(logfile.Length != 0)
+ {
+ throw new Ice.InitializationException("Ice.LogFile and Ice.UseSyslog cannot both be set.");
+ }
+ _initData.logger = new Ice.SysLoggerI(_initData.properties.getProperty("Ice.ProgramName"),
+ _initData.properties.getPropertyWithDefault("Ice.SyslogFacility", "LOG_USER"));
+ }
+ else if(logfile.Length != 0)
+ {
+
+ _initData.logger =
+ new Ice.FileLoggerI(_initData.properties.getProperty("Ice.ProgramName"), logfile);
+ }
+ else if(Ice.Util.getProcessLogger() is Ice.LoggerI)
+ {
+ //
+ // Ice.ConsoleListener is enabled by default.
+ //
+# if COMPACT
+ _initData.logger =
+ new Ice.ConsoleLoggerI(_initData.properties.getProperty("Ice.ProgramName"));
+# else
+ bool console =
+ _initData.properties.getPropertyAsIntWithDefault("Ice.ConsoleListener", 1) > 0;
+ _initData.logger =
+ new Ice.TraceLoggerI(_initData.properties.getProperty("Ice.ProgramName"), console);
+# endif
+ }
+#else
+ if(Ice.Util.getProcessLogger() is Ice.LoggerI)
+ {
+ _initData.logger =
+ new Ice.ConsoleLoggerI(_initData.properties.getProperty("Ice.ProgramName"));
+ }
+#endif
+ else
+ {
+ _initData.logger = Ice.Util.getProcessLogger();
+ }
+ }
+
+ _traceLevels = new TraceLevels(_initData.properties);
+
+ _defaultsAndOverrides = new DefaultsAndOverrides(_initData.properties, _initData.logger);
+
+ _clientACM = new ACMConfig(_initData.properties,
+ _initData.logger,
+ "Ice.ACM.Client",
+ new ACMConfig(_initData.properties, _initData.logger, "Ice.ACM",
+ new ACMConfig(false)));
+
+ _serverACM = new ACMConfig(_initData.properties,
+ _initData.logger,
+ "Ice.ACM.Server",
+ new ACMConfig(_initData.properties, _initData.logger, "Ice.ACM",
+ new ACMConfig(true)));
+
+#if COMPACT || SILVERLIGHT
+ char[] separators = { ' ', '\t', '\n', '\r' };
+ _factoryAssemblies = _initData.properties.getProperty("Ice.FactoryAssemblies").Split(separators);
+#endif
+ {
+ const int defaultMessageSizeMax = 1024;
+ int num =
+ _initData.properties.getPropertyAsIntWithDefault("Ice.MessageSizeMax", defaultMessageSizeMax);
+ if(num < 1 || num > 0x7fffffff / 1024)
+ {
+ _messageSizeMax = 0x7fffffff;
+ }
+ else
+ {
+ _messageSizeMax = num * 1024; // Property is in kilobytes, _messageSizeMax in bytes
+ }
+ }
+
+ if(_initData.properties.getProperty("Ice.BatchAutoFlushSize").Length == 0 &&
+ _initData.properties.getProperty("Ice.BatchAutoFlush").Length > 0)
+ {
+ if(_initData.properties.getPropertyAsInt("Ice.BatchAutoFlush") > 0)
+ {
+ _batchAutoFlushSize = _messageSizeMax;
+ }
+ }
+ else
+ {
+ int num = _initData.properties.getPropertyAsIntWithDefault("Ice.BatchAutoFlushSize", 1024); // 1MB
+ if(num < 1)
+ {
+ _batchAutoFlushSize = num;
+ }
+ else if(num > 0x7fffffff / 1024)
+ {
+ _batchAutoFlushSize = 0x7fffffff;
+ }
+ else
+ {
+ _batchAutoFlushSize = num * 1024; // Property is in kilobytes, _batchAutoFlushSize in bytes
+ }
+ }
+
+ _cacheMessageBuffers = _initData.properties.getPropertyAsIntWithDefault("Ice.CacheMessageBuffers", 2);
+
+ _implicitContext = Ice.ImplicitContextI.create(_initData.properties.getProperty("Ice.ImplicitContext"));
+ _routerManager = new RouterManager();
+
+ _locatorManager = new LocatorManager(_initData.properties);
+
+ _referenceFactory = new ReferenceFactory(this, communicator);
+
+ _proxyFactory = new ProxyFactory(this);
+
+ _requestHandlerFactory = new RequestHandlerFactory(this);
+
+ bool isIPv6Supported = Network.isIPv6Supported();
+ bool ipv4 = _initData.properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0;
+ bool ipv6 = _initData.properties.getPropertyAsIntWithDefault("Ice.IPv6", isIPv6Supported ? 1 : 0) > 0;
+ if(!ipv4 && !ipv6)
+ {
+ throw new Ice.InitializationException("Both IPV4 and IPv6 support cannot be disabled.");
+ }
+ else if(ipv4 && ipv6)
+ {
+ _protocolSupport = Network.EnableBoth;
+ }
+ else if(ipv4)
+ {
+ _protocolSupport = Network.EnableIPv4;
+ }
+ else
+ {
+ _protocolSupport = Network.EnableIPv6;
+ }
+ _preferIPv6 = _initData.properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0;
+
+ _networkProxy = createNetworkProxy(_initData.properties, _protocolSupport);
+
+ _endpointFactoryManager = new EndpointFactoryManager(this);
+
+ ProtocolInstance tcpInstance = new ProtocolInstance(this, Ice.TCPEndpointType.value, "tcp", false);
+ _endpointFactoryManager.add(new TcpEndpointFactory(tcpInstance));
+
+ ProtocolInstance udpInstance = new ProtocolInstance(this, Ice.UDPEndpointType.value, "udp", false);
+ _endpointFactoryManager.add(new UdpEndpointFactory(udpInstance));
+
+#if !SILVERLIGHT
+ _pluginManager = new Ice.PluginManagerI(communicator);
+#endif
+
+ _outgoingConnectionFactory = new OutgoingConnectionFactory(communicator, this);
+
+ _servantFactoryManager = new ObjectFactoryManager();
+
+ _objectAdapterFactory = new ObjectAdapterFactory(this, communicator);
+
+ _retryQueue = new RetryQueue(this);
+ }
+ catch(Ice.LocalException)
+ {
+ destroy();
+ throw;
+ }
+ }
+
+ public void finishSetup(ref string[] args, Ice.Communicator communicator)
+ {
+ //
+ // Load plug-ins.
+ //
+ Debug.Assert(_serverThreadPool == null);
+#if !SILVERLIGHT
+ Ice.PluginManagerI pluginManagerImpl = (Ice.PluginManagerI)_pluginManager;
+ pluginManagerImpl.loadPlugins(ref args);
+#endif
+
+ //
+ // Add WS and WSS endpoint factories if TCP/SSL factories are installed.
+ //
+ EndpointFactory tcpFactory = _endpointFactoryManager.get(Ice.TCPEndpointType.value);
+ if(tcpFactory != null)
+ {
+ ProtocolInstance instance = new ProtocolInstance(this, Ice.WSEndpointType.value, "ws", false);
+ _endpointFactoryManager.add(new WSEndpointFactory(instance, tcpFactory.clone(instance)));
+ }
+ EndpointFactory sslFactory = _endpointFactoryManager.get(Ice.SSLEndpointType.value);
+ if(sslFactory != null)
+ {
+ ProtocolInstance instance = new ProtocolInstance(this, Ice.WSSEndpointType.value, "wss", true);
+ _endpointFactoryManager.add(new WSEndpointFactory(instance, sslFactory.clone(instance)));
+ }
+
+ //
+ // Create Admin facets, if enabled.
+ //
+ // Note that any logger-dependent admin facet must be created after we load all plugins,
+ // since one of these plugins can be a Logger plugin that sets a new logger during loading
+ //
+
+ if(_initData.properties.getProperty("Ice.Admin.Enabled").Length == 0)
+ {
+ _adminEnabled = _initData.properties.getProperty("Ice.Admin.Endpoints").Length > 0;
+ }
+ else
+ {
+ _adminEnabled = _initData.properties.getPropertyAsInt("Ice.Admin.Enabled") > 0;
+ }
+
+ string[] facetFilter = _initData.properties.getPropertyAsList("Ice.Admin.Facets");
+ if(facetFilter.Length > 0)
+ {
+ foreach(string s in facetFilter)
+ {
+ _adminFacetFilter.Add(s);
+ }
+ }
+
+ if(_adminEnabled)
+ {
+ //
+ // Process facet
+ //
+ string processFacetName = "Process";
+ if(_adminFacetFilter.Count == 0 || _adminFacetFilter.Contains(processFacetName))
+ {
+ _adminFacets.Add(processFacetName, new ProcessI(communicator));
+ }
+
+ //
+ // Logger facet
+ //
+ string loggerFacetName = "Logger";
+ if(_adminFacetFilter.Count == 0 || _adminFacetFilter.Contains(loggerFacetName))
+ {
+ LoggerAdminLogger logger = new LoggerAdminLoggerI(_initData.properties, _initData.logger);
+ setLogger(logger);
+ _adminFacets.Add(loggerFacetName, logger.getFacet());
+ }
+
+ //
+ // Properties facet
+ //
+ string propertiesFacetName = "Properties";
+ PropertiesAdminI propsAdmin = null;
+ if(_adminFacetFilter.Count == 0 || _adminFacetFilter.Contains(propertiesFacetName))
+ {
+ propsAdmin= new PropertiesAdminI(_initData.properties, _initData.logger);
+ _adminFacets.Add(propertiesFacetName, propsAdmin);
+ }
+
+ //
+ // Metrics facet
+ //
+ string metricsFacetName = "Metrics";
+ if(_adminFacetFilter.Count == 0 || _adminFacetFilter.Contains(metricsFacetName))
+ {
+ CommunicatorObserverI observer = new CommunicatorObserverI(_initData);
+ _initData.observer = observer;
+ _adminFacets.Add(metricsFacetName, observer.getFacet());
+
+ //
+ // Make sure the admin plugin receives property updates.
+ //
+ if(propsAdmin != null)
+ {
+ propsAdmin.addUpdateCallback(observer.getFacet());
+ }
+ }
+ }
+
+ //
+ // Set observer updater
+ //
+ if(_initData.observer != null)
+ {
+ _initData.observer.setObserverUpdater(new ObserverUpdaterI(this));
+ }
+
+ //
+ // Create threads.
+ //
+ try
+ {
+#if !SILVERLIGHT
+ if(initializationData().properties.getProperty("Ice.ThreadPriority").Length > 0)
+ {
+ ThreadPriority priority = IceInternal.Util.stringToThreadPriority(
+ initializationData().properties.getProperty("Ice.ThreadPriority"));
+ _timer = new Timer(this, priority);
+ }
+ else
+ {
+ _timer = new Timer(this);
+ }
+#else
+ _timer = new Timer(this);
+#endif
+ }
+ catch(System.Exception ex)
+ {
+ string s = "cannot create thread for timer:\n" + ex;
+ _initData.logger.error(s);
+ throw;
+ }
+
+#if !SILVERLIGHT
+ try
+ {
+ _endpointHostResolver = new EndpointHostResolver(this);
+ }
+ catch(System.Exception ex)
+ {
+ string s = "cannot create thread for endpoint host resolver:\n" + ex;
+ _initData.logger.error(s);
+ throw;
+ }
+#endif
+ _clientThreadPool = new ThreadPool(this, "Ice.ThreadPool.Client", 0);
+
+ //
+ // The default router/locator may have been set during the loading of plugins.
+ // Therefore we make sure it is not already set before checking the property.
+ //
+ if(_referenceFactory.getDefaultRouter() == null)
+ {
+ Ice.RouterPrx r = Ice.RouterPrxHelper.uncheckedCast(
+ _proxyFactory.propertyToProxy("Ice.Default.Router"));
+ if(r != null)
+ {
+ _referenceFactory = _referenceFactory.setDefaultRouter(r);
+ }
+ }
+
+ if(_referenceFactory.getDefaultLocator() == null)
+ {
+ Ice.LocatorPrx l = Ice.LocatorPrxHelper.uncheckedCast(
+ _proxyFactory.propertyToProxy("Ice.Default.Locator"));
+ if(l != null)
+ {
+ _referenceFactory = _referenceFactory.setDefaultLocator(l);
+ }
+ }
+
+ //
+ // Show process id if requested (but only once).
+ //
+#if !SILVERLIGHT
+ lock(this)
+ {
+ if(!_printProcessIdDone && _initData.properties.getPropertyAsInt("Ice.PrintProcessId") > 0)
+ {
+ using(Process p = Process.GetCurrentProcess())
+ {
+ System.Console.WriteLine(p.Id);
+ }
+ _printProcessIdDone = true;
+ }
+ }
+#endif
+
+ //
+ // Server thread pool initialization is lazy in serverThreadPool().
+ //
+
+ //
+ // An application can set Ice.InitPlugins=0 if it wants to postpone
+ // initialization until after it has interacted directly with the
+ // plug-ins.
+ //
+#if !SILVERLIGHT
+ if(_initData.properties.getPropertyAsIntWithDefault("Ice.InitPlugins", 1) > 0)
+ {
+ pluginManagerImpl.initializePlugins();
+ }
+#endif
+ //
+ // This must be done last as this call creates the Ice.Admin object adapter
+ // and eventually registers a process proxy with the Ice locator (allowing
+ // remote clients to invoke on Ice.Admin facets as soon as it's registered).
+ //
+ if(_initData.properties.getPropertyAsIntWithDefault("Ice.Admin.DelayCreation", 0) <= 0)
+ {
+ getAdmin();
+ }
+ }
+
+ //
+ // Only for use by Ice.CommunicatorI
+ //
+ public void destroy()
+ {
+ lock(this)
+ {
+ //
+ // If destroy is in progress, wait for it to be done. This
+ // is necessary in case destroy() is called concurrently
+ // by multiple threads.
+ //
+ while(_state == StateDestroyInProgress)
+ {
+ Monitor.Wait(this);
+ }
+
+ if(_state == StateDestroyed)
+ {
+ return;
+ }
+ _state = StateDestroyInProgress;
+ }
+
+ //
+ // Shutdown and destroy all the incoming and outgoing Ice
+ // connections and wait for the connections to be finished.
+ //
+ if(_objectAdapterFactory != null)
+ {
+ _objectAdapterFactory.shutdown();
+ }
+
+ if(_outgoingConnectionFactory != null)
+ {
+ _outgoingConnectionFactory.destroy();
+ }
+
+ if(_objectAdapterFactory != null)
+ {
+ _objectAdapterFactory.destroy();
+ }
+
+ if(_outgoingConnectionFactory != null)
+ {
+ _outgoingConnectionFactory.waitUntilFinished();
+ }
+
+ if(_retryQueue != null)
+ {
+ _retryQueue.destroy(); // Must be called before destroying thread pools.
+ }
+
+ if(_initData.observer != null)
+ {
+ _initData.observer.setObserverUpdater(null);
+ }
+
+ LoggerAdminLogger logger = _initData.logger as LoggerAdminLogger;
+ if(logger != null)
+ {
+ logger.destroy();
+ }
+
+ //
+ // Now, destroy the thread pools. This must be done *only* after
+ // all the connections are finished (the connections destruction
+ // can require invoking callbacks with the thread pools).
+ //
+ if(_serverThreadPool != null)
+ {
+ _serverThreadPool.destroy();
+ }
+ if(_clientThreadPool != null)
+ {
+ _clientThreadPool.destroy();
+ }
+ if(_asyncIOThread != null)
+ {
+ _asyncIOThread.destroy();
+ }
+#if !SILVERLIGHT
+ if(_endpointHostResolver != null)
+ {
+ _endpointHostResolver.destroy();
+ }
+#endif
+
+ //
+ // Wait for all the threads to be finished.
+ //
+ if(_timer != null)
+ {
+ _timer.destroy();
+ }
+ if(_clientThreadPool != null)
+ {
+ _clientThreadPool.joinWithAllThreads();
+ }
+ if(_serverThreadPool != null)
+ {
+ _serverThreadPool.joinWithAllThreads();
+ }
+ if(_asyncIOThread != null)
+ {
+ _asyncIOThread.joinWithThread();
+ }
+#if !SILVERLIGHT
+ if(_endpointHostResolver != null)
+ {
+ _endpointHostResolver.joinWithThread();
+ }
+#endif
+
+ if(_servantFactoryManager != null)
+ {
+ _servantFactoryManager.destroy();
+ }
+
+ if(_routerManager != null)
+ {
+ _routerManager.destroy();
+ }
+
+ if(_locatorManager != null)
+ {
+ _locatorManager.destroy();
+ }
+
+ if(_endpointFactoryManager != null)
+ {
+ _endpointFactoryManager.destroy();
+ }
+
+ if(_initData.properties.getPropertyAsInt("Ice.Warn.UnusedProperties") > 0)
+ {
+ List<string> unusedProperties = ((Ice.PropertiesI)_initData.properties).getUnusedProperties();
+ if (unusedProperties.Count != 0)
+ {
+ StringBuilder message = new StringBuilder("The following properties were set but never read:");
+ foreach (string s in unusedProperties)
+ {
+ message.Append("\n ");
+ message.Append(s);
+ }
+ _initData.logger.warning(message.ToString());
+ }
+ }
+
+ //
+ // Destroy last so that a Logger plugin can receive all log/traces before its destruction.
+ //
+ if(_pluginManager != null)
+ {
+ _pluginManager.destroy();
+ }
+
+ lock(this)
+ {
+ _objectAdapterFactory = null;
+ _outgoingConnectionFactory = null;
+ _retryQueue = null;
+
+ _serverThreadPool = null;
+ _clientThreadPool = null;
+ _asyncIOThread = null;
+#if !SILVERLIGHT
+ _endpointHostResolver = null;
+#endif
+ _timer = null;
+
+ _servantFactoryManager = null;
+ _referenceFactory = null;
+ _requestHandlerFactory = null;
+ _proxyFactory = null;
+ _routerManager = null;
+ _locatorManager = null;
+ _endpointFactoryManager = null;
+ _pluginManager = null;
+
+ _adminAdapter = null;
+ _adminFacets.Clear();
+
+ _state = StateDestroyed;
+ Monitor.PulseAll(this);
+ }
+ }
+
+ public BufSizeWarnInfo getBufSizeWarn(short type)
+ {
+ lock(_setBufSizeWarn)
+ {
+ BufSizeWarnInfo info;
+ if(!_setBufSizeWarn.ContainsKey(type))
+ {
+ info = new BufSizeWarnInfo();
+ info.sndWarn = false;
+ info.sndSize = -1;
+ info.rcvWarn = false;
+ info.rcvSize = -1;
+ _setBufSizeWarn.Add(type, info);
+ }
+ else
+ {
+ info = _setBufSizeWarn[type];
+ }
+ return info;
+ }
+ }
+
+ public void setSndBufSizeWarn(short type, int size)
+ {
+ lock(_setBufSizeWarn)
+ {
+ BufSizeWarnInfo info = getBufSizeWarn(type);
+ info.sndWarn = true;
+ info.sndSize = size;
+ _setBufSizeWarn[type] = info;
+ }
+ }
+
+ public void setRcvBufSizeWarn(short type, int size)
+ {
+ lock(_setBufSizeWarn)
+ {
+ BufSizeWarnInfo info = getBufSizeWarn(type);
+ info.rcvWarn = true;
+ info.rcvSize = size;
+ _setBufSizeWarn[type] = info;
+ }
+ }
+
+ internal void updateConnectionObservers()
+ {
+ try
+ {
+ Debug.Assert(_outgoingConnectionFactory != null);
+ _outgoingConnectionFactory.updateConnectionObservers();
+ Debug.Assert(_objectAdapterFactory != null);
+ _objectAdapterFactory.updateConnectionObservers();
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ }
+ }
+
+ internal void updateThreadObservers()
+ {
+ try
+ {
+ if(_clientThreadPool != null)
+ {
+ _clientThreadPool.updateObservers();
+ }
+ if(_serverThreadPool != null)
+ {
+ _serverThreadPool.updateObservers();
+ }
+ Debug.Assert(_objectAdapterFactory != null);
+ _objectAdapterFactory.updateThreadObservers();
+#if !SILVERLIGHT
+ if(_endpointHostResolver != null)
+ {
+ _endpointHostResolver.updateObserver();
+ }
+#endif
+ if(_asyncIOThread != null)
+ {
+ _asyncIOThread.updateObserver();
+ }
+ if(_timer != null)
+ {
+ _timer.updateObserver(_initData.observer);
+ }
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ }
+ }
+
+ internal void addAllAdminFacets()
+ {
+ lock(this)
+ {
+ Dictionary<string, Ice.Object> filteredFacets = new Dictionary<string, Ice.Object>();
+
+ foreach(KeyValuePair<string, Ice.Object> entry in _adminFacets)
+ {
+ if(_adminFacetFilter.Count == 0 || _adminFacetFilter.Contains(entry.Key))
+ {
+ _adminAdapter.addFacet(entry.Value, _adminIdentity, entry.Key);
+ }
+ else
+ {
+ filteredFacets.Add(entry.Key, entry.Value);
+ }
+ }
+ _adminFacets = filteredFacets;
+ }
+ }
+
+ internal void setServerProcessProxy(Ice.ObjectAdapter adminAdapter, Ice.Identity adminIdentity)
+ {
+ Ice.ObjectPrx admin = adminAdapter.createProxy(adminIdentity);
+ Ice.LocatorPrx locator = adminAdapter.getLocator();
+ string serverId = _initData.properties.getProperty("Ice.Admin.ServerId");
+
+ if(locator != null && serverId.Length > 0)
+ {
+ Ice.ProcessPrx process = Ice.ProcessPrxHelper.uncheckedCast(admin.ice_facet("Process"));
+ try
+ {
+ //
+ // Note that as soon as the process proxy is registered, the communicator might be
+ // shutdown by a remote client and admin facets might start receiving calls.
+ //
+ locator.getRegistry().setServerProcessProxy(serverId, process);
+ }
+ catch(Ice.ServerNotFoundException)
+ {
+ if(_traceLevels.location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't register server `" + serverId + "' with the locator registry:\n");
+ s.Append("the server is not known to the locator registry");
+ _initData.logger.trace(_traceLevels.locationCat, s.ToString());
+ }
+
+ throw new Ice.InitializationException("Locator knows nothing about server `" + serverId + "'");
+ }
+ catch(Ice.LocalException ex)
+ {
+ if(_traceLevels.location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't register server `" + serverId + "' with the locator registry:\n" + ex);
+ _initData.logger.trace(_traceLevels.locationCat, s.ToString());
+ }
+ throw; // TODO: Shall we raise a special exception instead of a non obvious local exception?
+ }
+
+ if(_traceLevels.location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("registered server `" + serverId + "' with the locator registry");
+ _initData.logger.trace(_traceLevels.locationCat, s.ToString());
+ }
+ }
+ }
+
+ private NetworkProxy createNetworkProxy(Ice.Properties props, int protocolSupport)
+ {
+ string proxyHost;
+
+ proxyHost = props.getProperty("Ice.SOCKSProxyHost");
+ if(proxyHost.Length > 0)
+ {
+ if(protocolSupport == Network.EnableIPv6)
+ {
+ throw new Ice.InitializationException("IPv6 only is not supported with SOCKS4 proxies");
+ }
+ int proxyPort = props.getPropertyAsIntWithDefault("Ice.SOCKSProxyPort", 1080);
+ return new SOCKSNetworkProxy(proxyHost, proxyPort);
+ }
+
+ proxyHost = props.getProperty("Ice.HTTPProxyHost");
+ if(proxyHost.Length > 0)
+ {
+ return new HTTPNetworkProxy(proxyHost, props.getPropertyAsIntWithDefault("Ice.HTTPProxyPort", 1080));
+ }
+
+ return null;
+ }
+
+ private const int StateActive = 0;
+ private const int StateDestroyInProgress = 1;
+ private const int StateDestroyed = 2;
+ private int _state;
+ private Ice.InitializationData _initData; // Immutable, not reset by destroy().
+ private TraceLevels _traceLevels; // Immutable, not reset by destroy().
+ private DefaultsAndOverrides _defaultsAndOverrides; // Immutable, not reset by destroy().
+#if COMPACT || SILVERLIGHT
+ private string[] _factoryAssemblies; // Immutable, not reset by destroy().
+#endif
+ private int _messageSizeMax; // Immutable, not reset by destroy().
+ private int _batchAutoFlushSize; // Immutable, not reset by destroy().
+ private int _cacheMessageBuffers; // Immutable, not reset by destroy().
+ private ACMConfig _clientACM; // Immutable, not reset by destroy().
+ private ACMConfig _serverACM; // Immutable, not reset by destroy().
+ private Ice.ImplicitContextI _implicitContext; // Immutable
+ private RouterManager _routerManager;
+ private LocatorManager _locatorManager;
+ private ReferenceFactory _referenceFactory;
+ private RequestHandlerFactory _requestHandlerFactory;
+ private ProxyFactory _proxyFactory;
+ private OutgoingConnectionFactory _outgoingConnectionFactory;
+ private ObjectFactoryManager _servantFactoryManager;
+ private ObjectAdapterFactory _objectAdapterFactory;
+ private int _protocolSupport;
+ private bool _preferIPv6;
+ private NetworkProxy _networkProxy;
+ private ThreadPool _clientThreadPool;
+ private ThreadPool _serverThreadPool;
+ private AsyncIOThread _asyncIOThread;
+#if !SILVERLIGHT
+ private EndpointHostResolver _endpointHostResolver;
+#endif
+ private Timer _timer;
+ private RetryQueue _retryQueue;
+ private EndpointFactoryManager _endpointFactoryManager;
+ private Ice.PluginManager _pluginManager;
+ private bool _adminEnabled = false;
+ private Ice.ObjectAdapter _adminAdapter;
+ private Dictionary<string, Ice.Object> _adminFacets = new Dictionary<string, Ice.Object>();
+ private HashSet<string> _adminFacetFilter = new HashSet<string>();
+ private Ice.Identity _adminIdentity;
+ private Dictionary<short, BufSizeWarnInfo> _setBufSizeWarn = new Dictionary<short, BufSizeWarnInfo>();
+
+#if !SILVERLIGHT
+ private static bool _printProcessIdDone = false;
+#endif
+
+#if !SILVERLIGHT && !UNITY
+ private static bool _oneOfDone = false;
+#endif
+
+ private static System.Object _staticLock = new System.Object();
+ }
+}
diff --git a/csharp/src/Ice/InstrumentationI.cs b/csharp/src/Ice/InstrumentationI.cs
new file mode 100644
index 00000000000..f49e832cd50
--- /dev/null
+++ b/csharp/src/Ice/InstrumentationI.cs
@@ -0,0 +1,1222 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Text;
+ using System.Collections.Generic;
+
+ using IceMX;
+
+ public class ObserverWithDelegate<T, O> : Observer<T>
+ where T : Metrics, new()
+ where O : Ice.Instrumentation.Observer
+ {
+ override public void
+ attach()
+ {
+ base.attach();
+ if(delegate_ != null)
+ {
+ delegate_.attach();
+ }
+ }
+
+ override public void
+ detach()
+ {
+ base.detach();
+ if(delegate_ != null)
+ {
+ delegate_.detach();
+ }
+ }
+
+ override public void
+ failed(string exceptionName)
+ {
+ base.failed(exceptionName);
+ if(delegate_ != null)
+ {
+ delegate_.failed(exceptionName);
+ }
+ }
+
+ public O
+ getDelegate()
+ {
+ return delegate_;
+ }
+
+ public void
+ setDelegate(O del)
+ {
+ delegate_ = del;
+ }
+
+ public Observer getObserver<S, ObserverImpl, Observer>(string mapName, MetricsHelper<S> helper, Observer del)
+ where S : Metrics, new()
+ where ObserverImpl : ObserverWithDelegate<S, Observer>, Observer, new()
+ where Observer : Ice.Instrumentation.Observer
+ {
+ ObserverImpl obsv = base.getObserver<S, ObserverImpl>(mapName, helper);
+ if(obsv != null)
+ {
+ obsv.setDelegate(del);
+ return (Observer)obsv;
+ }
+ return del;
+ }
+
+ protected O delegate_;
+ };
+
+ public class ObserverFactoryWithDelegate<T, OImpl, O> : ObserverFactory<T, OImpl>
+ where T : Metrics, new()
+ where OImpl : ObserverWithDelegate<T, O>, O, new()
+ where O : Ice.Instrumentation.Observer
+ {
+ public ObserverFactoryWithDelegate(IceInternal.MetricsAdminI metrics, string name) : base(metrics, name)
+ {
+ }
+
+ public O getObserver(MetricsHelper<T> helper, O del)
+ {
+ OImpl o = base.getObserver(helper);
+ if(o != null)
+ {
+ o.setDelegate(del);
+ return o;
+ }
+ return del;
+ }
+
+ public O getObserver(MetricsHelper<T> helper, object observer, O del)
+ {
+ OImpl o = base.getObserver(helper, observer);
+ if(o != null)
+ {
+ o.setDelegate(del);
+ return o;
+ }
+ return del;
+ }
+ }
+
+ static class AttrsUtil
+ {
+ public static void
+ addEndpointAttributes<T>(MetricsHelper<T>.AttributeResolver r, Type cl) where T : IceMX.Metrics
+ {
+ r.add("endpoint", cl.GetMethod("getEndpoint"));
+
+ Type cli = typeof(Ice.EndpointInfo);
+ r.add("endpointType", cl.GetMethod("getEndpointInfo"), cli.GetMethod("type"));
+ r.add("endpointIsDatagram", cl.GetMethod("getEndpointInfo"), cli.GetMethod("datagram"));
+ r.add("endpointIsSecure", cl.GetMethod("getEndpointInfo"), cli.GetMethod("secure"));
+ r.add("endpointTimeout", cl.GetMethod("getEndpointInfo"), cli.GetField("timeout"));
+ r.add("endpointCompress", cl.GetMethod("getEndpointInfo"), cli.GetField("compress"));
+
+ cli = typeof(Ice.IPEndpointInfo);
+ r.add("endpointHost", cl.GetMethod("getEndpointInfo"), cli.GetField("host"));
+ r.add("endpointPort", cl.GetMethod("getEndpointInfo"), cli.GetField("port"));
+ }
+
+ public static void
+ addConnectionAttributes<T>(MetricsHelper<T>.AttributeResolver r, Type cl) where T : IceMX.Metrics
+ {
+ Type cli = typeof(Ice.ConnectionInfo);
+ r.add("incoming", cl.GetMethod("getConnectionInfo"), cli.GetField("incoming"));
+ r.add("adapterName", cl.GetMethod("getConnectionInfo"), cli.GetField("adapterName"));
+ r.add("connectionId", cl.GetMethod("getConnectionInfo"), cli.GetField("connectionId"));
+
+ cli = typeof(Ice.IPConnectionInfo);
+ r.add("localHost", cl.GetMethod("getConnectionInfo"), cli.GetField("localAddress"));
+ r.add("localPort", cl.GetMethod("getConnectionInfo"), cli.GetField("localPort"));
+ r.add("remoteHost", cl.GetMethod("getConnectionInfo"), cli.GetField("remoteAddress"));
+ r.add("remotePort", cl.GetMethod("getConnectionInfo"), cli.GetField("remotePort"));
+
+ cli = typeof(Ice.UDPConnectionInfo);
+ r.add("mcastHost", cl.GetMethod("getConnectionInfo"), cli.GetField("mcastAddress"));
+ r.add("mcastPort", cl.GetMethod("getConnectionInfo"), cli.GetField("mcastPort"));
+
+ AttrsUtil.addEndpointAttributes<T>(r, cl);
+ }
+ }
+
+ class ConnectionHelper : MetricsHelper<ConnectionMetrics>
+ {
+ class AttributeResolverI : MetricsHelper<ConnectionMetrics>.AttributeResolver
+ {
+ public AttributeResolverI()
+ {
+ try
+ {
+ Type cl = typeof(ConnectionHelper);
+ add("parent", cl.GetMethod("getParent"));
+ add("id", cl.GetMethod("getId"));
+ add("state", cl.GetMethod("getState"));
+ AttrsUtil.addConnectionAttributes<ConnectionMetrics>(this, cl);
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ };
+ static AttributeResolver _attributes = new AttributeResolverI();
+
+ public ConnectionHelper(Ice.ConnectionInfo con, Ice.Endpoint endpt, Ice.Instrumentation.ConnectionState state)
+ : base(_attributes)
+ {
+ _connectionInfo = con;
+ _endpoint = endpt;
+ _state = state;
+ }
+
+ public string getId()
+ {
+ if(_id == null)
+ {
+ StringBuilder os = new StringBuilder();
+ if(_connectionInfo is Ice.IPConnectionInfo)
+ {
+ Ice.IPConnectionInfo info = (Ice.IPConnectionInfo)_connectionInfo;
+ os.Append(info.localAddress).Append(':').Append(info.localPort);
+ os.Append(" -> ");
+ os.Append(info.remoteAddress).Append(':').Append(info.remotePort);
+ }
+ else
+ {
+ os.Append("connection-").Append(_connectionInfo);
+ }
+ if(_connectionInfo.connectionId.Length > 0)
+ {
+ os.Append(" [").Append(_connectionInfo.connectionId).Append("]");
+ }
+ _id = os.ToString();
+ }
+ return _id;
+ }
+
+ public string getState()
+ {
+ switch(_state)
+ {
+ case Ice.Instrumentation.ConnectionState.ConnectionStateValidating:
+ return "validating";
+ case Ice.Instrumentation.ConnectionState.ConnectionStateHolding:
+ return "holding";
+ case Ice.Instrumentation.ConnectionState.ConnectionStateActive:
+ return "active";
+ case Ice.Instrumentation.ConnectionState.ConnectionStateClosing:
+ return "closing";
+ case Ice.Instrumentation.ConnectionState.ConnectionStateClosed:
+ return "closed";
+ default:
+ Debug.Assert(false);
+ return "";
+ }
+ }
+
+ public string getParent()
+ {
+ if(_connectionInfo.adapterName != null && _connectionInfo.adapterName.Length > 0)
+ {
+ return _connectionInfo.adapterName;
+ }
+ else
+ {
+ return "Communicator";
+ }
+ }
+
+ public Ice.ConnectionInfo getConnectionInfo()
+ {
+ return _connectionInfo;
+ }
+
+ public Ice.Endpoint getEndpoint()
+ {
+ return _endpoint;
+ }
+
+ public Ice.EndpointInfo getEndpointInfo()
+ {
+ if(_endpointInfo == null)
+ {
+ _endpointInfo = _endpoint.getInfo();
+ }
+ return _endpointInfo;
+ }
+
+ readonly private Ice.ConnectionInfo _connectionInfo;
+ readonly private Ice.Endpoint _endpoint;
+ readonly private Ice.Instrumentation.ConnectionState _state;
+ private string _id;
+ private Ice.EndpointInfo _endpointInfo;
+ };
+
+ class DispatchHelper : MetricsHelper<DispatchMetrics>
+ {
+ class AttributeResolverI : MetricsHelper<DispatchMetrics>.AttributeResolver
+ {
+ public AttributeResolverI()
+ {
+ try
+ {
+ Type cl = typeof(DispatchHelper);
+ add("parent", cl.GetMethod("getParent"));
+ add("id", cl.GetMethod("getId"));
+
+ AttrsUtil.addConnectionAttributes<DispatchMetrics>(this, cl);
+
+ Type clc = typeof(Ice.Current);
+ add("operation", cl.GetMethod("getCurrent"), clc.GetField("operation"));
+ add("identity", cl.GetMethod("getIdentity"));
+ add("facet", cl.GetMethod("getCurrent"), clc.GetField("facet"));
+ add("current", cl.GetMethod("getCurrent"), clc.GetField("requestId"));
+ add("mode", cl.GetMethod("getMode"));
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ };
+ static AttributeResolver _attributes = new AttributeResolverI();
+
+ public DispatchHelper(Ice.Current current, int size) : base(_attributes)
+ {
+ _current = current;
+ _size = size;
+ }
+
+ override protected string defaultResolve(string attribute)
+ {
+ if(attribute.IndexOf("context.", 0) == 0)
+ {
+ string v;
+ if(_current.ctx.TryGetValue(attribute.Substring(8), out v))
+ {
+ return v;
+ }
+ }
+ throw new ArgumentOutOfRangeException(attribute);
+ }
+
+ override public void initMetrics(DispatchMetrics v)
+ {
+ v.size += _size;
+ }
+
+ public string getMode()
+ {
+ return _current.requestId == 0 ? "oneway" : "twoway";
+ }
+
+ public string getId()
+ {
+ if(_id == null)
+ {
+ StringBuilder os = new StringBuilder();
+ if(_current.id.category != null && _current.id.category.Length > 0)
+ {
+ os.Append(_current.id.category).Append('/');
+ }
+ os.Append(_current.id.name).Append(" [").Append(_current.operation).Append(']');
+ _id = os.ToString();
+ }
+ return _id;
+ }
+
+ public string getParent()
+ {
+ return _current.adapter.getName();
+ }
+
+ public Ice.ConnectionInfo getConnectionInfo()
+ {
+ if(_current.con != null)
+ {
+ return _current.con.getInfo();
+ }
+ return null;
+ }
+
+ public Ice.Endpoint getEndpoint()
+ {
+ if(_current.con != null)
+ {
+ return _current.con.getEndpoint();
+ }
+ return null;
+ }
+
+ public Ice.Connection getConnection()
+ {
+ return _current.con;
+ }
+
+ public Ice.EndpointInfo getEndpointInfo()
+ {
+ if(_current.con != null && _endpointInfo == null)
+ {
+ _endpointInfo = _current.con.getEndpoint().getInfo();
+ }
+ return _endpointInfo;
+ }
+
+ public Ice.Current getCurrent()
+ {
+ return _current;
+ }
+
+ public string getIdentity()
+ {
+ return _current.adapter.getCommunicator().identityToString(_current.id);
+ }
+
+ readonly private Ice.Current _current;
+ readonly private int _size;
+ private string _id;
+ private Ice.EndpointInfo _endpointInfo;
+ };
+
+ class InvocationHelper : MetricsHelper<InvocationMetrics>
+ {
+ class AttributeResolverI : MetricsHelper<InvocationMetrics>.AttributeResolver
+ {
+ public AttributeResolverI()
+ {
+ try
+ {
+ Type cl = typeof(InvocationHelper);
+ add("parent", cl.GetMethod("getParent"));
+ add("id", cl.GetMethod("getId"));
+
+ add("operation", cl.GetMethod("getOperation"));
+ add("identity", cl.GetMethod("getIdentity"));
+
+ Type cli = typeof(Ice.ObjectPrx);
+ add("facet", cl.GetMethod("getProxy"), cli.GetMethod("ice_getFacet"));
+ add("encoding", cl.GetMethod("getEncodingVersion"));
+ add("mode", cl.GetMethod("getMode"));
+ add("proxy", cl.GetMethod("getProxy"));
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ };
+ static AttributeResolver _attributes = new AttributeResolverI();
+
+ public InvocationHelper(Ice.ObjectPrx proxy, string op, Dictionary<string, string> ctx) : base(_attributes)
+ {
+ _proxy = proxy;
+ _operation = op;
+ _context = ctx;
+ }
+
+ override protected string defaultResolve(string attribute)
+ {
+ if(attribute.IndexOf("context.", 0) == 0)
+ {
+ string v;
+ if(_context.TryGetValue(attribute.Substring(8), out v))
+ {
+ return v;
+ }
+ }
+ throw new ArgumentOutOfRangeException(attribute);
+ }
+
+ public string getMode()
+ {
+ if(_proxy == null)
+ {
+ throw new ArgumentOutOfRangeException("mode");
+ }
+
+ if(_proxy.ice_isTwoway())
+ {
+ return "twoway";
+ }
+ else if(_proxy.ice_isOneway())
+ {
+ return "oneway";
+ }
+ else if(_proxy.ice_isBatchOneway())
+ {
+ return "batch-oneway";
+ }
+ else if(_proxy.ice_isDatagram())
+ {
+ return "datagram";
+ }
+ else if(_proxy.ice_isBatchDatagram())
+ {
+ return "batch-datagram";
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException("mode");
+ }
+ }
+
+ public string getId()
+ {
+ if(_id == null)
+ {
+ if(_proxy != null)
+ {
+ StringBuilder os = new StringBuilder();
+ try
+ {
+ os.Append(_proxy.ice_endpoints(emptyEndpoints)).Append(" [").Append(_operation).Append(']');
+ }
+ catch(Ice.Exception)
+ {
+ // Either a fixed proxy or the communicator is destroyed.
+ os.Append(_proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity()));
+ os.Append(" [").Append(_operation).Append(']');
+ }
+ _id = os.ToString();
+ }
+ else
+ {
+ _id = _operation;
+ }
+ }
+ return _id;
+ }
+
+ public string getParent()
+ {
+ return "Communicator";
+ }
+
+ public Ice.ObjectPrx getProxy()
+ {
+ return _proxy;
+ }
+
+ public string getEncodingVersion()
+ {
+ return Ice.Util.encodingVersionToString(_proxy.ice_getEncodingVersion());
+ }
+
+ public string getIdentity()
+ {
+ if(_proxy != null)
+ {
+ return _proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity());
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ public string getOperation()
+ {
+ return _operation;
+ }
+
+ readonly private Ice.ObjectPrx _proxy;
+ readonly private string _operation;
+ readonly private Dictionary<string, string> _context;
+ private string _id;
+
+ readonly static private Ice.Endpoint[] emptyEndpoints = new Ice.Endpoint[0];
+ };
+
+ class ThreadHelper : MetricsHelper<ThreadMetrics>
+ {
+ class AttributeResolverI : MetricsHelper<ThreadMetrics>.AttributeResolver
+ {
+ public AttributeResolverI()
+ {
+ try
+ {
+ Type cl = typeof(ThreadHelper);
+ add("parent", cl.GetField("_parent"));
+ add("id", cl.GetField("_id"));
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ };
+ static AttributeResolver _attributes = new AttributeResolverI();
+
+ public ThreadHelper(string parent, string id, Ice.Instrumentation.ThreadState state) : base(_attributes)
+ {
+ _parent = parent;
+ _id = id;
+ _state = state;
+ }
+
+ override public void initMetrics(ThreadMetrics v)
+ {
+ switch(_state)
+ {
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForIO:
+ ++v.inUseForIO;
+ break;
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForUser:
+ ++v.inUseForUser;
+ break;
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForOther:
+ ++v.inUseForOther;
+ break;
+ default:
+ break;
+ }
+ }
+
+ readonly public string _parent;
+ readonly public string _id;
+ readonly private Ice.Instrumentation.ThreadState _state;
+ };
+
+ class EndpointHelper : MetricsHelper<Metrics>
+ {
+ class AttributeResolverI : MetricsHelper<Metrics>.AttributeResolver
+ {
+ public AttributeResolverI()
+ {
+ try
+ {
+ Type cl = typeof(EndpointHelper);
+ add("parent", cl.GetMethod("getParent"));
+ add("id", cl.GetMethod("getId"));
+ AttrsUtil.addEndpointAttributes<Metrics>(this, cl);
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ };
+ static AttributeResolver _attributes = new AttributeResolverI();
+
+ public EndpointHelper(Ice.Endpoint endpt, string id) : base(_attributes)
+ {
+ _endpoint = endpt;
+ _id = id;
+ }
+
+ public EndpointHelper(Ice.Endpoint endpt) : base(_attributes)
+ {
+ _endpoint = endpt;
+ }
+
+ public Ice.EndpointInfo getEndpointInfo()
+ {
+ if(_endpointInfo == null)
+ {
+ _endpointInfo = _endpoint.getInfo();
+ }
+ return _endpointInfo;
+ }
+
+ public string getParent()
+ {
+ return "Communicator";
+ }
+
+ public string getId()
+ {
+ if(_id == null)
+ {
+ _id = _endpoint.ToString();
+ }
+ return _id;
+ }
+
+ public string getEndpoint()
+ {
+ return _endpoint.ToString();
+ }
+
+ readonly private Ice.Endpoint _endpoint;
+ private string _id;
+ private Ice.EndpointInfo _endpointInfo;
+ };
+
+ public class RemoteInvocationHelper : MetricsHelper<RemoteMetrics>
+ {
+ class AttributeResolverI : MetricsHelper<RemoteMetrics>.AttributeResolver
+ {
+ public AttributeResolverI()
+ {
+ try
+ {
+ Type cl = typeof(RemoteInvocationHelper);
+ add("parent", cl.GetMethod("getParent"));
+ add("id", cl.GetMethod("getId"));
+ add("requestId", cl.GetMethod("getRequestId"));
+ AttrsUtil.addConnectionAttributes<RemoteMetrics>(this, cl);
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ };
+ static AttributeResolver _attributes = new AttributeResolverI();
+
+ public RemoteInvocationHelper(Ice.ConnectionInfo con, Ice.Endpoint endpt, int requestId, int size) :
+ base(_attributes)
+ {
+ _connectionInfo = con;
+ _endpoint = endpt;
+ _requestId = requestId;
+ _size = size;
+ }
+
+ override public void initMetrics(RemoteMetrics v)
+ {
+ v.size += _size;
+ }
+
+ public string getId()
+ {
+ if(_id == null)
+ {
+ _id = _endpoint.ToString();
+ if(_connectionInfo.connectionId != null && _connectionInfo.connectionId.Length > 0)
+ {
+ _id += " [" + _connectionInfo.connectionId + "]";
+ }
+ }
+ return _id;
+ }
+
+ public int getRequestId()
+ {
+ return _requestId;
+ }
+
+ public string getParent()
+ {
+ if(_connectionInfo.adapterName != null && _connectionInfo.adapterName.Length > 0)
+ {
+ return _connectionInfo.adapterName;
+ }
+ else
+ {
+ return "Communicator";
+ }
+ }
+
+ public Ice.ConnectionInfo getConnectionInfo()
+ {
+ return _connectionInfo;
+ }
+
+ public Ice.Endpoint getEndpoint()
+ {
+ return _endpoint;
+ }
+
+ public Ice.EndpointInfo getEndpointInfo()
+ {
+ if(_endpointInfo == null)
+ {
+ _endpointInfo = _endpoint.getInfo();
+ }
+ return _endpointInfo;
+ }
+
+ readonly private Ice.ConnectionInfo _connectionInfo;
+ readonly private Ice.Endpoint _endpoint;
+ readonly private int _size;
+ readonly private int _requestId;
+ private string _id;
+ private Ice.EndpointInfo _endpointInfo;
+ };
+
+ public class CollocatedInvocationHelper : MetricsHelper<CollocatedMetrics>
+ {
+ class AttributeResolverI : MetricsHelper<CollocatedMetrics>.AttributeResolver
+ {
+ public AttributeResolverI()
+ {
+ try
+ {
+ Type cl = typeof(CollocatedInvocationHelper);
+ add("parent", cl.GetMethod("getParent"));
+ add("id", cl.GetMethod("getId"));
+ add("requestId", cl.GetMethod("getRequestId"));
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ };
+ static AttributeResolver _attributes = new AttributeResolverI();
+
+ public CollocatedInvocationHelper(Ice.ObjectAdapter adapter, int requestId, int size) :
+ base(_attributes)
+ {
+ _id = adapter.getName();
+ _requestId = requestId;
+ _size = size;
+ }
+
+ override public void initMetrics(CollocatedMetrics v)
+ {
+ v.size += _size;
+ }
+
+ public string getId()
+ {
+ return _id;
+ }
+
+ public int getRequestId()
+ {
+ return _requestId;
+ }
+
+ public string getParent()
+ {
+ return "Communicator";
+ }
+
+ readonly private int _size;
+ readonly private int _requestId;
+ readonly private string _id;
+ };
+
+ public class ObserverWithDelegateI : ObserverWithDelegate<Metrics, Ice.Instrumentation.Observer>
+ {
+ };
+
+ public class ConnectionObserverI : ObserverWithDelegate<ConnectionMetrics, Ice.Instrumentation.ConnectionObserver>,
+ Ice.Instrumentation.ConnectionObserver
+ {
+ public void sentBytes(int num)
+ {
+ _sentBytes = num;
+ forEach(sentBytesUpdate);
+ if(delegate_ != null)
+ {
+ delegate_.sentBytes(num);
+ }
+ }
+
+ public void receivedBytes(int num)
+ {
+ _receivedBytes = num;
+ forEach(receivedBytesUpdate);
+ if(delegate_ != null)
+ {
+ delegate_.receivedBytes(num);
+ }
+ }
+
+ private void sentBytesUpdate(ConnectionMetrics v)
+ {
+ v.sentBytes += _sentBytes;
+ }
+
+ private void receivedBytesUpdate(ConnectionMetrics v)
+ {
+ v.receivedBytes += _receivedBytes;
+ }
+
+ private int _sentBytes;
+ private int _receivedBytes;
+ };
+
+ public class DispatchObserverI : ObserverWithDelegate<DispatchMetrics, Ice.Instrumentation.DispatchObserver>,
+ Ice.Instrumentation.DispatchObserver
+ {
+ public void
+ userException()
+ {
+ forEach(userException);
+ if(delegate_ != null)
+ {
+ delegate_.userException();
+ }
+ }
+
+ public void reply(int size)
+ {
+ forEach((DispatchMetrics v) => {
+ v.replySize += size;
+ });
+ if(delegate_ != null)
+ {
+ delegate_.reply(size);
+ }
+ }
+
+ private void userException(DispatchMetrics v)
+ {
+ ++v.userException;
+ }
+ }
+
+ public class RemoteObserverI : ObserverWithDelegate<RemoteMetrics, Ice.Instrumentation.RemoteObserver>,
+ Ice.Instrumentation.RemoteObserver
+ {
+ public void reply(int size)
+ {
+ forEach((RemoteMetrics v) => {
+ v.replySize += size;
+ });
+ if(delegate_ != null)
+ {
+ delegate_.reply(size);
+ }
+ }
+ }
+
+ public class CollocatedObserverI : ObserverWithDelegate<CollocatedMetrics, Ice.Instrumentation.CollocatedObserver>,
+ Ice.Instrumentation.CollocatedObserver
+ {
+ public void reply(int size)
+ {
+ forEach((CollocatedMetrics v) => {
+ v.replySize += size;
+ });
+ if(delegate_ != null)
+ {
+ delegate_.reply(size);
+ }
+ }
+ }
+
+ public class InvocationObserverI : ObserverWithDelegate<InvocationMetrics, Ice.Instrumentation.InvocationObserver>,
+ Ice.Instrumentation.InvocationObserver
+ {
+ public void
+ userException()
+ {
+ forEach(userException);
+ if(delegate_ != null)
+ {
+ delegate_.userException();
+ }
+ }
+
+ public void
+ retried()
+ {
+ forEach(incrementRetry);
+ if(delegate_ != null)
+ {
+ delegate_.retried();
+ }
+ }
+
+ public Ice.Instrumentation.RemoteObserver getRemoteObserver(Ice.ConnectionInfo con, Ice.Endpoint endpt,
+ int requestId, int size)
+ {
+ Ice.Instrumentation.RemoteObserver del = null;
+ if(delegate_ != null)
+ {
+ del = delegate_.getRemoteObserver(con, endpt, requestId, size);
+ }
+ return getObserver<RemoteMetrics, RemoteObserverI,
+ Ice.Instrumentation.RemoteObserver>("Remote",
+ new RemoteInvocationHelper(con, endpt, requestId, size),
+ del);
+ }
+
+ public Ice.Instrumentation.CollocatedObserver getCollocatedObserver(Ice.ObjectAdapter adapter,
+ int requestId,
+ int size)
+ {
+ Ice.Instrumentation.CollocatedObserver del = null;
+ if(delegate_ != null)
+ {
+ del = delegate_.getCollocatedObserver(adapter, requestId, size);
+ }
+ return getObserver<CollocatedMetrics, CollocatedObserverI,
+ Ice.Instrumentation.CollocatedObserver>("Collocated",
+ new CollocatedInvocationHelper(adapter, requestId, size),
+ del);
+ }
+
+ private void incrementRetry(InvocationMetrics v)
+ {
+ ++v.retry;
+ }
+
+ private void userException(InvocationMetrics v)
+ {
+ ++v.userException;
+ }
+ }
+
+ public class ThreadObserverI : ObserverWithDelegate<ThreadMetrics, Ice.Instrumentation.ThreadObserver>,
+ Ice.Instrumentation.ThreadObserver
+ {
+ public void stateChanged(Ice.Instrumentation.ThreadState oldState, Ice.Instrumentation.ThreadState newState)
+ {
+ _oldState = oldState;
+ _newState = newState;
+ forEach(threadStateUpdate);
+ if(delegate_ != null)
+ {
+ delegate_.stateChanged(oldState, newState);
+ }
+ }
+
+ private void threadStateUpdate(ThreadMetrics v)
+ {
+ switch(_oldState)
+ {
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForIO:
+ --v.inUseForIO;
+ break;
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForUser:
+ --v.inUseForUser;
+ break;
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForOther:
+ --v.inUseForOther;
+ break;
+ default:
+ break;
+ }
+ switch(_newState)
+ {
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForIO:
+ ++v.inUseForIO;
+ break;
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForUser:
+ ++v.inUseForUser;
+ break;
+ case Ice.Instrumentation.ThreadState.ThreadStateInUseForOther:
+ ++v.inUseForOther;
+ break;
+ default:
+ break;
+ }
+ }
+
+ private Ice.Instrumentation.ThreadState _oldState;
+ private Ice.Instrumentation.ThreadState _newState;
+ };
+
+ public class CommunicatorObserverI : Ice.Instrumentation.CommunicatorObserver
+ {
+ public CommunicatorObserverI(Ice.InitializationData initData)
+ {
+ _metrics = new MetricsAdminI(initData.properties, initData.logger);
+ _delegate = initData.observer;
+ _connections = new ObserverFactoryWithDelegate<ConnectionMetrics, ConnectionObserverI,
+ Ice.Instrumentation.ConnectionObserver>(_metrics, "Connection");
+ _dispatch = new ObserverFactoryWithDelegate<DispatchMetrics, DispatchObserverI,
+ Ice.Instrumentation.DispatchObserver>(_metrics, "Dispatch");
+ _invocations = new ObserverFactoryWithDelegate<InvocationMetrics, InvocationObserverI,
+ Ice.Instrumentation.InvocationObserver>(_metrics, "Invocation");
+ _threads = new ObserverFactoryWithDelegate<ThreadMetrics, ThreadObserverI,
+ Ice.Instrumentation.ThreadObserver>(_metrics, "Thread");
+ _connects = new ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI,
+ Ice.Instrumentation.Observer>(_metrics, "ConnectionEstablishment");
+ _endpointLookups = new ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI,
+ Ice.Instrumentation.Observer>(_metrics, "EndpointLookup");
+
+ try
+ {
+ Type cl = typeof(InvocationMetrics);
+ _invocations.registerSubMap<RemoteMetrics>("Remote", cl.GetField("remotes"));
+ _invocations.registerSubMap<CollocatedMetrics>("Collocated", cl.GetField("collocated"));
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ public Ice.Instrumentation.Observer getConnectionEstablishmentObserver(Ice.Endpoint endpt, string connector)
+ {
+ if(_connects.isEnabled())
+ {
+ try
+ {
+ Ice.Instrumentation.Observer del = null;
+ if(_delegate != null)
+ {
+ del = _delegate.getConnectionEstablishmentObserver(endpt, connector);
+ }
+ return _connects.getObserver(new EndpointHelper(endpt, connector), del);
+ }
+ catch(Exception ex)
+ {
+ _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + ex);
+ }
+ }
+ return null;
+ }
+
+ public Ice.Instrumentation.Observer getEndpointLookupObserver(Ice.Endpoint endpt)
+ {
+ if(_endpointLookups.isEnabled())
+ {
+ try
+ {
+ Ice.Instrumentation.Observer del = null;
+ if(_delegate != null)
+ {
+ del = _delegate.getEndpointLookupObserver(endpt);
+ }
+ return _endpointLookups.getObserver(new EndpointHelper(endpt), del);
+ }
+ catch(Exception ex)
+ {
+ _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + ex);
+ }
+ }
+ return null;
+ }
+
+ public Ice.Instrumentation.ConnectionObserver getConnectionObserver(Ice.ConnectionInfo c,
+ Ice.Endpoint e,
+ Ice.Instrumentation.ConnectionState s,
+ Ice.Instrumentation.ConnectionObserver obsv)
+ {
+ if(_connections.isEnabled())
+ {
+ try
+ {
+ Ice.Instrumentation.ConnectionObserver del = null;
+ ConnectionObserverI o = obsv is ConnectionObserverI ? (ConnectionObserverI)obsv : null;
+ if(_delegate != null)
+ {
+ del = _delegate.getConnectionObserver(c, e, s, o != null ? o.getDelegate() : obsv);
+ }
+ return _connections.getObserver(new ConnectionHelper(c, e, s), obsv, del);
+ }
+ catch(Exception ex)
+ {
+ _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + ex);
+ }
+ }
+ return null;
+ }
+
+ public Ice.Instrumentation.ThreadObserver getThreadObserver(string parent, string id,
+ Ice.Instrumentation.ThreadState s,
+ Ice.Instrumentation.ThreadObserver obsv)
+ {
+ if(_threads.isEnabled())
+ {
+ try
+ {
+ Ice.Instrumentation.ThreadObserver del = null;
+ ThreadObserverI o = obsv is ThreadObserverI ? (ThreadObserverI)obsv : null;
+ if(_delegate != null)
+ {
+ del = _delegate.getThreadObserver(parent, id, s, o != null ? o.getDelegate() : obsv);
+ }
+ return _threads.getObserver(new ThreadHelper(parent, id, s), obsv, del);
+ }
+ catch(Exception ex)
+ {
+ _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + ex);
+ }
+ }
+ return null;
+ }
+
+ public Ice.Instrumentation.InvocationObserver getInvocationObserver(Ice.ObjectPrx prx, string operation,
+ Dictionary<string, string> ctx)
+ {
+ if(_invocations.isEnabled())
+ {
+ try
+ {
+ Ice.Instrumentation.InvocationObserver del = null;
+ if(_delegate != null)
+ {
+ del = _delegate.getInvocationObserver(prx, operation, ctx);
+ }
+ return _invocations.getObserver(new InvocationHelper(prx, operation, ctx), del);
+ }
+ catch(Exception ex)
+ {
+ _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + ex);
+ }
+ }
+ return null;
+ }
+
+ public Ice.Instrumentation.DispatchObserver getDispatchObserver(Ice.Current c, int size)
+ {
+ if(_dispatch.isEnabled())
+ {
+ try
+ {
+ Ice.Instrumentation.DispatchObserver del = null;
+ if(_delegate != null)
+ {
+ del = _delegate.getDispatchObserver(c, size);
+ }
+ return _dispatch.getObserver(new DispatchHelper(c, size), del);
+ }
+ catch(Exception ex)
+ {
+ _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + ex);
+ }
+ }
+ return null;
+ }
+
+ public void setObserverUpdater(Ice.Instrumentation.ObserverUpdater updater)
+ {
+ if(updater == null)
+ {
+ _connections.setUpdater(null);
+ _threads.setUpdater(null);
+ }
+ else
+ {
+ _connections.setUpdater(updater.updateConnectionObservers);
+ _threads.setUpdater(updater.updateThreadObservers);
+ }
+ if(_delegate != null)
+ {
+ _delegate.setObserverUpdater(updater);
+ }
+ }
+
+ public IceInternal.MetricsAdminI getFacet()
+ {
+ return _metrics;
+ }
+
+ readonly private IceInternal.MetricsAdminI _metrics;
+ readonly private Ice.Instrumentation.CommunicatorObserver _delegate;
+ readonly private ObserverFactoryWithDelegate<ConnectionMetrics, ConnectionObserverI,
+ Ice.Instrumentation.ConnectionObserver> _connections;
+ readonly private ObserverFactoryWithDelegate<DispatchMetrics, DispatchObserverI,
+ Ice.Instrumentation.DispatchObserver> _dispatch;
+ readonly private ObserverFactoryWithDelegate<InvocationMetrics, InvocationObserverI,
+ Ice.Instrumentation.InvocationObserver> _invocations;
+ readonly private ObserverFactoryWithDelegate<ThreadMetrics, ThreadObserverI,
+ Ice.Instrumentation.ThreadObserver> _threads;
+ readonly private ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI,
+ Ice.Instrumentation.Observer> _connects;
+ readonly private ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI,
+ Ice.Instrumentation.Observer> _endpointLookups;
+ }
+} \ No newline at end of file
diff --git a/csharp/src/Ice/LocatorInfo.cs b/csharp/src/Ice/LocatorInfo.cs
new file mode 100644
index 00000000000..1b3960df6d1
--- /dev/null
+++ b/csharp/src/Ice/LocatorInfo.cs
@@ -0,0 +1,1009 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+
+namespace IceInternal
+{
+ public sealed class LocatorInfo
+ {
+ public interface GetEndpointsCallback
+ {
+ void setEndpoints(EndpointI[] endpoints, bool cached);
+ void setException(Ice.LocalException ex);
+ }
+
+ private class RequestCallback
+ {
+ public void
+ response(LocatorInfo locatorInfo, Ice.ObjectPrx proxy)
+ {
+ EndpointI[] endpoints = null;
+ if(proxy != null)
+ {
+ Reference r = ((Ice.ObjectPrxHelperBase)proxy).reference__();
+ if(_ref.isWellKnown() && !Protocol.isSupported(_ref.getEncoding(), r.getEncoding()))
+ {
+ //
+ // If a well-known proxy and the returned
+ // proxy encoding isn't supported, we're done:
+ // there's no compatible endpoint we can use.
+ //
+ }
+ else if(!r.isIndirect())
+ {
+ endpoints = r.getEndpoints();
+ }
+ else if(_ref.isWellKnown() && !r.isWellKnown())
+ {
+ //
+ // We're resolving the endpoints of a well-known object and the proxy returned
+ // by the locator is an indirect proxy. We now need to resolve the endpoints
+ // of this indirect proxy.
+ //
+ locatorInfo.getEndpoints(r, _ref, _ttl, _callback);
+ return;
+ }
+ }
+
+ if(_ref.getInstance().traceLevels().location >= 1)
+ {
+ locatorInfo.getEndpointsTrace(_ref, endpoints, false);
+ }
+ if(_callback != null)
+ {
+ _callback.setEndpoints(endpoints == null ? new EndpointI[0] : endpoints, false);
+ }
+ }
+
+ public void
+ exception(LocatorInfo locatorInfo, Ice.Exception exc)
+ {
+ try
+ {
+ locatorInfo.getEndpointsException(_ref, exc); // This throws.
+ }
+ catch(Ice.LocalException ex)
+ {
+ if(_callback != null)
+ {
+ _callback.setException(ex);
+ }
+ }
+ }
+
+ public
+ RequestCallback(Reference @ref, int ttl, GetEndpointsCallback cb)
+ {
+ _ref = @ref;
+ _ttl = ttl;
+ _callback = cb;
+ }
+
+ readonly Reference _ref;
+ readonly int _ttl;
+ readonly GetEndpointsCallback _callback;
+ }
+
+ private abstract class Request
+ {
+ public void
+ addCallback(Reference @ref, Reference wellKnownRef, int ttl, GetEndpointsCallback cb)
+ {
+ lock(this)
+ {
+ RequestCallback callback = new RequestCallback(@ref, ttl, cb);
+ if(_response)
+ {
+ callback.response(_locatorInfo, _proxy);
+ }
+ else if(_exception != null)
+ {
+ callback.exception(_locatorInfo, _exception);
+ }
+ else
+ {
+ _callbacks.Add(callback);
+ if(wellKnownRef != null)
+ {
+ // This request is to resolve the endpoints of a cached well-known object ref
+ _wellKnownRefs.Add(wellKnownRef);
+ }
+ if(!_sent)
+ {
+ _sent = true;
+ send();
+ }
+ }
+ }
+ }
+
+ public EndpointI[]
+ getEndpoints(Reference @ref, Reference wellKnownRef, int ttl, out bool cached)
+ {
+ lock(this)
+ {
+ if(!_response || _exception == null)
+ {
+ if(wellKnownRef != null)
+ {
+ // This request is to resolve the endpoints of a cached well-known object ref
+ _wellKnownRefs.Add(wellKnownRef);
+ }
+ if(!_sent)
+ {
+ _sent = true;
+ send();
+ }
+
+ while(!_response && _exception == null)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ }
+
+ if(_exception != null)
+ {
+ _locatorInfo.getEndpointsException(@ref, _exception); // This throws.
+ }
+
+ Debug.Assert(_response);
+ EndpointI[] endpoints = null;
+ if(_proxy != null)
+ {
+ Reference r = ((Ice.ObjectPrxHelperBase)_proxy).reference__();
+ if(!r.isIndirect())
+ {
+ endpoints = r.getEndpoints();
+ }
+ else if(@ref.isWellKnown() && !r.isWellKnown())
+ {
+ //
+ // We're resolving the endpoints of a well-known object and the proxy returned
+ // by the locator is an indirect proxy. We now need to resolve the endpoints
+ // of this indirect proxy.
+ //
+ return _locatorInfo.getEndpoints(r, @ref, ttl, out cached);
+ }
+ }
+
+ cached = false;
+ if(_ref.getInstance().traceLevels().location >= 1)
+ {
+ _locatorInfo.getEndpointsTrace(@ref, endpoints, false);
+ }
+ return endpoints == null ? new EndpointI[0] : endpoints;
+ }
+ }
+
+ public Request(LocatorInfo locatorInfo, Reference @ref)
+ {
+ _locatorInfo = locatorInfo;
+ _ref = @ref;
+ _sent = false;
+ _response = false;
+ }
+
+ public void
+ response(Ice.ObjectPrx proxy)
+ {
+ lock(this)
+ {
+ _locatorInfo.finishRequest(_ref, _wellKnownRefs, proxy, false);
+ _response = true;
+ _proxy = proxy;
+ foreach(RequestCallback callback in _callbacks)
+ {
+ callback.response(_locatorInfo, proxy);
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public void
+ exception(Ice.Exception ex)
+ {
+ lock(this)
+ {
+ _locatorInfo.finishRequest(_ref, _wellKnownRefs, null, ex is Ice.UserException);
+ _exception = ex;
+ foreach(RequestCallback callback in _callbacks)
+ {
+ callback.exception(_locatorInfo, ex);
+ }
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ protected abstract void send();
+
+ readonly protected LocatorInfo _locatorInfo;
+ readonly protected Reference _ref;
+
+ private List<RequestCallback> _callbacks = new List<RequestCallback>();
+ private List<Reference> _wellKnownRefs = new List<Reference>();
+ private bool _sent;
+ private bool _response;
+ private Ice.ObjectPrx _proxy;
+ private Ice.Exception _exception;
+ }
+
+ private class ObjectRequest : Request
+ {
+ public ObjectRequest(LocatorInfo locatorInfo, Reference @ref) : base(locatorInfo, @ref)
+ {
+ }
+
+ override protected void
+ send()
+ {
+ try
+ {
+ _locatorInfo.getLocator().begin_findObjectById(_ref.getIdentity()).whenCompleted(
+ this.response, this.exception);
+ }
+ catch(Ice.Exception ex)
+ {
+ exception(ex);
+ }
+ }
+ }
+
+ private class AdapterRequest : Request
+ {
+ public AdapterRequest(LocatorInfo locatorInfo, Reference @ref) : base(locatorInfo, @ref)
+ {
+ }
+
+ override protected void
+ send()
+ {
+ try
+ {
+ _locatorInfo.getLocator().begin_findAdapterById(_ref.getAdapterId()).whenCompleted(
+ this.response, this.exception);
+ }
+ catch(Ice.Exception ex)
+ {
+ exception(ex);
+ }
+ }
+ }
+
+ internal LocatorInfo(Ice.LocatorPrx locator, LocatorTable table, bool background)
+ {
+ _locator = locator;
+ _table = table;
+ _background = background;
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ _locatorRegistry = null;
+ _table.clear();
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(object.ReferenceEquals(this, obj))
+ {
+ return true;
+ }
+
+ LocatorInfo rhs = obj as LocatorInfo;
+ return rhs == null ? false : _locator.Equals(rhs._locator);
+ }
+
+ public override int GetHashCode()
+ {
+ return _locator.GetHashCode();
+ }
+
+ public Ice.LocatorPrx getLocator()
+ {
+ //
+ // No synchronization necessary, _locator is immutable.
+ //
+ return _locator;
+ }
+
+ public Ice.LocatorRegistryPrx getLocatorRegistry()
+ {
+ lock(this)
+ {
+ if(_locatorRegistry != null)
+ {
+ return _locatorRegistry;
+ }
+ }
+
+ //
+ // Do not make locator calls from within sync.
+ //
+ Ice.LocatorRegistryPrx locatorRegistry = _locator.getRegistry();
+ if(locatorRegistry == null)
+ {
+ return null;
+ }
+
+ lock(this)
+ {
+ //
+ // The locator registry can't be located. We use ordered
+ // endpoint selection in case the locator returned a proxy
+ // with some endpoints which are prefered to be tried first.
+ //
+ _locatorRegistry = (Ice.LocatorRegistryPrx)locatorRegistry.ice_locator(null).ice_endpointSelection(
+ Ice.EndpointSelectionType.Ordered);
+ return _locatorRegistry;
+ }
+ }
+
+ public EndpointI[]
+ getEndpoints(Reference @ref, int ttl, out bool cached)
+ {
+ return getEndpoints(@ref, null, ttl, out cached);
+ }
+
+ public EndpointI[]
+ getEndpoints(Reference @ref, Reference wellKnownRef, int ttl, out bool cached)
+ {
+ Debug.Assert(@ref.isIndirect());
+ EndpointI[] endpoints = null;
+ cached = false;
+ if(!@ref.isWellKnown())
+ {
+ endpoints = _table.getAdapterEndpoints(@ref.getAdapterId(), ttl, out cached);
+ if(!cached)
+ {
+ if(_background && endpoints != null)
+ {
+ getAdapterRequest(@ref).addCallback(@ref, wellKnownRef, ttl, null);
+ }
+ else
+ {
+ return getAdapterRequest(@ref).getEndpoints(@ref, wellKnownRef, ttl, out cached);
+ }
+ }
+ }
+ else
+ {
+ Reference r = _table.getObjectReference(@ref.getIdentity(), ttl, out cached);
+ if(!cached)
+ {
+ if(_background && r != null)
+ {
+ getObjectRequest(@ref).addCallback(@ref, null, ttl, null);
+ }
+ else
+ {
+ return getObjectRequest(@ref).getEndpoints(@ref, null, ttl, out cached);
+ }
+ }
+
+ if(!r.isIndirect())
+ {
+ endpoints = r.getEndpoints();
+ }
+ else if(!r.isWellKnown())
+ {
+ return getEndpoints(r, @ref, ttl, out cached);
+ }
+ }
+
+ Debug.Assert(endpoints != null);
+ cached = true;
+ if(@ref.getInstance().traceLevels().location >= 1)
+ {
+ getEndpointsTrace(@ref, endpoints, true);
+ }
+ return endpoints;
+ }
+
+ public void
+ getEndpoints(Reference @ref, int ttl, GetEndpointsCallback callback)
+ {
+ getEndpoints(@ref, null, ttl, callback);
+ }
+
+ public void
+ getEndpoints(Reference @ref, Reference wellKnownRef, int ttl, GetEndpointsCallback callback)
+ {
+ Debug.Assert(@ref.isIndirect());
+ EndpointI[] endpoints = null;
+ bool cached = false;
+ if(!@ref.isWellKnown())
+ {
+ endpoints = _table.getAdapterEndpoints(@ref.getAdapterId(), ttl, out cached);
+ if(!cached)
+ {
+ if(_background && endpoints != null)
+ {
+ getAdapterRequest(@ref).addCallback(@ref, wellKnownRef, ttl, null);
+ }
+ else
+ {
+ getAdapterRequest(@ref).addCallback(@ref, wellKnownRef, ttl, callback);
+ return;
+ }
+ }
+ }
+ else
+ {
+ Reference r = _table.getObjectReference(@ref.getIdentity(), ttl, out cached);
+ if(!cached)
+ {
+ if(_background && r != null)
+ {
+ getObjectRequest(@ref).addCallback(@ref, null, ttl, null);
+ }
+ else
+ {
+ getObjectRequest(@ref).addCallback(@ref, null, ttl, callback);
+ return;
+ }
+ }
+
+ if(!r.isIndirect())
+ {
+ endpoints = r.getEndpoints();
+ }
+ else if(!r.isWellKnown())
+ {
+ getEndpoints(r, @ref, ttl, callback);
+ return;
+ }
+ }
+
+ Debug.Assert(endpoints != null);
+ if(@ref.getInstance().traceLevels().location >= 1)
+ {
+ getEndpointsTrace(@ref, endpoints, true);
+ }
+ if(callback != null)
+ {
+ callback.setEndpoints(endpoints, true);
+ }
+ }
+
+ public void clearCache(Reference rf)
+ {
+ Debug.Assert(rf.isIndirect());
+ if(!rf.isWellKnown())
+ {
+ EndpointI[] endpoints = _table.removeAdapterEndpoints(rf.getAdapterId());
+
+ if(endpoints != null && rf.getInstance().traceLevels().location >= 2)
+ {
+ trace("removed endpoints from locator table\n", rf, endpoints);
+ }
+ }
+ else
+ {
+ Reference r = _table.removeObjectReference(rf.getIdentity());
+ if(r != null)
+ {
+ if(!r.isIndirect())
+ {
+ if(rf.getInstance().traceLevels().location >= 2)
+ {
+ trace("removed endpoints from locator table", rf, r.getEndpoints());
+ }
+ }
+ else if(!r.isWellKnown())
+ {
+ clearCache(r);
+ }
+ }
+ }
+ }
+
+ private void trace(string msg, Reference r, EndpointI[] endpoints)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append(msg + "\n");
+ if(r.getAdapterId().Length > 0)
+ {
+ s.Append("adapter = " + r.getAdapterId() + "\n");
+ }
+ else
+ {
+ s.Append("object = " + r.getInstance().identityToString(r.getIdentity()) + "\n");
+ }
+
+ s.Append("endpoints = ");
+ int sz = endpoints.Length;
+ for (int i = 0; i < sz; i++)
+ {
+ s.Append(endpoints[i].ToString());
+ if(i + 1 < sz)
+ {
+ s.Append(":");
+ }
+ }
+
+ r.getInstance().initializationData().logger.trace(r.getInstance().traceLevels().locationCat, s.ToString());
+ }
+
+ private void getEndpointsException(Reference @ref, System.Exception exc)
+ {
+ try
+ {
+ throw exc;
+ }
+ catch(Ice.AdapterNotFoundException ex)
+ {
+ Instance instance = @ref.getInstance();
+ if(instance.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("adapter not found\n");
+ s.Append("adapter = " + @ref.getAdapterId());
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
+ }
+
+ Ice.NotRegisteredException e = new Ice.NotRegisteredException(ex);
+ e.kindOfObject = "object adapter";
+ e.id = @ref.getAdapterId();
+ throw e;
+ }
+ catch(Ice.ObjectNotFoundException ex)
+ {
+ Instance instance = @ref.getInstance();
+ if(instance.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("object not found\n");
+ s.Append("object = " + instance.identityToString(@ref.getIdentity()));
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
+ }
+
+ Ice.NotRegisteredException e = new Ice.NotRegisteredException(ex);
+ e.kindOfObject = "object";
+ e.id = instance.identityToString(@ref.getIdentity());
+ throw e;
+ }
+ catch(Ice.NotRegisteredException)
+ {
+ throw;
+ }
+ catch(Ice.LocalException ex)
+ {
+ Instance instance = @ref.getInstance();
+ if(instance.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't contact the locator to retrieve adapter endpoints\n");
+ if(@ref.getAdapterId().Length > 0)
+ {
+ s.Append("adapter = " + @ref.getAdapterId() + "\n");
+ }
+ else
+ {
+ s.Append("object = " + instance.identityToString(@ref.getIdentity()) + "\n");
+ }
+ s.Append("reason = " + ex);
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
+ }
+ throw;
+ }
+ catch(System.Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ private void getEndpointsTrace(Reference @ref, EndpointI[] endpoints, bool cached)
+ {
+ if(endpoints != null && endpoints.Length > 0)
+ {
+ if(cached)
+ {
+ trace("found endpoints in locator table", @ref, endpoints);
+ }
+ else
+ {
+ trace("retrieved endpoints from locator, adding to locator table", @ref, endpoints);
+ }
+ }
+ else
+ {
+ Instance instance = @ref.getInstance();
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("no endpoints configured for ");
+ if(@ref.getAdapterId().Length > 0)
+ {
+ s.Append("adapter\n");
+ s.Append("adapter = " + @ref.getAdapterId());
+ }
+ else
+ {
+ s.Append("object\n");
+ s.Append("object = " + instance.identityToString(@ref.getIdentity()));
+ }
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
+ }
+ }
+
+ private Request
+ getAdapterRequest(Reference @ref)
+ {
+ if(@ref.getInstance().traceLevels().location >= 1)
+ {
+ Instance instance = @ref.getInstance();
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("searching for adapter by id\nadapter = ");
+ s.Append(@ref.getAdapterId());
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
+ }
+
+ lock(this)
+ {
+ Request request;
+ if(_adapterRequests.TryGetValue(@ref.getAdapterId(), out request))
+ {
+ return request;
+ }
+
+ request = new AdapterRequest(this, @ref);
+ _adapterRequests.Add(@ref.getAdapterId(), request);
+ return request;
+ }
+ }
+
+ private Request
+ getObjectRequest(Reference @ref)
+ {
+ if(@ref.getInstance().traceLevels().location >= 1)
+ {
+ Instance instance = @ref.getInstance();
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("searching for object by id\nobject = ");
+ s.Append(instance.identityToString(@ref.getIdentity()));
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
+ }
+
+ lock(this)
+ {
+ Request request;
+ if(_objectRequests.TryGetValue(@ref.getIdentity(), out request))
+ {
+ return request;
+ }
+
+ request = new ObjectRequest(this, @ref);
+ _objectRequests.Add(@ref.getIdentity(), request);
+ return request;
+ }
+ }
+
+ private void
+ finishRequest(Reference @ref, List<Reference> wellKnownRefs, Ice.ObjectPrx proxy, bool notRegistered)
+ {
+ Ice.ObjectPrxHelperBase @base = proxy as Ice.ObjectPrxHelperBase;
+ if(proxy == null || @base.reference__().isIndirect())
+ {
+ //
+ // Remove the cached references of well-known objects for which we tried
+ // to resolved the endpoints if these endpoints are empty.
+ //
+ foreach(Reference r in wellKnownRefs)
+ {
+ _table.removeObjectReference(r.getIdentity());
+ }
+ }
+
+ if(!@ref.isWellKnown())
+ {
+ if(proxy != null && !@base.reference__().isIndirect())
+ {
+ // Cache the adapter endpoints.
+ _table.addAdapterEndpoints(@ref.getAdapterId(), @base.reference__().getEndpoints());
+ }
+ else if(notRegistered) // If the adapter isn't registered anymore, remove it from the cache.
+ {
+ _table.removeAdapterEndpoints(@ref.getAdapterId());
+ }
+
+ lock(this)
+ {
+ Debug.Assert(_adapterRequests.ContainsKey(@ref.getAdapterId()));
+ _adapterRequests.Remove(@ref.getAdapterId());
+ }
+ }
+ else
+ {
+ if(proxy != null && !@base.reference__().isWellKnown())
+ {
+ // Cache the well-known object reference.
+ _table.addObjectReference(@ref.getIdentity(), @base.reference__());
+ }
+ else if(notRegistered) // If the well-known object isn't registered anymore, remove it from the cache.
+ {
+ _table.removeObjectReference(@ref.getIdentity());
+ }
+
+ lock(this)
+ {
+ Debug.Assert(_objectRequests.ContainsKey(@ref.getIdentity()));
+ _objectRequests.Remove(@ref.getIdentity());
+ }
+ }
+ }
+
+ private readonly Ice.LocatorPrx _locator;
+ private Ice.LocatorRegistryPrx _locatorRegistry;
+ private readonly LocatorTable _table;
+ private readonly bool _background;
+
+ private Dictionary<string, Request> _adapterRequests = new Dictionary<string, Request>();
+ private Dictionary<Ice.Identity, Request> _objectRequests = new Dictionary<Ice.Identity, Request>();
+ }
+
+ public sealed class LocatorManager
+ {
+ struct LocatorKey
+ {
+ public LocatorKey(Ice.LocatorPrx prx)
+ {
+ Reference r = ((Ice.ObjectPrxHelperBase)prx).reference__();
+ _id = r.getIdentity();
+ _encoding = r.getEncoding();
+ }
+
+ public override bool Equals(object o)
+ {
+ LocatorKey k = (LocatorKey)o;
+ if(!k._id.Equals(_id))
+ {
+ return false;
+ }
+ if(!k._encoding.Equals(_encoding))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int h = 5381;
+ IceInternal.HashUtil.hashAdd(ref h, _id);
+ IceInternal.HashUtil.hashAdd(ref h, _encoding);
+ return h;
+ }
+
+ private Ice.Identity _id;
+ private Ice.EncodingVersion _encoding;
+ };
+
+ internal LocatorManager(Ice.Properties properties)
+ {
+ _table = new Dictionary<Ice.LocatorPrx, LocatorInfo>();
+ _locatorTables = new Dictionary<LocatorKey, LocatorTable>();
+ _background = properties.getPropertyAsInt("Ice.BackgroundLocatorCacheUpdates") > 0;
+ }
+
+ internal void destroy()
+ {
+ lock(this)
+ {
+ foreach(LocatorInfo info in _table.Values)
+ {
+ info.destroy();
+ }
+ _table.Clear();
+ _locatorTables.Clear();
+ }
+ }
+
+ //
+ // Returns locator info for a given locator. Automatically creates
+ // the locator info if it doesn't exist yet.
+ //
+ public LocatorInfo get(Ice.LocatorPrx loc)
+ {
+ if(loc == null)
+ {
+ return null;
+ }
+
+ //
+ // The locator can't be located.
+ //
+ Ice.LocatorPrx locator = Ice.LocatorPrxHelper.uncheckedCast(loc.ice_locator(null));
+
+ //
+ // TODO: reap unused locator info objects?
+ //
+
+ lock(this)
+ {
+ LocatorInfo info = null;
+ if(!_table.TryGetValue(locator, out info))
+ {
+ //
+ // Rely on locator identity for the adapter table. We want to
+ // have only one table per locator (not one per locator
+ // proxy).
+ //
+ LocatorTable table = null;
+ LocatorKey key = new LocatorKey(locator);
+ if(!_locatorTables.TryGetValue(key, out table))
+ {
+ table = new LocatorTable();
+ _locatorTables[key] = table;
+ }
+
+ info = new LocatorInfo(locator, table, _background);
+ _table[locator] = info;
+ }
+
+ return info;
+ }
+ }
+
+ private Dictionary<Ice.LocatorPrx, LocatorInfo> _table;
+ private Dictionary<LocatorKey, LocatorTable> _locatorTables;
+ private readonly bool _background;
+ }
+
+ sealed class LocatorTable
+ {
+ internal LocatorTable()
+ {
+ _adapterEndpointsTable = new Dictionary<string, EndpointTableEntry>();
+ _objectTable = new Dictionary<Ice.Identity, ReferenceTableEntry>();
+ }
+
+ internal void clear()
+ {
+ lock(this)
+ {
+ _adapterEndpointsTable.Clear();
+ _objectTable.Clear();
+ }
+ }
+
+ internal IceInternal.EndpointI[] getAdapterEndpoints(string adapter, int ttl, out bool cached)
+ {
+ if(ttl == 0) // Locator cache disabled.
+ {
+ cached = false;
+ return null;
+ }
+
+ lock(this)
+ {
+ EndpointTableEntry entry = null;
+ if(_adapterEndpointsTable.TryGetValue(adapter, out entry))
+ {
+ cached = checkTTL(entry.time, ttl);
+ return entry.endpoints;
+
+ }
+ cached = false;
+ return null;
+ }
+ }
+
+ internal void addAdapterEndpoints(string adapter, IceInternal.EndpointI[] endpoints)
+ {
+ lock(this)
+ {
+ _adapterEndpointsTable[adapter] =
+ new EndpointTableEntry(Time.currentMonotonicTimeMillis(), endpoints);
+ }
+ }
+
+ internal IceInternal.EndpointI[] removeAdapterEndpoints(string adapter)
+ {
+ lock(this)
+ {
+ EndpointTableEntry entry = null;
+ if(_adapterEndpointsTable.TryGetValue(adapter, out entry))
+ {
+ _adapterEndpointsTable.Remove(adapter);
+ return entry.endpoints;
+ }
+ return null;
+ }
+ }
+
+ internal Reference getObjectReference(Ice.Identity id, int ttl, out bool cached)
+ {
+ if(ttl == 0) // Locator cache disabled.
+ {
+ cached = false;
+ return null;
+ }
+
+ lock(this)
+ {
+ ReferenceTableEntry entry = null;
+ if(_objectTable.TryGetValue(id, out entry))
+ {
+ cached = checkTTL(entry.time, ttl);
+ return entry.reference;
+ }
+ cached = false;
+ return null;
+ }
+ }
+
+ internal void addObjectReference(Ice.Identity id, Reference reference)
+ {
+ lock(this)
+ {
+ _objectTable[id] = new ReferenceTableEntry(Time.currentMonotonicTimeMillis(), reference);
+ }
+ }
+
+ internal Reference removeObjectReference(Ice.Identity id)
+ {
+ lock(this)
+ {
+ ReferenceTableEntry entry = null;
+ if(_objectTable.TryGetValue(id, out entry))
+ {
+ _objectTable.Remove(id);
+ return entry.reference;
+ }
+ return null;
+ }
+ }
+
+ private bool checkTTL(long time, int ttl)
+ {
+ Debug.Assert(ttl != 0);
+ if(ttl < 0) // TTL = infinite
+ {
+ return true;
+ }
+ else
+ {
+ return Time.currentMonotonicTimeMillis() - time <= ((long)ttl * 1000);
+ }
+ }
+
+ sealed private class EndpointTableEntry
+ {
+ public EndpointTableEntry(long time, IceInternal.EndpointI[] endpoints)
+ {
+ this.time = time;
+ this.endpoints = endpoints;
+ }
+
+ public long time;
+ public IceInternal.EndpointI[] endpoints;
+ }
+
+ sealed private class ReferenceTableEntry
+ {
+ public ReferenceTableEntry(long time, Reference reference)
+ {
+ this.time = time;
+ this.reference = reference;
+ }
+
+ public long time;
+ public Reference reference;
+ }
+
+ private Dictionary<string, EndpointTableEntry> _adapterEndpointsTable;
+ private Dictionary<Ice.Identity, ReferenceTableEntry> _objectTable;
+ }
+
+}
diff --git a/csharp/src/Ice/LoggerAdminI.cs b/csharp/src/Ice/LoggerAdminI.cs
new file mode 100644
index 00000000000..e32b098c634
--- /dev/null
+++ b/csharp/src/Ice/LoggerAdminI.cs
@@ -0,0 +1,483 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+
+namespace IceInternal
+{
+sealed class LoggerAdminI : Ice.LoggerAdminDisp_
+{
+ public override void
+ attachRemoteLogger(Ice.RemoteLoggerPrx prx, Ice.LogMessageType[] messageTypes, string[] categories,
+ int messageMax, Ice.Current current)
+ {
+ if(prx == null)
+ {
+ return; // can't send this null RemoteLogger anything!
+ }
+
+ Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(prx.ice_twoway());
+
+ Filters filters = new Filters(messageTypes, categories);
+ LinkedList<Ice.LogMessage> initLogMessages = null;
+
+ lock(this)
+ {
+ if(_sendLogCommunicator == null)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.ObjectNotExistException();
+ }
+
+ _sendLogCommunicator =
+ createSendLogCommunicator(current.adapter.getCommunicator(), _logger.getLocalLogger());
+ }
+
+ Ice.Identity remoteLoggerId = remoteLogger.ice_getIdentity();
+
+ if(_remoteLoggerMap.ContainsKey(remoteLoggerId))
+ {
+ if(_traceLevel > 0)
+ {
+ _logger.trace(_traceCategory, "rejecting `" + remoteLogger.ToString() +
+ "' with RemoteLoggerAlreadyAttachedException");
+ }
+
+ throw new Ice.RemoteLoggerAlreadyAttachedException();
+ }
+
+ _remoteLoggerMap.Add(remoteLoggerId,
+ new RemoteLoggerData(changeCommunicator(remoteLogger, _sendLogCommunicator), filters));
+
+ if(messageMax != 0)
+ {
+ initLogMessages = new LinkedList<Ice.LogMessage>(_queue); // copy
+ }
+ else
+ {
+ initLogMessages = new LinkedList<Ice.LogMessage>();
+ }
+ }
+
+ if(_traceLevel > 0)
+ {
+ _logger.trace(_traceCategory, "attached `" + remoteLogger.ToString() + "'");
+ }
+
+ if(initLogMessages.Count > 0)
+ {
+ filterLogMessages(initLogMessages, filters.messageTypes, filters.traceCategories, messageMax);
+ }
+
+ try
+ {
+ remoteLogger.begin_init(_logger.getPrefix(), initLogMessages.ToArray(), initCompleted, null);
+ }
+ catch(Ice.LocalException ex)
+ {
+ deadRemoteLogger(remoteLogger, _logger, ex, "init");
+ throw ex;
+ }
+ }
+
+ public override bool
+ detachRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Current current)
+ {
+ if(remoteLogger == null)
+ {
+ return false;
+ }
+
+ //
+ // No need to convert the proxy as we only use its identity
+ //
+ bool found = removeRemoteLogger(remoteLogger);
+
+ if(_traceLevel > 0)
+ {
+ if(found)
+ {
+ _logger.trace(_traceCategory, "detached `" + remoteLogger.ToString() + "'");
+ }
+ else
+ {
+ _logger.trace(_traceCategory, "cannot detach `" + remoteLogger.ToString() + "': not found");
+ }
+ }
+
+ return found;
+ }
+
+ public override Ice.LogMessage[]
+ getLog(Ice.LogMessageType[] messageTypes, string[] categories, int messageMax, out string prefix,
+ Ice.Current current)
+ {
+ LinkedList<Ice.LogMessage> logMessages = null;
+ lock(this)
+ {
+ if(messageMax != 0)
+ {
+ logMessages = new LinkedList<Ice.LogMessage>(_queue);
+ }
+ else
+ {
+ logMessages = new LinkedList<Ice.LogMessage>();
+ }
+ }
+
+ prefix = _logger.getPrefix();
+
+ if(logMessages.Count > 0)
+ {
+ Filters filters = new Filters(messageTypes, categories);
+ filterLogMessages(logMessages, filters.messageTypes, filters.traceCategories, messageMax);
+ }
+ return logMessages.ToArray();
+ }
+
+
+ internal LoggerAdminI(Ice.Properties props, LoggerAdminLoggerI logger)
+ {
+ _maxLogCount = props.getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepLogs", 100);
+ _maxTraceCount = props.getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepTraces", 100);
+ _traceLevel = props.getPropertyAsInt("Ice.Trace.Admin.Logger");
+ _logger = logger;
+ }
+
+ internal void destroy()
+ {
+ Ice.Communicator sendLogCommunicator = null;
+
+ lock(this)
+ {
+ if(!_destroyed)
+ {
+ _destroyed = true;
+ sendLogCommunicator = _sendLogCommunicator;
+ _sendLogCommunicator = null;
+ }
+ }
+
+ //
+ // Destroy outside lock to avoid deadlock when there are outstanding two-way log calls sent to
+ // remote logggers
+ //
+ if(sendLogCommunicator != null)
+ {
+ sendLogCommunicator.destroy();
+ }
+ }
+
+ internal List<Ice.RemoteLoggerPrx> log(Ice.LogMessage logMessage)
+ {
+ lock(this)
+ {
+ List<Ice.RemoteLoggerPrx> remoteLoggers = null;
+
+ //
+ // Put message in _queue
+ //
+ if((logMessage.type != Ice.LogMessageType.TraceMessage && _maxLogCount > 0) ||
+ (logMessage.type == Ice.LogMessageType.TraceMessage && _maxTraceCount > 0))
+ {
+ _queue.AddLast(logMessage);
+
+ if(logMessage.type != Ice.LogMessageType.TraceMessage)
+ {
+ Debug.Assert(_maxLogCount > 0);
+ if(_logCount == _maxLogCount)
+ {
+ //
+ // Need to remove the oldest log from the queue
+ //
+ Debug.Assert(_oldestLog != null);
+ var next = _oldestLog.Next;
+ _queue.Remove(_oldestLog);
+ _oldestLog = next;
+
+ while(_oldestLog != null && _oldestLog.Value.type == Ice.LogMessageType.TraceMessage)
+ {
+ _oldestLog = _oldestLog.Next;
+ }
+ Debug.Assert(_oldestLog != null); // remember: we just added a Log at the end
+ }
+ else
+ {
+ Debug.Assert(_logCount < _maxLogCount);
+ _logCount++;
+ if(_oldestLog == null)
+ {
+ _oldestLog = _queue.Last;
+ }
+ }
+ }
+ else
+ {
+ Debug.Assert(_maxTraceCount > 0);
+ if(_traceCount == _maxTraceCount)
+ {
+ //
+ // Need to remove the oldest trace from the queue
+ //
+ Debug.Assert(_oldestTrace != null);
+ var next = _oldestTrace.Next;
+ _queue.Remove(_oldestTrace);
+ _oldestTrace = next;
+
+ while(_oldestTrace != null && _oldestTrace.Value.type != Ice.LogMessageType.TraceMessage)
+ {
+ _oldestTrace = _oldestTrace.Next;
+ }
+ Debug.Assert(_oldestTrace != null); // remember: we just added a Log at the end
+ }
+ else
+ {
+ Debug.Assert(_traceCount < _maxTraceCount);
+ _traceCount++;
+ if(_oldestTrace == null)
+ {
+ _oldestTrace = _queue.Last;
+ }
+ }
+ }
+ }
+
+ //
+ // Queue updated, now find which remote loggers want this message
+ //
+ foreach(RemoteLoggerData p in _remoteLoggerMap.Values)
+ {
+ Filters filters = p.filters;
+
+ if(filters.messageTypes.Count == 0 || filters.messageTypes.Contains(logMessage.type))
+ {
+ if(logMessage.type != Ice.LogMessageType.TraceMessage || filters.traceCategories.Count == 0 ||
+ filters.traceCategories.Contains(logMessage.traceCategory))
+ {
+ if(remoteLoggers == null)
+ {
+ remoteLoggers = new List<Ice.RemoteLoggerPrx>();
+ }
+ remoteLoggers.Add(p.remoteLogger);
+ }
+ }
+ }
+
+ return remoteLoggers;
+ }
+ }
+
+ internal void deadRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Logger logger, Ice.LocalException ex,
+ string operation)
+ {
+ //
+ // No need to convert remoteLogger as we only use its identity
+ //
+ if(removeRemoteLogger(remoteLogger))
+ {
+ if(_traceLevel > 0)
+ {
+ logger.trace(_traceCategory, "detached `" + remoteLogger.ToString() + "' because "
+ + operation + " raised:\n" + ex.ToString());
+ }
+ }
+ }
+
+ internal int getTraceLevel()
+ {
+ return _traceLevel;
+ }
+
+ private bool removeRemoteLogger(Ice.RemoteLoggerPrx remoteLogger)
+ {
+ lock(this)
+ {
+ return _remoteLoggerMap.Remove(remoteLogger.ice_getIdentity());
+ }
+ }
+
+ private void initCompleted(Ice.AsyncResult r)
+ {
+ Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(r.getProxy());
+
+ try
+ {
+ remoteLogger.end_init(r);
+
+ if(_traceLevel > 1)
+ {
+ _logger.trace(_traceCategory, r.getOperation() + " on `" + remoteLogger.ToString()
+ + "' completed successfully");
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ deadRemoteLogger(remoteLogger, _logger, ex, r.getOperation());
+ }
+ }
+
+ private static void filterLogMessages(LinkedList<Ice.LogMessage> logMessages,
+ HashSet<Ice.LogMessageType> messageTypes,
+ HashSet<string> traceCategories, int messageMax)
+ {
+ Debug.Assert(logMessages.Count > 0 && messageMax != 0);
+
+ //
+ // Filter only if one of the 3 filters is set; messageMax < 0 means "give me all"
+ // that match the other filters, if any.
+ //
+ if(messageTypes.Count > 0 || traceCategories.Count > 0 || messageMax > 0)
+ {
+ int count = 0;
+ var p = logMessages.Last;
+ while(p != null)
+ {
+ bool keepIt = false;
+ Ice.LogMessage msg = p.Value;
+ if(messageTypes.Count == 0 || messageTypes.Contains(msg.type))
+ {
+ if(msg.type != Ice.LogMessageType.TraceMessage || traceCategories.Count == 0 ||
+ traceCategories.Contains(msg.traceCategory))
+ {
+ keepIt = true;
+ }
+ }
+
+ if(keepIt)
+ {
+ ++count;
+ if(messageMax > 0 && count >= messageMax)
+ {
+ // Remove all older messages
+ p = p.Previous;
+ while(p != null)
+ {
+ var previous = p.Previous;
+ logMessages.Remove(p);
+ p = previous;
+ }
+ break; // while
+ }
+ else
+ {
+ p = p.Previous;
+ }
+ }
+ else
+ {
+ var previous = p.Previous;
+ logMessages.Remove(p);
+ p = previous;
+ }
+ }
+ }
+ // else, don't need any filtering
+ }
+
+ //
+ // Change this proxy's communicator, while keeping its invocation timeout
+ //
+ private static Ice.RemoteLoggerPrx changeCommunicator(Ice.RemoteLoggerPrx prx, Ice.Communicator communicator)
+ {
+ if(prx == null)
+ {
+ return null;
+ }
+
+ Ice.ObjectPrx result = communicator.stringToProxy(prx.ToString());
+ return Ice.RemoteLoggerPrxHelper.uncheckedCast(result.ice_invocationTimeout(prx.ice_getInvocationTimeout()));
+ }
+
+ private static void copyProperties(string prefix, Ice.Properties from, Ice.Properties to)
+ {
+ foreach(var p in from.getPropertiesForPrefix(prefix))
+ {
+ to.setProperty(p.Key, p.Value);
+ }
+ }
+
+ private static Ice.Communicator createSendLogCommunicator(Ice.Communicator communicator, Ice.Logger logger)
+ {
+ Ice.InitializationData initData = new Ice.InitializationData();
+ initData.logger = logger;
+ initData.properties = Ice.Util.createProperties();
+
+ Ice.Properties mainProps = communicator.getProperties();
+
+ copyProperties("Ice.Default.Locator", mainProps, initData.properties);
+ copyProperties("Ice.Plugin.IceSSL", mainProps, initData.properties);
+ copyProperties("IceSSL.", mainProps, initData.properties);
+
+ string[] extraProps = mainProps.getPropertyAsList("Ice.Admin.Logger.Properties");
+
+ if(extraProps.Length > 0)
+ {
+ for(int i = 0; i < extraProps.Length; ++i)
+ {
+ string p = extraProps[i];
+ if(!p.StartsWith("--"))
+ {
+ extraProps[i] = "--" + p;
+ }
+ }
+ initData.properties.parseCommandLineOptions("", extraProps);
+ }
+ return Ice.Util.initialize(initData);
+ }
+
+
+ private readonly LinkedList<Ice.LogMessage> _queue = new LinkedList<Ice.LogMessage>();
+ private int _logCount = 0; // non-trace messages
+ private readonly int _maxLogCount;
+ private int _traceCount = 0;
+ private readonly int _maxTraceCount;
+ private readonly int _traceLevel;
+
+ private LinkedListNode<Ice.LogMessage> _oldestTrace = null;
+ private LinkedListNode<Ice.LogMessage> _oldestLog = null;
+
+ private class Filters
+ {
+ internal Filters(Ice.LogMessageType[] m, string[] c)
+ {
+ messageTypes = new HashSet<Ice.LogMessageType>(m);
+ traceCategories = new HashSet<string>(c);
+ }
+
+ internal readonly HashSet<Ice.LogMessageType> messageTypes;
+ internal readonly HashSet<string> traceCategories;
+ }
+
+ private class RemoteLoggerData
+ {
+ internal RemoteLoggerData(Ice.RemoteLoggerPrx prx, Filters f)
+ {
+ remoteLogger = prx;
+ filters = f;
+ }
+
+ internal readonly Ice.RemoteLoggerPrx remoteLogger;
+ internal readonly Filters filters;
+ }
+
+ private readonly Dictionary<Ice.Identity, RemoteLoggerData> _remoteLoggerMap
+ = new Dictionary<Ice.Identity, RemoteLoggerData>();
+
+ private readonly LoggerAdminLoggerI _logger;
+
+ private Ice.Communicator _sendLogCommunicator = null;
+ private bool _destroyed = false;
+ static private readonly string _traceCategory = "Admin.Logger";
+}
+
+}
diff --git a/csharp/src/Ice/LoggerAdminLoggerI.cs b/csharp/src/Ice/LoggerAdminLoggerI.cs
new file mode 100644
index 00000000000..67647f33dc1
--- /dev/null
+++ b/csharp/src/Ice/LoggerAdminLoggerI.cs
@@ -0,0 +1,241 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+
+namespace IceInternal
+{
+
+interface LoggerAdminLogger : Ice.Logger
+{
+ Ice.Object getFacet();
+ void destroy();
+}
+
+sealed class LoggerAdminLoggerI : LoggerAdminLogger
+{
+ public void print(string message)
+ {
+ Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.PrintMessage, now(), "", message);
+ _localLogger.print(message);
+ log(logMessage);
+ }
+
+ public void trace(string category, string message)
+ {
+ Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.TraceMessage, now(), category, message);
+ _localLogger.trace(category, message);
+ log(logMessage);
+ }
+
+ public void warning(string message)
+ {
+ Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.WarningMessage, now(), "", message);
+ _localLogger.warning(message);
+ log(logMessage);
+ }
+
+ public void error(string message)
+ {
+ Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.ErrorMessage, now(), "", message);
+ _localLogger.error(message);
+ log(logMessage);
+ }
+
+ public string getPrefix()
+ {
+ return _localLogger.getPrefix();
+ }
+
+ public Ice.Logger cloneWithPrefix(string prefix)
+ {
+ return _localLogger.cloneWithPrefix(prefix);
+ }
+
+ public Ice.Object getFacet()
+ {
+ return _loggerAdmin;
+ }
+
+ public void destroy()
+ {
+ Thread thread = null;
+ lock(this)
+ {
+ if(_sendLogThread != null)
+ {
+ thread = _sendLogThread;
+ _sendLogThread = null;
+ _destroyed = true;
+ Monitor.PulseAll(this);
+ }
+ }
+
+ if(thread != null)
+ {
+ thread.Join();
+ }
+
+ _loggerAdmin.destroy();
+ }
+
+ internal LoggerAdminLoggerI(Ice.Properties props, Ice.Logger localLogger)
+ {
+ LoggerAdminLoggerI wrapper = localLogger as LoggerAdminLoggerI;
+
+ if(wrapper != null)
+ {
+ _localLogger = wrapper.getLocalLogger();
+ }
+ else
+ {
+ _localLogger = localLogger;
+ }
+
+ _loggerAdmin = new LoggerAdminI(props, this);
+ }
+
+ internal Ice.Logger getLocalLogger()
+ {
+ return _localLogger;
+ }
+
+ internal void log(Ice.LogMessage logMessage)
+ {
+ List<Ice.RemoteLoggerPrx> remoteLoggers = _loggerAdmin.log(logMessage);
+
+ if(remoteLoggers != null)
+ {
+ Debug.Assert(remoteLoggers.Count > 0);
+
+ lock(this)
+ {
+ if(_sendLogThread == null)
+ {
+ _sendLogThread = new Thread(new ThreadStart(run));
+ _sendLogThread.Name = "Ice.SendLogThread";
+ _sendLogThread.IsBackground = true;
+ _sendLogThread.Start();
+ }
+
+ _jobQueue.Enqueue(new Job(remoteLoggers, logMessage));
+ Monitor.PulseAll(this);
+ }
+ }
+ }
+
+ private void run()
+ {
+ if(_loggerAdmin.getTraceLevel() > 1)
+ {
+ _localLogger.trace(_traceCategory, "send log thread started");
+ }
+
+ for(;;)
+ {
+ Job job = null;
+ lock(this)
+ {
+ while(!_destroyed && _jobQueue.Count == 0)
+ {
+ Monitor.Wait(this);
+ }
+
+ if(_destroyed)
+ {
+ break; // for(;;)
+ }
+
+ Debug.Assert(_jobQueue.Count > 0);
+ job = _jobQueue.Dequeue();
+ }
+
+ foreach(var p in job.remoteLoggers)
+ {
+ if(_loggerAdmin.getTraceLevel() > 1)
+ {
+ _localLogger.trace(_traceCategory, "sending log message to `" + p.ToString() + "'");
+ }
+
+ try
+ {
+ //
+ // p is a proxy associated with the _sendLogCommunicator
+ //
+ p.begin_log(job.logMessage, logCompleted, null);
+ }
+ catch(Ice.LocalException ex)
+ {
+ _loggerAdmin.deadRemoteLogger(p, _localLogger, ex, "log");
+ }
+ }
+ }
+
+ if(_loggerAdmin.getTraceLevel() > 1)
+ {
+ _localLogger.trace(_traceCategory, "send log thread completed");
+ }
+ }
+
+ private void logCompleted(Ice.AsyncResult r)
+ {
+ Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(r.getProxy());
+
+ try
+ {
+ remoteLogger.end_log(r);
+
+ if(_loggerAdmin.getTraceLevel() > 1)
+ {
+ _localLogger.trace(_traceCategory, r.getOperation() + " on `" + remoteLogger.ToString()
+ + "' completed successfully");
+ }
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ // expected if there are outstanding calls during communicator destruction
+ }
+ catch(Ice.LocalException ex)
+ {
+ _loggerAdmin.deadRemoteLogger(remoteLogger, _localLogger, ex, r.getOperation());
+ }
+ }
+
+ static private long now()
+ {
+ TimeSpan t = DateTime.UtcNow - _unixEpoch;
+ return Convert.ToInt64(t.TotalMilliseconds * 1000);
+ }
+
+ private class Job
+ {
+ internal Job(List<Ice.RemoteLoggerPrx> r, Ice.LogMessage l)
+ {
+ remoteLoggers = r;
+ logMessage = l;
+ }
+
+ internal readonly List<Ice.RemoteLoggerPrx> remoteLoggers;
+ internal readonly Ice.LogMessage logMessage;
+ }
+
+ private readonly Ice.Logger _localLogger;
+ private readonly LoggerAdminI _loggerAdmin;
+ private bool _destroyed = false;
+ private Thread _sendLogThread;
+ private readonly Queue<Job> _jobQueue = new Queue<Job>();
+
+ static private readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ static private readonly string _traceCategory = "Admin.Logger";
+}
+
+}
diff --git a/csharp/src/Ice/LoggerI.cs b/csharp/src/Ice/LoggerI.cs
new file mode 100644
index 00000000000..f0e59e0eadb
--- /dev/null
+++ b/csharp/src/Ice/LoggerI.cs
@@ -0,0 +1,264 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#define TRACE
+
+namespace Ice
+{
+ using System.Diagnostics;
+ using System.Globalization;
+#if !SILVERLIGHT && !UNITY
+ using System.IO;
+#endif
+
+ public abstract class LoggerI : Logger
+ {
+ public LoggerI(string prefix)
+ {
+ _prefix = prefix;
+
+ if(prefix.Length > 0)
+ {
+ _formattedPrefix = prefix + ": ";
+ }
+
+ _date = "d";
+ _time = "HH:mm:ss:fff";
+ }
+
+ public void print(string message)
+ {
+ lock(_globalMutex)
+ {
+ write(message);
+ }
+ }
+
+ public virtual void trace(string category, string message)
+ {
+ string s = format("--", category, message);
+ lock(_globalMutex)
+ {
+ write(s);
+ }
+ }
+
+ public virtual void warning(string message)
+ {
+ string s = format("-!", "warning", message);
+ lock(_globalMutex)
+ {
+ write(s);
+ }
+ }
+
+ public virtual void error(string message)
+ {
+ string s = format("!!", "error", message);
+ lock(_globalMutex)
+ {
+ write(s);
+ }
+ }
+
+ public string getPrefix()
+ {
+ return _prefix;
+ }
+
+ private string format(string prefix, string category, string message)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder(prefix);
+ s.Append(' ');
+ s.Append(System.DateTime.Now.ToString(_date, CultureInfo.CurrentCulture));
+ s.Append(' ');
+ s.Append(System.DateTime.Now.ToString(_time, CultureInfo.CurrentCulture));
+ s.Append(' ');
+ s.Append(_formattedPrefix);
+ s.Append(category);
+ s.Append(": ");
+ s.Append(message);
+ s.Replace("\n", "\n ");
+ return s.ToString();
+ }
+
+ public abstract Logger cloneWithPrefix(string prefix);
+
+ protected abstract void write(string message);
+
+ internal string _prefix = "";
+ internal string _formattedPrefix = "";
+ internal string _date = null;
+ internal string _time = null;
+
+ internal static object _globalMutex = new object();
+ }
+
+ public sealed class ConsoleLoggerI : LoggerI
+ {
+ public ConsoleLoggerI(string prefix)
+ : base(prefix)
+ {
+ _date = "d";
+ _time = "HH:mm:ss:fff";
+ }
+
+ public override Logger cloneWithPrefix(string prefix)
+ {
+ return new ConsoleLoggerI(prefix);
+ }
+
+ protected override void write(string message)
+ {
+ System.Console.Error.WriteLine(message);
+ }
+ }
+
+#if !SILVERLIGHT && !UNITY
+ public sealed class FileLoggerI : LoggerI
+ {
+ public FileLoggerI(string prefix, string file) :
+ base(prefix)
+ {
+ _file = file;
+ _writer = new StreamWriter(new FileStream(file, FileMode.Append, FileAccess.Write, FileShare.None));
+ }
+
+ public override Logger cloneWithPrefix(string prefix)
+ {
+ return new FileLoggerI(prefix, _file);
+ }
+
+ protected override void write(string message)
+ {
+ _writer.WriteLine(message);
+ _writer.Flush();
+ }
+
+ private string _file;
+ private TextWriter _writer;
+ }
+
+
+# if !COMPACT
+ public class ConsoleListener : TraceListener
+ {
+ public ConsoleListener()
+ {
+ _date = "d";
+ _time = "HH:mm:ss:fff";
+ }
+
+ public override void TraceEvent(TraceEventCache cache, string source, TraceEventType type,
+ int id, string message)
+ {
+ System.Text.StringBuilder s;
+ if(type == TraceEventType.Error)
+ {
+ s = new System.Text.StringBuilder("!!");
+ }
+ else if(type == TraceEventType.Warning)
+ {
+ s = new System.Text.StringBuilder("-!");
+ }
+ else
+ {
+ s = new System.Text.StringBuilder("--");
+ }
+ s.Append(' ');
+ s.Append(System.DateTime.Now.ToString(_date, CultureInfo.CurrentCulture));
+ s.Append(' ');
+ s.Append(System.DateTime.Now.ToString(_time, CultureInfo.CurrentCulture));
+ s.Append(' ');
+ s.Append(message);
+ this.WriteLine(s.ToString());
+ }
+
+ public override void Write(string message)
+ {
+ System.Console.Error.Write(message);
+ }
+
+ public override void WriteLine(string message)
+ {
+ System.Console.Error.WriteLine(message);
+ }
+
+ internal string _date = null;
+ internal string _time = null;
+ }
+
+ public sealed class TraceLoggerI : LoggerI
+ {
+ public TraceLoggerI(string prefix, bool console)
+ : base(prefix)
+ {
+ _console = console;
+ if(console && !Trace.Listeners.Contains(_consoleListener))
+ {
+ Trace.Listeners.Add(_consoleListener);
+ }
+ }
+
+ public override void trace(string category, string message)
+ {
+ string s = format(category, message);
+ lock(_globalMutex)
+ {
+ Trace.TraceInformation(s);
+ Trace.Flush();
+ }
+ }
+
+ public override void warning(string message)
+ {
+ string s = format("warning", message);
+ lock(_globalMutex)
+ {
+ Trace.TraceWarning(s);
+ Trace.Flush();
+ }
+ }
+
+ public override void error(string message)
+ {
+ string s = format("error", message);
+ {
+ Trace.TraceError(s);
+ Trace.Flush();
+ }
+ }
+
+ public override Logger cloneWithPrefix(string prefix)
+ {
+ return new TraceLoggerI(prefix, _console);
+ }
+
+ protected override void write(string message)
+ {
+ Trace.WriteLine(message);
+ Trace.Flush();
+ }
+
+ private string format(string category, string message)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder(_formattedPrefix);
+ s.Append(category);
+ s.Append(": ");
+ s.Append(message);
+ s.Replace("\n", "\n ");
+ return s.ToString();
+ }
+
+ private bool _console;
+ internal static ConsoleListener _consoleListener = new ConsoleListener();
+ }
+# endif
+#endif
+}
diff --git a/csharp/src/Ice/LoggerPlugin.cs b/csharp/src/Ice/LoggerPlugin.cs
new file mode 100644
index 00000000000..942675580ea
--- /dev/null
+++ b/csharp/src/Ice/LoggerPlugin.cs
@@ -0,0 +1,65 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ /// <summary>
+ /// Class to support custom loggers. Applications using a custom logger
+ /// instantiate a LoggerPlugin with a custom logger and
+ /// return the instance from their PluginFactory implementation.
+ /// </summary>
+ public class LoggerPlugin : Ice.Plugin
+ {
+ /// <summary>
+ /// Installs a custom logger for a communicator.
+ /// </summary>
+ /// <param name="communicator">The communicator using the custom logger.</param>
+ /// <param name="logger">The custom logger for the communicator.</param>
+ public
+ LoggerPlugin(Communicator communicator, Logger logger)
+ {
+ if(communicator == null)
+ {
+ PluginInitializationException ex = new PluginInitializationException();
+ ex.reason = "Communicator cannot be null";
+ throw ex;
+ }
+
+ if(logger == null)
+ {
+ PluginInitializationException ex = new PluginInitializationException();
+ ex.reason = "Logger cannot be null";
+ throw ex;
+ }
+
+ IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
+ instance.setLogger(logger);
+ }
+
+ /// <summary>
+ /// Called by the Ice run time during communicator initialization. The derived class
+ /// can override this method to perform any initialization that might be required
+ /// by a custom logger.
+ /// </summary>
+ public void
+ initialize()
+ {
+ }
+
+ /// <summary>
+ /// Called by the Ice run time when the communicator is destroyed. The derived class
+ /// can override this method to perform any finalization that might be required
+ /// by a custom logger.
+ /// </summary>
+ public void
+ destroy()
+ {
+ }
+ }
+}
diff --git a/csharp/src/Ice/Makefile b/csharp/src/Ice/Makefile
new file mode 100644
index 00000000000..ee868c8c3d6
--- /dev/null
+++ b/csharp/src/Ice/Makefile
@@ -0,0 +1,201 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = Ice
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = Acceptor.cs \
+ ACM.cs \
+ AMDCallback.cs \
+ Application.cs \
+ Arrays.cs \
+ AssemblyInfo.cs \
+ AssemblyUtil.cs \
+ AsyncIOThread.cs \
+ AsyncResult.cs \
+ Base64.cs \
+ BasicStream.cs \
+ BatchRequestInterceptor.cs \
+ BatchRequestQueue.cs \
+ Buffer.cs \
+ ByteBuffer.cs \
+ CollectionBase.cs \
+ Collections.cs \
+ CollocatedRequestHandler.cs \
+ CommunicatorI.cs \
+ Compare.cs \
+ ConnectionFactory.cs \
+ ConnectionI.cs \
+ ConnectionRequestHandler.cs \
+ Connector.cs \
+ ConnectRequestHandler.cs \
+ DefaultsAndOverrides.cs \
+ DictionaryBase.cs \
+ DispatchInterceptor.cs \
+ EndpointFactory.cs \
+ EndpointFactoryManager.cs \
+ EndpointHostResolver.cs \
+ EndpointI.cs \
+ EventHandler.cs \
+ Exception.cs \
+ FormatType.cs \
+ HttpParser.cs \
+ ImplicitContextI.cs \
+ Incoming.cs \
+ IncomingAsync.cs \
+ Instance.cs \
+ InstrumentationI.cs \
+ IPEndpointI.cs \
+ LocatorInfo.cs \
+ LoggerAdminI.cs \
+ LoggerAdminLoggerI.cs \
+ LoggerI.cs \
+ LoggerPlugin.cs \
+ MetricsAdminI.cs \
+ MetricsObserverI.cs \
+ Network.cs \
+ NetworkProxy.cs \
+ Object.cs \
+ ObjectAdapterFactory.cs \
+ ObjectAdapterI.cs \
+ ObjectFactoryManager.cs \
+ ObserverHelper.cs \
+ OpaqueEndpointI.cs \
+ Optional.cs \
+ Options.cs \
+ OutgoingAsync.cs \
+ OutputBase.cs \
+ Patcher.cs \
+ PluginManagerI.cs \
+ ProcessI.cs \
+ PropertiesAdminI.cs \
+ PropertiesI.cs \
+ Property.cs \
+ PropertyNames.cs \
+ Protocol.cs \
+ ProtocolInstance.cs \
+ ProtocolPluginFacade.cs \
+ Proxy.cs \
+ ProxyFactory.cs \
+ ProxyIdentityKey.cs \
+ Reference.cs \
+ ReferenceFactory.cs \
+ ReplyStatus.cs \
+ RequestHandler.cs \
+ RequestHandlerFactory.cs \
+ ResponseHandler.cs \
+ RetryQueue.cs \
+ RouterInfo.cs \
+ ServantManager.cs \
+ SliceChecksums.cs \
+ SlicedData.cs \
+ SocketOperation.cs \
+ Stream.cs \
+ StreamI.cs \
+ StreamSocket.cs \
+ StreamWrapper.cs \
+ StringUtil.cs \
+ SysLoggerI.cs \
+ TcpAcceptor.cs \
+ TcpConnector.cs \
+ TcpEndpointI.cs \
+ TcpTransceiver.cs \
+ ThreadHookPlugin.cs \
+ ThreadPool.cs \
+ TieBase.cs \
+ Time.cs \
+ Timer.cs \
+ TraceLevels.cs \
+ TraceUtil.cs \
+ Transceiver.cs \
+ UdpConnector.cs \
+ UdpEndpointI.cs \
+ UdpTransceiver.cs \
+ UnknownSlicedObject.cs \
+ UserExceptionFactory.cs \
+ Util.cs \
+ ValueWriter.cs \
+ WSAcceptor.cs \
+ WSConnector.cs \
+ WSEndpoint.cs \
+ WSTransceiver.cs
+
+SLICE_SRCS = $(SDIR)/BuiltinSequences.ice \
+ $(SDIR)/Communicator.ice \
+ $(SDIR)/Connection.ice \
+ $(SDIR)/Current.ice \
+ $(SDIR)/Endpoint.ice \
+ $(SDIR)/EndpointTypes.ice \
+ $(SDIR)/FacetMap.ice \
+ $(SDIR)/Identity.ice \
+ $(SDIR)/ImplicitContext.ice \
+ $(SDIR)/Instrumentation.ice \
+ $(SDIR)/LocalException.ice \
+ $(SDIR)/Locator.ice \
+ $(SDIR)/Logger.ice \
+ $(SDIR)/Metrics.ice \
+ $(SDIR)/ObjectAdapter.ice \
+ $(SDIR)/ObjectFactory.ice \
+ $(SDIR)/Plugin.ice \
+ $(SDIR)/Process.ice \
+ $(SDIR)/Properties.ice \
+ $(SDIR)/PropertiesAdmin.ice \
+ $(SDIR)/RemoteLogger.ice \
+ $(SDIR)/Router.ice \
+ $(SDIR)/ServantLocator.ice \
+ $(SDIR)/SliceChecksumDict.ice \
+ $(SDIR)/Version.ice \
+
+SDIR = $(slicedir)/Ice
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+ifneq ($(MANAGED),yes)
+ MCSFLAGS := $(MCSFLAGS) -unsafe+
+endif
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(subst /,$(DSEP),$^)
+ $(INSTALL) $(LIBNAME).config $(assembliesdir)
+
+clean::
+ -rm -f $(assembliesdir)/$(LIBNAME).config
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+else
+install:: all
+ $(call installdata,$(TARGETS).config,$(DESTDIR)$(install_assembliesdir))
+endif
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+clean::
+ echo $(GEN_SRCS)
+ -rm -f $(assembliesdir)/$(PKG).xml
+
+$(GDIR)/BuiltinSequences.cs: $(SDIR)/BuiltinSequences.ice $(SLICE2CPP) $(SLICEPARSERLIB)
+ rm -f $(GDIR)/BuiltinSequences.cs
+ $(SLICE2CS) $(SLICE2CSFLAGS) --stream $(SDIR)/BuiltinSequences.ice
+ mv BuiltinSequences.cs $(GDIR)
diff --git a/csharp/src/Ice/Makefile.mak b/csharp/src/Ice/Makefile.mak
new file mode 100644
index 00000000000..f6c85328dc5
--- /dev/null
+++ b/csharp/src/Ice/Makefile.mak
@@ -0,0 +1,199 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = Ice
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = Acceptor.cs \
+ ACM.cs \
+ AMDCallback.cs \
+ Application.cs \
+ Arrays.cs \
+ AssemblyInfo.cs \
+ AssemblyUtil.cs \
+ AsyncIOThread.cs \
+ AsyncResult.cs \
+ Base64.cs \
+ BasicStream.cs \
+ BatchRequestInterceptor.cs \
+ BatchRequestQueue.cs \
+ Buffer.cs \
+ ByteBuffer.cs \
+ CollectionBase.cs \
+ Collections.cs \
+ CollocatedRequestHandler.cs \
+ CommunicatorI.cs \
+ Compare.cs \
+ ConnectionFactory.cs \
+ ConnectionI.cs \
+ ConnectionRequestHandler.cs \
+ Connector.cs \
+ ConnectRequestHandler.cs \
+ DefaultsAndOverrides.cs \
+ DictionaryBase.cs \
+ DispatchInterceptor.cs \
+ EndpointFactory.cs \
+ EndpointFactoryManager.cs \
+ EndpointHostResolver.cs \
+ EndpointI.cs \
+ EventHandler.cs \
+ Exception.cs \
+ FormatType.cs \
+ HashSet.cs \
+ HttpParser.cs \
+ ImplicitContextI.cs \
+ Incoming.cs \
+ IncomingAsync.cs \
+ Instance.cs \
+ InstrumentationI.cs \
+ IPEndpointI.cs \
+ LocatorInfo.cs \
+ LoggerAdminI.cs \
+ LoggerAdminLoggerI.cs \
+ LoggerI.cs \
+ LoggerPlugin.cs \
+ MetricsAdminI.cs \
+ MetricsObserverI.cs \
+ Network.cs \
+ NetworkProxy.cs \
+ Object.cs \
+ ObjectAdapterFactory.cs \
+ ObjectAdapterI.cs \
+ ObjectFactoryManager.cs \
+ ObserverHelper.cs \
+ OpaqueEndpointI.cs \
+ Optional.cs \
+ Options.cs \
+ OutgoingAsync.cs \
+ OutputBase.cs \
+ Patcher.cs \
+ PluginManagerI.cs \
+ ProcessI.cs \
+ PropertiesAdminI.cs \
+ PropertiesI.cs \
+ Property.cs \
+ PropertyNames.cs \
+ Protocol.cs \
+ ProtocolInstance.cs \
+ ProtocolPluginFacade.cs \
+ Proxy.cs \
+ ProxyFactory.cs \
+ ProxyIdentityKey.cs \
+ Reference.cs \
+ ReferenceFactory.cs \
+ ReplyStatus.cs \
+ RequestHandler.cs \
+ RequestHandlerFactory.cs \
+ ResponseHandler.cs \
+ RetryQueue.cs \
+ RouterInfo.cs \
+ ServantManager.cs \
+ SliceChecksums.cs \
+ SlicedData.cs \
+ SocketOperation.cs \
+ Stream.cs \
+ StreamI.cs \
+ StreamSocket.cs \
+ StreamWrapper.cs \
+ StringUtil.cs \
+ SysLoggerI.cs \
+ TcpAcceptor.cs \
+ TcpConnector.cs \
+ TcpEndpointI.cs \
+ TcpTransceiver.cs \
+ ThreadHookPlugin.cs \
+ ThreadPool.cs \
+ TieBase.cs \
+ Time.cs \
+ Timer.cs \
+ TraceLevels.cs \
+ TraceUtil.cs \
+ Transceiver.cs \
+ UdpConnector.cs \
+ UdpEndpointI.cs \
+ UdpTransceiver.cs \
+ UnknownSlicedObject.cs \
+ UserExceptionFactory.cs \
+ Util.cs \
+ ValueWriter.cs \
+ WSAcceptor.cs \
+ WSConnector.cs \
+ WSEndpoint.cs \
+ WSTransceiver.cs
+
+GEN_SRCS = $(GDIR)\BuiltinSequences.cs \
+ $(GDIR)\Communicator.cs \
+ $(GDIR)\Connection.cs \
+ $(GDIR)\Current.cs \
+ $(GDIR)\Endpoint.cs \
+ $(GDIR)\EndpointTypes.cs \
+ $(GDIR)\FacetMap.cs \
+ $(GDIR)\Identity.cs \
+ $(GDIR)\ImplicitContext.cs \
+ $(GDIR)\Instrumentation.cs \
+ $(GDIR)\LocalException.cs \
+ $(GDIR)\Locator.cs \
+ $(GDIR)\Logger.cs \
+ $(GDIR)\Metrics.cs \
+ $(GDIR)\ObjectAdapter.cs \
+ $(GDIR)\ObjectFactory.cs \
+ $(GDIR)\Plugin.cs \
+ $(GDIR)\Process.cs \
+ $(GDIR)\Properties.cs \
+ $(GDIR)\PropertiesAdmin.cs \
+ $(GDIR)\RemoteLogger.cs \
+ $(GDIR)\Router.cs \
+ $(GDIR)\ServantLocator.cs \
+ $(GDIR)\SliceChecksumDict.cs \
+ $(GDIR)\Version.cs
+
+SDIR = $(slicedir)\Ice
+GDIR = generated
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+!if "$(MANAGED)" != "yes"
+MCSFLAGS = $(MCSFLAGS) /unsafe
+!endif
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) --ice -I"$(slicedir)"
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) /baseaddress:0x20000000 $(MCSFLAGS) $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
+
+$(GDIR)\BuiltinSequences.cs: "$(SDIR)\BuiltinSequences.ice" "$(SLICE2CS)" "$(SLICEPARSERLIB)"
+ del /q $(GDIR)\BuiltinSequences.cs
+ "$(SLICE2CS)" $(SLICE2CSFLAGS) --stream "$(SDIR)\BuiltinSequences.ice"
+ move BuiltinSequences.cs $(GDIR)
diff --git a/csharp/src/Ice/MetricsAdminI.cs b/csharp/src/Ice/MetricsAdminI.cs
new file mode 100644
index 00000000000..d6f58e9de20
--- /dev/null
+++ b/csharp/src/Ice/MetricsAdminI.cs
@@ -0,0 +1,1048 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Text;
+ using System.Diagnostics;
+ using System.Collections.Generic;
+ using System.Text.RegularExpressions;
+
+ internal interface IMetricsMap
+ {
+ IceMX.Metrics[] getMetrics();
+ IceMX.MetricsFailures[] getFailures();
+ IceMX.MetricsFailures getFailures(string id);
+ Dictionary<string, string> getProperties();
+ };
+
+ interface ISubMap
+ {
+ void addSubMapToMetrics(IceMX.Metrics metrics);
+ };
+
+ interface ISubMapCloneFactory
+ {
+ ISubMap create();
+ };
+
+ interface ISubMapFactory
+ {
+ ISubMapCloneFactory createCloneFactory(string subMapPrefix, Ice.Properties properties);
+ };
+
+ internal interface IMetricsMapFactory
+ {
+ void registerSubMap<S>(string subMap, System.Reflection.FieldInfo field) where S : IceMX.Metrics, new();
+ void update();
+ IMetricsMap create(string mapPrefix, Ice.Properties properties);
+ };
+
+ internal class SubMap<S> : ISubMap where S : IceMX.Metrics, new()
+ {
+ internal SubMap(MetricsMap<S> map, System.Reflection.FieldInfo field)
+ {
+ _map = map;
+ _field = field;
+ }
+
+ internal MetricsMap<S>.Entry getMatching(IceMX.MetricsHelper<S> helper)
+ {
+ return _map.getMatching(helper, null);
+ }
+
+ public void addSubMapToMetrics(IceMX.Metrics metrics)
+ {
+ try
+ {
+ _field.SetValue(metrics, _map.getMetrics());
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ readonly private MetricsMap<S> _map;
+ readonly private System.Reflection.FieldInfo _field;
+ };
+
+ internal class SubMapCloneFactory<S> : ISubMapCloneFactory where S : IceMX.Metrics, new()
+ {
+ internal SubMapCloneFactory(MetricsMap<S> map, System.Reflection.FieldInfo field)
+ {
+ _map = map;
+ _field = field;
+ }
+
+ public ISubMap create()
+ {
+ return new SubMap<S>(new MetricsMap<S>(_map), _field);
+ }
+
+ readonly private MetricsMap<S> _map;
+ readonly private System.Reflection.FieldInfo _field;
+ };
+
+ class SubMapFactory<S> : ISubMapFactory where S : IceMX.Metrics, new()
+ {
+ internal SubMapFactory(System.Reflection.FieldInfo field)
+ {
+ _field = field;
+ }
+
+ public ISubMapCloneFactory createCloneFactory(string subMapPrefix, Ice.Properties properties)
+ {
+ return new SubMapCloneFactory<S>(new MetricsMap<S>(subMapPrefix, properties, null), _field);
+ }
+
+ readonly private System.Reflection.FieldInfo _field;
+ };
+
+ public class MetricsMap<T> : IMetricsMap where T : IceMX.Metrics, new()
+ {
+ public class Entry
+ {
+ internal Entry(MetricsMap<T> map, T obj)
+ {
+ _map = map;
+ _object = obj;
+ }
+
+ public void failed(string exceptionName)
+ {
+ lock(_map)
+ {
+ ++_object.failures;
+ int count;
+ if(_failures == null)
+ {
+ _failures = new Dictionary<string, int>();
+ }
+ if(_failures.TryGetValue(exceptionName, out count))
+ {
+ _failures[exceptionName] = count + 1;
+ }
+ else
+ {
+ _failures[exceptionName] = 1;
+ }
+ }
+ }
+
+ internal MetricsMap<S>.Entry getMatching<S>(string mapName, IceMX.MetricsHelper<S> helper)
+ where S : IceMX.Metrics, new()
+ {
+ ISubMap m;
+ lock(_map)
+ {
+ if(_subMaps == null || !_subMaps.TryGetValue(mapName, out m))
+ {
+ m = _map.createSubMap(mapName);
+ if(m == null)
+ {
+ return null;
+ }
+ if(_subMaps == null)
+ {
+ _subMaps = new Dictionary<string, ISubMap>();
+ }
+ _subMaps.Add(mapName, m);
+ }
+ }
+ return ((SubMap<S>)m).getMatching(helper);
+ }
+
+ public void detach(long lifetime)
+ {
+ lock(_map)
+ {
+ _object.totalLifetime += lifetime;
+ if(--_object.current == 0)
+ {
+ _map.detached(this);
+ }
+ }
+ }
+
+ public void execute(IceMX.Observer<T>.MetricsUpdate func)
+ {
+ lock(_map)
+ {
+ func(_object);
+ }
+ }
+
+ public MetricsMap<T> getMap()
+ {
+ return _map;
+ }
+
+ internal IceMX.MetricsFailures getFailures()
+ {
+ if(_failures == null)
+ {
+ return null;
+ }
+ IceMX.MetricsFailures f = new IceMX.MetricsFailures();
+ f.id = _object.id;
+ f.failures = new Dictionary<string, int>(_failures);
+ return f;
+ }
+
+ internal void attach(IceMX.MetricsHelper<T> helper)
+ {
+ ++_object.total;
+ ++_object.current;
+ helper.initMetrics(_object);
+ }
+
+ internal bool isDetached()
+ {
+ return _object.current == 0;
+ }
+
+ internal IceMX.Metrics clone()
+ {
+ T metrics = (T)_object.Clone();
+ if(_subMaps != null)
+ {
+ foreach(ISubMap s in _subMaps.Values)
+ {
+ s.addSubMapToMetrics(metrics);
+ }
+ }
+ return metrics;
+ }
+
+ internal string getId()
+ {
+ return _object.id;
+ }
+
+ private MetricsMap<T> _map;
+ private T _object;
+ private Dictionary<string, int> _failures;
+ private Dictionary<string, ISubMap> _subMaps;
+ };
+
+ internal MetricsMap(string mapPrefix, Ice.Properties props, Dictionary<string, ISubMapFactory> subMaps)
+ {
+ MetricsAdminI.validateProperties(mapPrefix, props);
+ _properties = props.getPropertiesForPrefix(mapPrefix);
+
+ _retain = props.getPropertyAsIntWithDefault(mapPrefix + "RetainDetached", 10);
+ _accept = parseRule(props, mapPrefix + "Accept");
+ _reject = parseRule(props, mapPrefix + "Reject");
+ _groupByAttributes = new List<string>();
+ _groupBySeparators = new List<string>();
+
+ string groupBy = props.getPropertyWithDefault(mapPrefix + "GroupBy", "id");
+ if(groupBy.Length > 0)
+ {
+ string v = "";
+ bool attribute = Char.IsLetter(groupBy[0]) || Char.IsDigit(groupBy[0]);
+ if(!attribute)
+ {
+ _groupByAttributes.Add("");
+ }
+
+ foreach(char p in groupBy)
+ {
+ bool isAlphaNum = Char.IsLetter(p) || Char.IsDigit(p) || p == '.';
+ if(attribute && !isAlphaNum)
+ {
+ _groupByAttributes.Add(v);
+ v = "" + p;
+ attribute = false;
+ }
+ else if(!attribute && isAlphaNum)
+ {
+ _groupBySeparators.Add(v);
+ v = "" + p;
+ attribute = true;
+ }
+ else
+ {
+ v += p;
+ }
+ }
+
+ if(attribute)
+ {
+ _groupByAttributes.Add(v);
+ }
+ else
+ {
+ _groupBySeparators.Add(v);
+ }
+ }
+
+ if(subMaps != null && subMaps.Count > 0)
+ {
+ _subMaps = new Dictionary<string, ISubMapCloneFactory>();
+
+ List<string> subMapNames = new List<string>();
+ foreach(KeyValuePair<string, ISubMapFactory> e in subMaps)
+ {
+ subMapNames.Add(e.Key);
+ string subMapsPrefix = mapPrefix + "Map.";
+ string subMapPrefix = subMapsPrefix + e.Key + '.';
+ if(props.getPropertiesForPrefix(subMapPrefix).Count == 0)
+ {
+ if(props.getPropertiesForPrefix(subMapsPrefix).Count == 0)
+ {
+ subMapPrefix = mapPrefix;
+ }
+ else
+ {
+ continue; // This sub-map isn't configured.
+ }
+ }
+
+ _subMaps.Add(e.Key, e.Value.createCloneFactory(subMapPrefix, props));
+ }
+ }
+ else
+ {
+ _subMaps = null;
+ }
+ }
+
+ internal MetricsMap(MetricsMap<T> map)
+ {
+ _properties = map._properties;
+ _groupByAttributes = map._groupByAttributes;
+ _groupBySeparators = map._groupBySeparators;
+ _retain = map._retain;
+ _accept = map._accept;
+ _reject = map._reject;
+ _subMaps = map._subMaps;
+ }
+
+ public Dictionary<string, string> getProperties()
+ {
+ return _properties;
+ }
+
+ public IceMX.Metrics[] getMetrics()
+ {
+ lock(this)
+ {
+ IceMX.Metrics[] metrics = new IceMX.Metrics[_objects.Count];
+ int i = 0;
+ foreach(Entry e in _objects.Values)
+ {
+ metrics[i++] = e.clone();
+ }
+ return metrics;
+ }
+ }
+
+ public IceMX.MetricsFailures[] getFailures()
+ {
+ lock(this)
+ {
+ List<IceMX.MetricsFailures> failures = new List<IceMX.MetricsFailures>();
+ foreach(Entry e in _objects.Values)
+ {
+ IceMX.MetricsFailures f = e.getFailures();
+ if(f != null)
+ {
+ failures.Add(f);
+ }
+ }
+ return failures.ToArray();
+ }
+ }
+
+ public IceMX.MetricsFailures getFailures(string id)
+ {
+ lock(this)
+ {
+ Entry e;
+ if(_objects.TryGetValue(id, out e))
+ {
+ return e.getFailures();
+ }
+ return null;
+ }
+ }
+
+ ISubMap createSubMap(string subMapName)
+ {
+ if(_subMaps == null)
+ {
+ return null;
+ }
+ ISubMapCloneFactory factory;
+ if(_subMaps.TryGetValue(subMapName, out factory))
+ {
+ return factory.create();
+ }
+ return null;
+ }
+
+ public Entry getMatching(IceMX.MetricsHelper<T> helper, Entry previous)
+ {
+ //
+ // Check the accept and reject filters.
+ //
+ foreach(KeyValuePair<string, Regex> e in _accept)
+ {
+ if(!match(e.Key, e.Value, helper, false))
+ {
+ return null;
+ }
+ }
+
+ foreach(KeyValuePair<string, Regex> e in _reject)
+ {
+ if(match(e.Key, e.Value, helper, true))
+ {
+ return null;
+ }
+ }
+
+ //
+ // Compute the key from the GroupBy property.
+ //
+ string key;
+ try
+ {
+ if(_groupByAttributes.Count == 1)
+ {
+ key = helper.resolve(_groupByAttributes[0]);
+ }
+ else
+ {
+ StringBuilder os = new StringBuilder();
+ IEnumerator<string> q = _groupBySeparators.GetEnumerator();
+ foreach(string p in _groupByAttributes)
+ {
+ os.Append(helper.resolve(p));
+ if(q.MoveNext())
+ {
+ os.Append(q.Current);
+ }
+ }
+ key = os.ToString();
+ }
+ }
+ catch(Exception)
+ {
+ return null;
+ }
+
+ //
+ // Lookup the metrics object.
+ //
+ lock(this)
+ {
+ if(previous != null && previous.getId().Equals(key))
+ {
+ Debug.Assert(_objects[key] == previous);
+ return previous;
+ }
+
+ Entry e;
+ if(!_objects.TryGetValue(key, out e))
+ {
+ try
+ {
+ T t = new T();
+ t.id = key;
+ e = new Entry(this, t);
+ _objects.Add(key, e);
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ }
+ }
+ e.attach(helper);
+ return e;
+ }
+ }
+
+ private void detached(Entry entry)
+ {
+ if(_retain == 0)
+ {
+ return;
+ }
+
+ if(_detachedQueue == null)
+ {
+ _detachedQueue = new LinkedList<Entry>();
+ }
+ Debug.Assert(_detachedQueue.Count <= _retain);
+
+ // Compress the queue by removing entries which are no longer detached.
+ LinkedListNode<Entry> p = _detachedQueue.First;
+ while(p != null)
+ {
+ LinkedListNode<Entry> next = p.Next;
+ if(p.Value == entry || !p.Value.isDetached())
+ {
+ _detachedQueue.Remove(p);
+ }
+ p = next;
+ }
+
+ // If there's still no room, remove the oldest entry (at the front).
+ if(_detachedQueue.Count == _retain)
+ {
+ _objects.Remove(_detachedQueue.First.Value.getId());
+ _detachedQueue.RemoveFirst();
+ }
+
+ // Add the entry at the back of the queue.
+ _detachedQueue.AddLast(entry);
+ }
+
+ private Dictionary<string, Regex> parseRule(Ice.Properties properties, string name)
+ {
+ Dictionary<string, Regex> pats = new Dictionary<string, Regex>();
+ Dictionary<string, string> rules = properties.getPropertiesForPrefix(name + '.');
+ foreach(KeyValuePair<string, string> e in rules)
+ {
+ pats.Add(e.Key.Substring(name.Length + 1), new Regex(e.Value));
+ }
+ return pats;
+ }
+
+ private bool match(string attribute, Regex regex, IceMX.MetricsHelper<T> helper, bool reject)
+ {
+ string value;
+ try
+ {
+ value = helper.resolve(attribute);
+ }
+ catch(Exception)
+ {
+ return !reject;
+ }
+ return regex.IsMatch(value);
+ }
+
+ readonly private Dictionary<string, string> _properties;
+ readonly private List<string> _groupByAttributes;
+ readonly private List<string> _groupBySeparators;
+ readonly private int _retain;
+ readonly private Dictionary<string, Regex> _accept;
+ readonly private Dictionary<string, Regex> _reject;
+
+ readonly private Dictionary<string, Entry> _objects = new Dictionary<string, Entry>();
+ readonly private Dictionary<string, ISubMapCloneFactory> _subMaps;
+ private LinkedList<Entry> _detachedQueue;
+ };
+
+ internal class MetricsViewI
+ {
+ internal MetricsViewI(string name)
+ {
+ _name = name;
+ }
+
+ internal bool addOrUpdateMap(Ice.Properties properties, string mapName, IMetricsMapFactory factory,
+ Ice.Logger logger)
+ {
+ //
+ // Add maps to views configured with the given map.
+ //
+ string viewPrefix = "IceMX.Metrics." + _name + ".";
+ string mapsPrefix = viewPrefix + "Map.";
+ Dictionary<string, string> mapsProps = properties.getPropertiesForPrefix(mapsPrefix);
+
+ string mapPrefix;
+ Dictionary<string, string> mapProps = new Dictionary<string, string>();
+ if(mapsProps.Count > 0)
+ {
+ mapPrefix = mapsPrefix + mapName + ".";
+ mapProps = properties.getPropertiesForPrefix(mapPrefix);
+ if(mapProps.Count == 0)
+ {
+ // This map isn't configured for this view.
+ return _maps.Remove(mapName);
+ }
+ }
+ else
+ {
+ mapPrefix = viewPrefix;
+ mapProps = properties.getPropertiesForPrefix(mapPrefix);
+ }
+
+ if(properties.getPropertyAsInt(mapPrefix + "Disabled") > 0)
+ {
+ // This map is disabled for this view.
+ return _maps.Remove(mapName);
+ }
+
+ IMetricsMap m;
+ if(_maps.TryGetValue(mapName, out m) &&
+ IceUtilInternal.Collections.DictionaryEquals(m.getProperties(), mapProps))
+ {
+ return false; // The map configuration didn't change, no need to re-create.
+ }
+
+ try
+ {
+ _maps[mapName] = factory.create(mapPrefix, properties);
+ }
+ catch(Exception ex)
+ {
+ logger.warning("unexpected exception while creating metrics map:\n" + ex);
+ _maps.Remove(mapName);
+ }
+ return true;
+ }
+
+ internal bool removeMap(string mapName)
+ {
+ return _maps.Remove(mapName);
+ }
+
+ internal Dictionary<string, IceMX.Metrics[]> getMetrics()
+ {
+ Dictionary<string, IceMX.Metrics[]> metrics = new Dictionary<string, IceMX.Metrics[]>();
+ foreach(KeyValuePair<string, IMetricsMap> e in _maps)
+ {
+ IceMX.Metrics[] m = e.Value.getMetrics();
+ if(m != null)
+ {
+ metrics.Add(e.Key, m);
+ }
+ }
+ return metrics;
+ }
+
+ internal IceMX.MetricsFailures[] getFailures(string mapName)
+ {
+ IMetricsMap m;
+ if(_maps.TryGetValue(mapName, out m))
+ {
+ return m.getFailures();
+ }
+ return null;
+ }
+
+ internal IceMX.MetricsFailures getFailures(string mapName, string id)
+ {
+ IMetricsMap m;
+ if(_maps.TryGetValue(mapName, out m))
+ {
+ return m.getFailures(id);
+ }
+ return null;
+ }
+
+ internal ICollection<string> getMaps()
+ {
+ return _maps.Keys;
+ }
+
+ internal MetricsMap<T> getMap<T>(string mapName) where T : IceMX.Metrics, new()
+ {
+ IMetricsMap m;
+ if(_maps.TryGetValue(mapName, out m))
+ {
+ return (MetricsMap<T>)m;
+ }
+ return null;
+ }
+
+ readonly private string _name;
+ readonly private Dictionary<string, IMetricsMap> _maps = new Dictionary<string, IMetricsMap>();
+ };
+
+ public class MetricsAdminI : IceMX.MetricsAdminDisp_, Ice.PropertiesAdminUpdateCallback
+ {
+ readonly static private string[] suffixes =
+ {
+ "Disabled",
+ "GroupBy",
+ "Accept.*",
+ "Reject.*",
+ "RetainDetached",
+ "Map.*",
+ };
+
+ public static void validateProperties(string prefix, Ice.Properties properties)
+ {
+ Dictionary<string, string> props = properties.getPropertiesForPrefix(prefix);
+ List<string> unknownProps = new List<string>();
+ foreach(string prop in props.Keys)
+ {
+ bool valid = false;
+ foreach(string suffix in suffixes)
+ {
+ if(IceUtilInternal.StringUtil.match(prop, prefix + suffix, false))
+ {
+ valid = true;
+ break;
+ }
+ }
+
+ if(!valid)
+ {
+ unknownProps.Add(prop);
+ }
+ }
+
+ if(unknownProps.Count != 0 && properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0)
+ {
+ StringBuilder message = new StringBuilder("found unknown IceMX properties for `");
+ message.Append(prefix.Substring(0, prefix.Length - 1));
+ message.Append("':");
+ foreach(string p in unknownProps)
+ {
+ message.Append("\n ");
+ message.Append(p);
+ }
+ Ice.Util.getProcessLogger().warning(message.ToString());
+ }
+ }
+
+ class MetricsMapFactory<T> : IMetricsMapFactory where T : IceMX.Metrics, new()
+ {
+#if COMPACT
+ public MetricsMapFactory(Ice.VoidAction updater)
+#else
+ public MetricsMapFactory(System.Action updater)
+#endif
+ {
+ _updater = updater;
+ }
+
+ public void update()
+ {
+ Debug.Assert(_updater != null);
+ _updater();
+ }
+
+ public IMetricsMap create(string mapPrefix, Ice.Properties properties)
+ {
+ return new MetricsMap<T>(mapPrefix, properties, _subMaps);
+ }
+
+ public void registerSubMap<S>(string subMap, System.Reflection.FieldInfo field)
+ where S : IceMX.Metrics, new()
+ {
+ _subMaps.Add(subMap, new SubMapFactory<S>(field));
+ }
+
+#if COMPACT
+ readonly private Ice.VoidAction _updater;
+#else
+ readonly private System.Action _updater;
+#endif
+ readonly private Dictionary<string, ISubMapFactory> _subMaps = new Dictionary<string, ISubMapFactory>();
+ };
+
+ public MetricsAdminI(Ice.Properties properties, Ice.Logger logger)
+ {
+ _logger = logger;
+ _properties = properties;
+ updateViews();
+ }
+
+ public void updateViews()
+ {
+ HashSet<IMetricsMapFactory> updatedMaps = new HashSet<IMetricsMapFactory>();
+ lock(this)
+ {
+ string viewsPrefix = "IceMX.Metrics.";
+ Dictionary<string, string> viewsProps = _properties.getPropertiesForPrefix(viewsPrefix);
+ Dictionary<string, MetricsViewI> views = new Dictionary<string, MetricsViewI>();
+ _disabledViews.Clear();
+ foreach(KeyValuePair<string, string> e in viewsProps)
+ {
+ string viewName = e.Key.Substring(viewsPrefix.Length);
+ int dotPos = viewName.IndexOf('.');
+ if(dotPos > 0)
+ {
+ viewName = viewName.Substring(0, dotPos);
+ }
+
+ if(views.ContainsKey(viewName) || _disabledViews.Contains(viewName))
+ {
+ continue; // View already configured.
+ }
+
+ validateProperties(viewsPrefix + viewName + ".", _properties);
+
+ if(_properties.getPropertyAsIntWithDefault(viewsPrefix + viewName + ".Disabled", 0) > 0)
+ {
+ _disabledViews.Add(viewName);
+ continue; // The view is disabled
+ }
+
+ //
+ // Create the view or update it.
+ //
+ MetricsViewI v;
+ if(!_views.TryGetValue(viewName, out v))
+ {
+ v = new MetricsViewI(viewName);
+ }
+ views[viewName] = v;
+
+ foreach(KeyValuePair<string, IMetricsMapFactory> f in _factories)
+ {
+ if(v.addOrUpdateMap(_properties, f.Key, f.Value, _logger))
+ {
+ updatedMaps.Add(f.Value);
+ }
+ }
+ }
+
+ Dictionary<string, MetricsViewI> tmp = _views;
+ _views = views;
+ views = tmp;
+
+ //
+ // Go through removed views to collect maps to update.
+ //
+ foreach(KeyValuePair<string, MetricsViewI> v in views)
+ {
+ if(!_views.ContainsKey(v.Key))
+ {
+ foreach(string n in v.Value.getMaps())
+ {
+ updatedMaps.Add(_factories[n]);
+ }
+ }
+ }
+ }
+
+ //
+ // Call the updaters to update the maps.
+ //
+ foreach(IMetricsMapFactory f in updatedMaps)
+ {
+ f.update();
+ }
+ }
+
+ override public string[] getMetricsViewNames(out string[] disabledViews, Ice.Current current)
+ {
+ lock(this)
+ {
+ disabledViews = _disabledViews.ToArray();
+ return new List<String>(_views.Keys).ToArray();
+ }
+ }
+
+ override public void enableMetricsView(string name, Ice.Current current)
+ {
+ lock(this)
+ {
+ getMetricsView(name); // Throws if unknown view.
+ _properties.setProperty("IceMX.Metrics." + name + ".Disabled", "0");
+ }
+ updateViews();
+ }
+
+ override public void disableMetricsView(string name, Ice.Current current)
+ {
+ lock(this)
+ {
+ getMetricsView(name); // Throws if unknown view.
+ _properties.setProperty("IceMX.Metrics." + name + ".Disabled", "1");
+ }
+ updateViews();
+ }
+
+ override public Dictionary<string, IceMX.Metrics[]> getMetricsView(string viewName, out long timestamp,
+ Ice.Current current)
+ {
+ lock(this)
+ {
+ MetricsViewI view = getMetricsView(viewName);
+ timestamp = IceInternal.Time.currentMonotonicTimeMillis();
+ if(view != null)
+ {
+ return view.getMetrics();
+ }
+ return new Dictionary<string, IceMX.Metrics[]>();
+ }
+ }
+
+ override public IceMX.MetricsFailures[] getMapMetricsFailures(string viewName, string mapName, Ice.Current c)
+ {
+ lock(this)
+ {
+ MetricsViewI view = getMetricsView(viewName);
+ if(view != null)
+ {
+ return view.getFailures(mapName);
+ }
+ return new IceMX.MetricsFailures[0];
+ }
+ }
+
+ override public IceMX.MetricsFailures getMetricsFailures(string viewName, string mapName, string id,
+ Ice.Current c)
+ {
+ lock(this)
+ {
+ MetricsViewI view = getMetricsView(viewName);
+ if(view != null)
+ {
+ return view.getFailures(mapName, id);
+ }
+ return new IceMX.MetricsFailures();
+ }
+ }
+
+#if COMPACT
+ public void registerMap<T>(string map, Ice.VoidAction updater)
+#else
+ public void registerMap<T>(string map, System.Action updater)
+#endif
+ where T : IceMX.Metrics, new()
+ {
+ bool updated;
+ MetricsMapFactory<T> factory;
+ lock(this)
+ {
+ factory = new MetricsMapFactory<T>(updater);
+ _factories.Add(map, factory);
+ updated = addOrUpdateMap(map, factory);
+ }
+ if(updated)
+ {
+ factory.update();
+ }
+ }
+
+ public void registerSubMap<S>(string map, string subMap, System.Reflection.FieldInfo field)
+ where S : IceMX.Metrics, new()
+ {
+ bool updated;
+ IMetricsMapFactory factory;
+ lock(this)
+ {
+ if(!_factories.TryGetValue(map, out factory))
+ {
+ return;
+ }
+ factory.registerSubMap<S>(subMap, field);
+ removeMap(map);
+ updated = addOrUpdateMap(map, factory);
+ }
+ if(updated)
+ {
+ factory.update();
+ }
+ }
+
+ public void unregisterMap(string mapName)
+ {
+ bool updated;
+ IMetricsMapFactory factory;
+ lock(this)
+ {
+ if(!_factories.TryGetValue(mapName, out factory))
+ {
+ return;
+ }
+ _factories.Remove(mapName);
+ updated = removeMap(mapName);
+ }
+ if(updated)
+ {
+ factory.update();
+ }
+ }
+
+ public List<MetricsMap<T>> getMaps<T>(string mapName) where T : IceMX.Metrics, new()
+ {
+ List<MetricsMap<T>> maps = new List<MetricsMap<T>>();
+ foreach(MetricsViewI v in _views.Values)
+ {
+ MetricsMap<T> map = v.getMap<T>(mapName);
+ if(map != null)
+ {
+ maps.Add(map);
+ }
+ }
+ return maps;
+ }
+
+ public Ice.Logger getLogger()
+ {
+ return _logger;
+ }
+
+ public void updated(Dictionary<string, string> props)
+ {
+ foreach(KeyValuePair<string, string> e in props)
+ {
+ if(e.Key.IndexOf("IceMX.") == 0)
+ {
+ // Udpate the metrics views using the new configuration.
+ try
+ {
+ updateViews();
+ }
+ catch(Exception ex)
+ {
+ _logger.warning("unexpected exception while updating metrics view configuration:\n" +
+ ex.ToString());
+ }
+ return;
+ }
+ }
+ }
+
+ private MetricsViewI getMetricsView(string name)
+ {
+ MetricsViewI view;
+ if(!_views.TryGetValue(name, out view))
+ {
+ if(!_disabledViews.Contains(name))
+ {
+ throw new IceMX.UnknownMetricsView();
+ }
+ return null;
+ }
+ return view;
+ }
+
+ private bool addOrUpdateMap(string mapName, IMetricsMapFactory factory)
+ {
+ bool updated = false;
+ foreach(MetricsViewI v in _views.Values)
+ {
+ updated |= v.addOrUpdateMap(_properties, mapName, factory, _logger);
+ }
+ return updated;
+ }
+
+ private bool removeMap(string mapName)
+ {
+ bool updated = false;
+ foreach(MetricsViewI v in _views.Values)
+ {
+ updated |= v.removeMap(mapName);
+ }
+ return updated;
+ }
+
+ private Ice.Properties _properties;
+ readonly private Ice.Logger _logger;
+ readonly private Dictionary<string, IMetricsMapFactory> _factories =
+ new Dictionary<string, IMetricsMapFactory>();
+ private Dictionary<string, MetricsViewI> _views = new Dictionary<string, MetricsViewI>();
+ private List<string> _disabledViews = new List<string>();
+ }
+} \ No newline at end of file
diff --git a/csharp/src/Ice/MetricsObserverI.cs b/csharp/src/Ice/MetricsObserverI.cs
new file mode 100644
index 00000000000..3681c185125
--- /dev/null
+++ b/csharp/src/Ice/MetricsObserverI.cs
@@ -0,0 +1,454 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceMX
+{
+ using IceInternal;
+ using System;
+ using System.Diagnostics;
+ using System.Collections.Generic;
+
+ public class MetricsHelper<T> where T : Metrics
+ {
+ public class AttributeResolver
+ {
+ private abstract class Resolver
+ {
+ protected Resolver(string name)
+ {
+ _name = name;
+ }
+
+ protected abstract object resolve(object obj);
+
+ public string resolveImpl(object obj)
+ {
+ try
+ {
+ object result = resolve(obj);
+ if(result != null)
+ {
+ return result.ToString();
+ }
+ return "";
+ }
+ catch(ArgumentOutOfRangeException ex)
+ {
+ throw ex;
+ }
+ catch(Exception ex)
+ {
+#if COMPACT
+ throw new ArgumentOutOfRangeException(_name, ex.ToString());
+#else
+ throw new ArgumentOutOfRangeException(_name, ex);
+#endif
+ }
+ }
+
+ readonly protected string _name;
+ };
+
+ class FieldResolverI : Resolver
+ {
+ internal FieldResolverI(string name, System.Reflection.FieldInfo field) : base(name)
+ {
+ Debug.Assert(field != null);
+ _field = field;
+ }
+
+ override protected object resolve(object obj)
+ {
+ return _field.GetValue(obj);
+ }
+
+ readonly private System.Reflection.FieldInfo _field;
+ };
+
+ class MethodResolverI : Resolver
+ {
+ internal MethodResolverI(string name, System.Reflection.MethodInfo method) : base(name)
+ {
+ Debug.Assert(method != null);
+ _method = method;
+ }
+
+ override protected object resolve(object obj)
+ {
+ return _method.Invoke(obj, null);
+ }
+
+ readonly private System.Reflection.MethodInfo _method;
+ };
+
+ class MemberFieldResolverI : Resolver
+ {
+ internal MemberFieldResolverI(string name, System.Reflection.MethodInfo method,
+ System.Reflection.FieldInfo field)
+ : base(name)
+ {
+ Debug.Assert(method != null && field != null);
+ _method = method;
+ _field = field;
+ }
+
+ override protected object resolve(object obj)
+ {
+ object o = _method.Invoke(obj, null);
+ if(o != null)
+ {
+ return _field.GetValue(o);
+ }
+ throw new ArgumentOutOfRangeException(_name);
+ }
+
+ readonly private System.Reflection.MethodInfo _method;
+ readonly private System.Reflection.FieldInfo _field;
+ };
+
+ class MemberMethodResolverI : Resolver
+ {
+ internal MemberMethodResolverI(string name, System.Reflection.MethodInfo method,
+ System.Reflection.MethodInfo subMeth)
+ : base(name)
+ {
+ Debug.Assert(method != null && subMeth != null);
+ _method = method;
+ _subMethod = subMeth;
+ }
+
+ override protected object resolve(object obj)
+ {
+ object o = _method.Invoke(obj, null);
+ if(o != null)
+ {
+ return _subMethod.Invoke(o, null);
+ }
+ throw new ArgumentOutOfRangeException(_name);
+ }
+
+ readonly private System.Reflection.MethodInfo _method;
+ readonly private System.Reflection.MethodInfo _subMethod;
+ };
+
+ protected AttributeResolver()
+ {
+ }
+
+ public string resolve(MetricsHelper<T> helper, string attribute)
+ {
+ Resolver resolver;
+ if(!_attributes.TryGetValue(attribute, out resolver))
+ {
+ if(attribute.Equals("none"))
+ {
+ return "";
+ }
+ string v = helper.defaultResolve(attribute);
+ if(v != null)
+ {
+ return v;
+ }
+ throw new ArgumentOutOfRangeException(attribute);
+ }
+ return resolver.resolveImpl(helper);
+ }
+
+ public void
+ add(string name, System.Reflection.MethodInfo method)
+ {
+ _attributes.Add(name, new MethodResolverI(name, method));
+ }
+
+ public void
+ add(string name, System.Reflection.FieldInfo field)
+ {
+ _attributes.Add(name, new FieldResolverI(name, field));
+ }
+
+ public void
+ add(string name, System.Reflection.MethodInfo method, System.Reflection.FieldInfo field)
+ {
+ _attributes.Add(name, new MemberFieldResolverI(name, method, field));
+ }
+
+ public void
+ add(string name, System.Reflection.MethodInfo method, System.Reflection.MethodInfo subMethod)
+ {
+ _attributes.Add(name, new MemberMethodResolverI(name, method, subMethod));
+ }
+
+ private Dictionary<string, Resolver> _attributes = new Dictionary<string, Resolver>();
+ };
+
+ protected MetricsHelper(AttributeResolver attributes)
+ {
+ _attributes = attributes;
+ }
+
+ public string resolve(string attribute)
+ {
+ return _attributes.resolve(this, attribute);
+ }
+
+ virtual public void initMetrics(T metrics)
+ {
+ // Override in specialized helpers.
+ }
+
+ virtual protected string defaultResolve(string attribute)
+ {
+ return null;
+ }
+
+ private AttributeResolver _attributes;
+ };
+
+ public class Observer<T> : Stopwatch, Ice.Instrumentation.Observer where T : Metrics, new()
+ {
+ public delegate void MetricsUpdate(T m);
+
+ virtual public void attach()
+ {
+ Start();
+ }
+
+ virtual public void detach()
+ {
+ Stop();
+ long lifetime = _previousDelay + (long)(ElapsedTicks / (Frequency / 1000000.0));
+ foreach(MetricsMap<T>.Entry e in _objects)
+ {
+ e.detach(lifetime);
+ }
+ }
+
+ virtual public void failed(string exceptionName)
+ {
+ foreach(MetricsMap<T>.Entry e in _objects)
+ {
+ e.failed(exceptionName);
+ }
+ }
+
+ public void forEach(MetricsUpdate u)
+ {
+ foreach(MetricsMap<T>.Entry e in _objects)
+ {
+ e.execute(u);
+ }
+ }
+
+ public void init(MetricsHelper<T> helper, List<MetricsMap<T>.Entry> objects, Observer<T> previous)
+ {
+ _objects = objects;
+
+ if(previous == null)
+ {
+ return;
+ }
+
+ _previousDelay = previous._previousDelay + (long)(previous.ElapsedTicks / (Frequency / 1000000.0));
+ foreach(MetricsMap<T>.Entry e in previous._objects)
+ {
+ if(!_objects.Contains(e))
+ {
+ e.detach(_previousDelay);
+ }
+ }
+ }
+
+ public ObserverImpl getObserver<S, ObserverImpl>(string mapName, MetricsHelper<S> helper)
+ where S : Metrics, new()
+ where ObserverImpl : Observer<S>, new()
+ {
+ List<MetricsMap<S>.Entry> metricsObjects = null;
+ foreach(MetricsMap<T>.Entry entry in _objects)
+ {
+ MetricsMap<S>.Entry e = entry.getMatching(mapName, helper);
+ if(e != null)
+ {
+ if(metricsObjects == null)
+ {
+ metricsObjects = new List<MetricsMap<S>.Entry>(_objects.Count);
+ }
+ metricsObjects.Add(e);
+ }
+ }
+
+ if(metricsObjects == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ ObserverImpl obsv = new ObserverImpl();
+ obsv.init(helper, metricsObjects, null);
+ return obsv;
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ return null;
+ }
+ }
+
+ public MetricsMap<T>.Entry getEntry(MetricsMap<T> map)
+ {
+ foreach(MetricsMap<T>.Entry e in _objects)
+ {
+ if(e.getMap() == map)
+ {
+ return e;
+ }
+ }
+ return null;
+ }
+
+ private List<MetricsMap<T>.Entry> _objects;
+ private long _previousDelay = 0;
+ };
+
+ public class ObserverFactory<T, O> where T : Metrics, new() where O : Observer<T>, new()
+ {
+ public ObserverFactory(IceInternal.MetricsAdminI metrics, string name)
+ {
+ _metrics = metrics;
+ _name = name;
+ _metrics.registerMap<T>(name, this.update);
+ }
+
+ public ObserverFactory(string name)
+ {
+ _name = name;
+ _metrics = null;
+ }
+
+ public void destroy()
+ {
+ if(_metrics != null)
+ {
+ _metrics.unregisterMap(_name);
+ }
+ }
+
+ public O getObserver(MetricsHelper<T> helper)
+ {
+ return getObserver(helper, null);
+ }
+
+ public O getObserver(MetricsHelper<T> helper, object observer)
+ {
+ lock(this)
+ {
+ List<MetricsMap<T>.Entry> metricsObjects = null;
+ O old = null;
+ try
+ {
+ old = (O)observer;
+ }
+ catch(InvalidCastException)
+ {
+ }
+ foreach(MetricsMap<T> m in _maps)
+ {
+ MetricsMap<T>.Entry e = m.getMatching(helper, old != null ? old.getEntry(m) : null);
+ if(e != null)
+ {
+ if(metricsObjects == null)
+ {
+ metricsObjects = new List<MetricsMap<T>.Entry>(_maps.Count);
+ }
+ metricsObjects.Add(e);
+ }
+ }
+
+ if(metricsObjects == null)
+ {
+ if(old != null)
+ {
+ old.detach();
+ }
+ return null;
+ }
+
+ O obsv;
+ try
+ {
+ obsv = new O();
+ }
+ catch(Exception)
+ {
+ Debug.Assert(false);
+ return null;
+ }
+ obsv.init(helper, metricsObjects, old);
+ return obsv;
+ }
+ }
+
+ public void registerSubMap<S>(string subMap, System.Reflection.FieldInfo field)
+ where S : Metrics, new()
+ {
+ _metrics.registerSubMap<S>(_name, subMap, field);
+ }
+
+ public bool isEnabled()
+ {
+ return _enabled;
+ }
+
+ public void update()
+ {
+#if COMPACT
+ Ice.VoidAction updater;
+#else
+ System.Action updater;
+#endif
+ lock(this)
+ {
+ _maps.Clear();
+ foreach(MetricsMap<T> m in _metrics.getMaps<T>(_name))
+ {
+ _maps.Add(m);
+ }
+ _enabled = _maps.Count > 0;
+ updater = _updater;
+ }
+
+ if(updater != null)
+ {
+ updater();
+ }
+ }
+
+#if COMPACT
+ public void setUpdater(Ice.VoidAction updater)
+#else
+ public void setUpdater(System.Action updater)
+#endif
+ {
+ lock(this)
+ {
+ _updater = updater;
+ }
+ }
+
+ private readonly IceInternal.MetricsAdminI _metrics;
+ private readonly string _name;
+ private List<MetricsMap<T>> _maps = new List<MetricsMap<T>>();
+ private volatile bool _enabled;
+#if COMPACT
+ private Ice.VoidAction _updater;
+#else
+ private System.Action _updater;
+#endif
+ };
+} \ No newline at end of file
diff --git a/csharp/src/Ice/Network.cs b/csharp/src/Ice/Network.cs
new file mode 100644
index 00000000000..413679340a4
--- /dev/null
+++ b/csharp/src/Ice/Network.cs
@@ -0,0 +1,1452 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Net;
+#if !COMPACT && !UNITY
+ using System.Net.NetworkInformation;
+#endif
+ using System.Net.Sockets;
+ using System.Runtime.InteropServices;
+ using System.Threading;
+ using System.Globalization;
+
+ public sealed class Network
+ {
+ // ProtocolSupport
+ public const int EnableIPv4 = 0;
+ public const int EnableIPv6 = 1;
+ public const int EnableBoth = 2;
+
+#if COMPACT
+ public static SocketError socketErrorCode(SocketException ex)
+ {
+ return (SocketError)ex.ErrorCode;
+ }
+#else
+ public static SocketError socketErrorCode(SocketException ex)
+ {
+ return ex.SocketErrorCode;
+ }
+#endif
+
+#if COMPACT
+ //
+ // SocketError enumeration isn't available with Silverlight
+ //
+ public enum SocketError
+ {
+ Interrupted = 10004, // A blocking Socket call was canceled.
+ //AccessDenied =10013, // An attempt was made to access a Socket in a way that is forbidden by its access permissions.
+ Fault = 10014, // An invalid pointer address was detected by the underlying socket provider.
+ InvalidArgument = 10022, // An invalid argument was supplied to a Socket member.
+ TooManyOpenSockets = 10024, // There are too many open sockets in the underlying socket provider.
+ WouldBlock = 10035, // An operation on a nonblocking socket cannot be completed immediately.
+ InProgress = 10036, // A blocking operation is in progress.
+ //AlreadyInProgress = 10037, // The nonblocking Socket already has an operation in progress.
+ //NotSocket = 10038, // A Socket operation was attempted on a non-socket.
+ //DestinationAddressRequired = 10039, // A required address was omitted from an operation on a Socket.
+ MessageSize = 10040, // The datagram is too long.
+ //ProtocolType = 10041, // The protocol type is incorrect for this Socket.
+ //ProtocolOption = 10042, // An unknown, invalid, or unsupported option or level was used with a Socket.
+ //ProtocolNotSupported = 10043, // The protocol is not implemented or has not been configured.
+ //SocketNotSupported = 10044, // The support for the specified socket type does not exist in this address family.
+ //OperationNotSupported = 10045, // The address family is not supported by the protocol family.
+ //ProtocolFamilyNotSupported = 10046, // The protocol family is not implemented or has not been configured.
+ //AddressFamilyNotSupported = 10047, // The address family specified is not supported.
+ //AddressAlreadyInUse = 10048, // Only one use of an address is normally permitted.
+ //AddressNotAvailable = 10049, // The selected IP address is not valid in this context.
+ NetworkDown = 10050, // The network is not available.
+ NetworkUnreachable = 10051, // No route to the remote host exists.
+ NetworkReset = 10052, // The application tried to set KeepAlive on a connection that has already timed out.
+ ConnectionAborted = 10053, // The connection was aborted by the .NET Framework or the underlying socket provider.
+ ConnectionReset = 10054, // The connection was reset by the remote peer.
+ NoBufferSpaceAvailable = 10055, // No free buffer space is available for a Socket operation.
+ //IsConnected = 10056, // The Socket is already connected.
+ NotConnected = 10057, // The application tried to send or receive data, and the Socket is not connected.
+ Shutdown = 10058, // A request to send or receive data was disallowed because the Socket has already been closed.
+ TimedOut = 10060, // The connection attempt timed out, or the connected host has failed to respond.
+ ConnectionRefused = 10061, // The remote host is actively refusing a connection.
+ //HostDown = 10064, // The operation failed because the remote host is down.
+ HostUnreachable = 10065, // There is no network route to the specified host.
+ //ProcessLimit = 10067, // Too many processes are using the underlying socket provider.
+ //SystemNotReady = 10091, // The network subsystem is unavailable.
+ //VersionNotSupported = 10092, // The version of the underlying socket provider is out of range.
+ //NotInitialized = 10093, // The underlying socket provider has not been initialized.
+ //Disconnecting = 10101, // A graceful shutdown is in progress.
+ //TypeNotFound = 10109, // The specified class was not found.
+ //HostNotFound = 11001, // No such host is known. The name is not an official host name or alias.
+ TryAgain = 11002, // The name of the host could not be resolved. Try again later.
+ //NoRecovery = 11003, // The error is unrecoverable or the requested database cannot be located.
+ //NoData = 11004, // The requested name or IP address was not found on the name server.
+ //IOPending = 997, // The application has initiated an overlapped operation that cannot be completed immediately.
+ OperationAborted =995 // The overlapped operation was aborted due to the closure of the Socket.
+ }
+#endif
+
+ public static bool interrupted(SocketException ex)
+ {
+ return socketErrorCode(ex) == SocketError.Interrupted;
+ }
+
+ public static bool acceptInterrupted(SocketException ex)
+ {
+ if(interrupted(ex))
+ {
+ return true;
+ }
+ SocketError error = socketErrorCode(ex);
+ return error == SocketError.ConnectionAborted ||
+ error == SocketError.ConnectionReset ||
+ error == SocketError.TimedOut;
+ }
+
+ public static bool noBuffers(SocketException ex)
+ {
+ SocketError error = socketErrorCode(ex);
+ return error == SocketError.NoBufferSpaceAvailable ||
+ error == SocketError.Fault;
+ }
+
+ public static bool wouldBlock(SocketException ex)
+ {
+ return socketErrorCode(ex) == SocketError.WouldBlock;
+ }
+
+ public static bool connectFailed(SocketException ex)
+ {
+ SocketError error = socketErrorCode(ex);
+ return error == SocketError.ConnectionRefused ||
+ error == SocketError.TimedOut ||
+ error == SocketError.NetworkUnreachable ||
+ error == SocketError.HostUnreachable ||
+ error == SocketError.ConnectionReset ||
+ error == SocketError.Shutdown ||
+ error == SocketError.ConnectionAborted ||
+ error == SocketError.NetworkDown;
+ }
+
+ public static bool connectInProgress(SocketException ex)
+ {
+ SocketError error = socketErrorCode(ex);
+ return error == SocketError.WouldBlock ||
+ error == SocketError.InProgress;
+ }
+
+ public static bool connectionLost(SocketException ex)
+ {
+ SocketError error = socketErrorCode(ex);
+ return error == SocketError.ConnectionReset ||
+ error == SocketError.Shutdown ||
+ error == SocketError.ConnectionAborted ||
+ error == SocketError.NetworkDown ||
+ error == SocketError.NetworkReset;
+ }
+
+ public static bool connectionLost(System.IO.IOException ex)
+ {
+ //
+ // In some cases the IOException has an inner exception that we can pass directly
+ // to the other overloading of connectionLost().
+ //
+ if(ex.InnerException != null && ex.InnerException is SocketException)
+ {
+ return connectionLost(ex.InnerException as SocketException);
+ }
+
+ //
+ // In other cases the IOException has no inner exception. We could examine the
+ // exception's message, but that is fragile due to localization issues. We
+ // resort to extracting the value of the protected HResult member via reflection.
+ //
+ int hr = (int)ex.GetType().GetProperty("HResult",
+ System.Reflection.BindingFlags.Instance |
+ System.Reflection.BindingFlags.NonPublic |
+ System.Reflection.BindingFlags.Public).GetValue(ex, null);
+
+ //
+ // This value corresponds to the following errors:
+ //
+ // "Authentication failed because the remote party has closed the transport stream"
+ //
+ if(hr == -2146232800)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool connectionRefused(SocketException ex)
+ {
+ return socketErrorCode(ex) == SocketError.ConnectionRefused;
+ }
+
+ public static bool notConnected(SocketException ex)
+ {
+ // BUGFIX: SocketError.InvalidArgument because shutdown() under OS X returns EINVAL
+ // if the server side is gone.
+ // BUGFIX: shutdown() under Vista might return SocketError.ConnectionReset
+ SocketError error = socketErrorCode(ex);
+ return error == SocketError.NotConnected ||
+ error == SocketError.InvalidArgument ||
+ error == SocketError.ConnectionReset;
+ }
+
+ public static bool recvTruncated(SocketException ex)
+ {
+ return socketErrorCode(ex) == SocketError.MessageSize;
+ }
+
+ public static bool operationAborted(SocketException ex)
+ {
+ return socketErrorCode(ex) == SocketError.OperationAborted;
+ }
+
+ public static bool timeout(System.IO.IOException ex)
+ {
+ //
+ // TODO: Instead of testing for an English substring, we need to examine the inner
+ // exception (if there is one).
+ //
+ return ex.Message.IndexOf("period of time", StringComparison.Ordinal) >= 0;
+ }
+
+ public static bool noMoreFds(System.Exception ex)
+ {
+ try
+ {
+ return ex != null && socketErrorCode((SocketException)ex) == SocketError.TooManyOpenSockets;
+ }
+ catch(InvalidCastException)
+ {
+ return false;
+ }
+ }
+
+ public static bool isMulticast(IPEndPoint addr)
+ {
+#if COMPACT
+ string ip = addr.Address.ToString().ToUpper();
+#else
+ string ip = addr.Address.ToString().ToUpperInvariant();
+#endif
+ if(addr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ char[] splitChars = { '.' };
+ string[] arr = ip.Split(splitChars);
+ try
+ {
+ int i = System.Int32.Parse(arr[0], CultureInfo.InvariantCulture);
+ if(i >= 223 && i <= 239)
+ {
+ return true;
+ }
+ }
+ catch(System.FormatException)
+ {
+ return false;
+ }
+ }
+ else // AddressFamily.InterNetworkV6
+ {
+ if(ip.StartsWith("FF", StringComparison.Ordinal))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static bool isIPv6Supported()
+ {
+ try
+ {
+ Socket socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
+ closeSocketNoThrow(socket);
+ return true;
+ }
+ catch(SocketException)
+ {
+ return false;
+ }
+ }
+
+ public static Socket createSocket(bool udp, AddressFamily family)
+ {
+ Socket socket;
+
+ try
+ {
+ if(udp)
+ {
+ socket = new Socket(family, SocketType.Dgram, ProtocolType.Udp);
+ }
+ else
+ {
+ socket = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
+ }
+ }
+ catch(SocketException ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+ catch(ArgumentException ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+
+
+ if(!udp)
+ {
+ try
+ {
+ setTcpNoDelay(socket);
+#if !SILVERLIGHT
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
+# if !__MonoCS__
+ setTcpLoopbackFastPath(socket);
+# endif
+#endif
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+ return socket;
+ }
+
+ public static Socket createServerSocket(bool udp, AddressFamily family, int protocol)
+ {
+ Socket socket = createSocket(udp, family);
+# if !COMPACT && !UNITY && !__MonoCS__ && !SILVERLIGHT && !DOTNET3_5
+ //
+ // The IPv6Only enumerator was added in .NET 4.
+ //
+ if(family == AddressFamily.InterNetworkV6 && protocol != EnableIPv4)
+ {
+ try
+ {
+ int flag = protocol == EnableIPv6 ? 1 : 0;
+ socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, flag);
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+#endif
+ return socket;
+ }
+
+ public static void closeSocketNoThrow(Socket socket)
+ {
+ if(socket == null)
+ {
+ return;
+ }
+ try
+ {
+ socket.Close();
+ }
+ catch(SocketException)
+ {
+ // Ignore
+ }
+ }
+
+ public static void closeSocket(Socket socket)
+ {
+ if(socket == null)
+ {
+ return;
+ }
+ try
+ {
+ socket.Close();
+ }
+ catch(SocketException ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public static void setTcpNoDelay(Socket socket)
+ {
+ try
+ {
+#if SILVERLIGHT
+ socket.NoDelay = true;
+#else
+ socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1);
+#endif
+ }
+ catch(System.Exception ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+#if !SILVERLIGHT
+ public static void setTcpLoopbackFastPath(Socket socket)
+ {
+ const int SIO_LOOPBACK_FAST_PATH = (-1744830448);
+
+ Byte[] OptionInValue = BitConverter.GetBytes(1);
+ try
+ {
+ socket.IOControl(SIO_LOOPBACK_FAST_PATH, OptionInValue, null);
+ }
+ catch(System.Exception)
+ {
+ // Expected on platforms that do not support TCP Loopback Fast Path
+ }
+ }
+
+ public static void setBlock(Socket socket, bool block)
+ {
+ try
+ {
+ socket.Blocking = block;
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public static void setKeepAlive(Socket socket)
+ {
+ try
+ {
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
+ }
+ catch(System.Exception ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+#endif
+
+ public static void setSendBufferSize(Socket socket, int sz)
+ {
+ try
+ {
+#if SILVERLIGHT
+ socket.SendBufferSize = sz;
+#else
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, sz);
+#endif
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public static int getSendBufferSize(Socket socket)
+ {
+ int sz;
+ try
+ {
+#if SILVERLIGHT
+ sz = socket.SendBufferSize;
+#else
+ sz = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
+#endif
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ return sz;
+ }
+
+ public static void setRecvBufferSize(Socket socket, int sz)
+ {
+ try
+ {
+#if SILVERLIGHT
+ socket.ReceiveBufferSize = sz;
+#else
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, sz);
+#endif
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public static int getRecvBufferSize(Socket socket)
+ {
+ int sz = 0;
+ try
+ {
+#if SILVERLIGHT
+ sz = socket.ReceiveBufferSize;
+#else
+ sz = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
+#endif
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ return sz;
+ }
+
+#if !SILVERLIGHT
+ public static void setReuseAddress(Socket socket, bool reuse)
+ {
+ try
+ {
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuse ? 1 : 0);
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public static void setMcastGroup(Socket s, IPAddress group, string iface)
+ {
+ try
+ {
+ int index = getInterfaceIndex(iface, group.AddressFamily);
+ if(group.AddressFamily == AddressFamily.InterNetwork)
+ {
+ MulticastOption option;
+#if COMPACT
+ option = new MulticastOption(group);
+#else
+ if(index == -1)
+ {
+ option = new MulticastOption(group);
+ }
+
+ else
+ {
+ option = new MulticastOption(group, index);
+ }
+#endif
+ s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, option);
+ }
+ else
+ {
+ IPv6MulticastOption option;
+ if(index == -1)
+ {
+ option = new IPv6MulticastOption(group);
+ }
+ else
+ {
+ option = new IPv6MulticastOption(group, index);
+ }
+ s.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, option);
+ }
+ }
+ catch(Exception ex)
+ {
+ closeSocketNoThrow(s);
+ throw new Ice.SocketException(ex);
+ }
+ }
+#endif
+
+ public static void setMcastTtl(Socket socket, int ttl, AddressFamily family)
+ {
+ try
+ {
+#if SILVERLIGHT
+ socket.Ttl = (short)ttl;
+#else
+ if(family == AddressFamily.InterNetwork)
+ {
+ socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, ttl);
+ }
+ else
+ {
+ socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive, ttl);
+ }
+#endif
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+#if !SILVERLIGHT
+ public static IPEndPoint doBind(Socket socket, EndPoint addr)
+ {
+ try
+ {
+ socket.Bind(addr);
+ return (IPEndPoint)socket.LocalEndPoint;
+ }
+ catch(SocketException ex)
+ {
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public static void doListen(Socket socket, int backlog)
+ {
+
+ repeatListen:
+
+ try
+ {
+ socket.Listen(backlog);
+ }
+ catch(SocketException ex)
+ {
+ if(interrupted(ex))
+ {
+ goto repeatListen;
+ }
+
+ closeSocketNoThrow(socket);
+ throw new Ice.SocketException(ex);
+ }
+ }
+#endif
+
+#if !SILVERLIGHT
+ public static bool doConnect(Socket fd, EndPoint addr, EndPoint sourceAddr)
+ {
+ EndPoint bindAddr = sourceAddr;
+ if(bindAddr == null)
+ {
+ //
+ // Even though we are on the client side, the call to Bind()
+ // is necessary to work around a .NET bug: if a socket is
+ // connected non-blocking, the LocalEndPoint and RemoteEndPoint
+ // properties are null. The call to Bind() fixes this.
+ //
+ IPAddress any = fd.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any;
+ bindAddr = new IPEndPoint(any, 0);
+ }
+ doBind(fd, bindAddr);
+
+ repeatConnect:
+ try
+ {
+ IAsyncResult result = fd.BeginConnect(addr, null, null);
+ if(!result.CompletedSynchronously)
+ {
+ return false;
+ }
+ fd.EndConnect(result);
+ }
+ catch(SocketException ex)
+ {
+ if(interrupted(ex))
+ {
+ goto repeatConnect;
+ }
+
+ closeSocketNoThrow(fd);
+
+ if(connectionRefused(ex))
+ {
+ throw new Ice.ConnectionRefusedException(ex);
+ }
+ else
+ {
+ throw new Ice.ConnectFailedException(ex);
+ }
+ }
+
+ //
+ // On Windows, we need to set the socket's blocking status again
+ // after the asynchronous connect. Seems like a bug in .NET.
+ //
+ setBlock(fd, fd.Blocking);
+
+ if(AssemblyUtil.platform_ == AssemblyUtil.Platform.NonWindows)
+ {
+ //
+ // Prevent self connect (self connect happens on Linux when a client tries to connect to
+ // a server which was just deactivated if the client socket re-uses the same ephemeral
+ // port as the server).
+ //
+ if(addr.Equals(getLocalAddress(fd)))
+ {
+ throw new Ice.ConnectionRefusedException();
+ }
+ }
+ return true;
+ }
+
+ public static IAsyncResult doConnectAsync(Socket fd, EndPoint addr, EndPoint sourceAddr, AsyncCallback callback,
+ object state)
+ {
+ //
+ // NOTE: It's the caller's responsability to close the socket upon
+ // failure to connect. The socket isn't closed by this method.
+ //
+ EndPoint bindAddr = sourceAddr;
+ if(bindAddr == null)
+ {
+ //
+ // Even though we are on the client side, the call to Bind()
+ // is necessary to work around a .NET bug: if a socket is
+ // connected non-blocking, the LocalEndPoint and RemoteEndPoint
+ // properties are null. The call to Bind() fixes this.
+ //
+ IPAddress any = fd.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any;
+ bindAddr = new IPEndPoint(any, 0);
+ }
+ fd.Bind(bindAddr);
+
+ repeatConnect:
+ try
+ {
+ return fd.BeginConnect(addr,
+ delegate(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ callback(result.AsyncState);
+ }
+ }, state);
+ }
+ catch(SocketException ex)
+ {
+ if(interrupted(ex))
+ {
+ goto repeatConnect;
+ }
+
+ if(connectionRefused(ex))
+ {
+ throw new Ice.ConnectionRefusedException(ex);
+ }
+ else
+ {
+ throw new Ice.ConnectFailedException(ex);
+ }
+ }
+ }
+
+ public static void doFinishConnectAsync(Socket fd, IAsyncResult result)
+ {
+ //
+ // NOTE: It's the caller's responsability to close the socket upon
+ // failure to connect. The socket isn't closed by this method.
+ //
+ try
+ {
+ fd.EndConnect(result);
+ }
+ catch(SocketException ex)
+ {
+ if(connectionRefused(ex))
+ {
+ throw new Ice.ConnectionRefusedException(ex);
+ }
+ else
+ {
+ throw new Ice.ConnectFailedException(ex);
+ }
+ }
+
+ //
+ // On Windows, we need to set the socket's blocking status again
+ // after the asynchronous connect. Seems like a bug in .NET.
+ //
+ setBlock(fd, fd.Blocking);
+
+ if(AssemblyUtil.platform_ == AssemblyUtil.Platform.NonWindows)
+ {
+ //
+ // Prevent self connect (self connect happens on Linux when a client tries to connect to
+ // a server which was just deactivated if the client socket re-uses the same ephemeral
+ // port as the server).
+ //
+ EndPoint remoteAddr = getRemoteAddress(fd);
+ if(remoteAddr != null && remoteAddr.Equals(getLocalAddress(fd)))
+ {
+ throw new Ice.ConnectionRefusedException();
+ }
+ }
+ }
+#endif
+
+ public static EndPoint getAddressForServer(string host, int port, int protocol, bool preferIPv6)
+ {
+ if(host.Length == 0)
+ {
+ if(protocol != EnableIPv4)
+ {
+ return new IPEndPoint(IPAddress.IPv6Any, port);
+ }
+ else
+ {
+ return new IPEndPoint(IPAddress.Any, port);
+ }
+ }
+ return getAddresses(host, port, protocol, Ice.EndpointSelectionType.Ordered, preferIPv6, true)[0];
+ }
+
+ public static List<EndPoint> getAddresses(string host, int port, int protocol,
+ Ice.EndpointSelectionType selType, bool preferIPv6, bool blocking)
+ {
+ List<EndPoint> addresses = new List<EndPoint>();
+ if(host.Length == 0)
+ {
+ if(protocol != EnableIPv4)
+ {
+ addresses.Add(new IPEndPoint(IPAddress.IPv6Loopback, port));
+ }
+
+ if(protocol != EnableIPv6)
+ {
+ addresses.Add(new IPEndPoint(IPAddress.Loopback, port));
+ }
+ return addresses;
+ }
+
+
+ int retry = 5;
+
+ repeatGetHostByName:
+ try
+ {
+ //
+ // No need for lookup if host is ip address.
+ //
+ try
+ {
+ IPAddress addr = IPAddress.Parse(host);
+ if((addr.AddressFamily == AddressFamily.InterNetwork && protocol != EnableIPv6) ||
+ (addr.AddressFamily == AddressFamily.InterNetworkV6 && protocol != EnableIPv4))
+ {
+ addresses.Add(new IPEndPoint(addr, port));
+ return addresses;
+ }
+ else
+ {
+ Ice.DNSException e = new Ice.DNSException();
+ e.host = host;
+ throw e;
+ }
+ }
+ catch(FormatException)
+ {
+#if !SILVERLIGHT
+ if(!blocking)
+ {
+ return addresses;
+ }
+#endif
+ }
+
+#if SILVERLIGHT
+ if(protocol != EnableIPv6)
+ {
+ addresses.Add(new DnsEndPoint(host, port, AddressFamily.InterNetwork));
+ }
+ if(protocol != EnableIPv4)
+ {
+ addresses.Add(new DnsEndPoint(host, port, AddressFamily.InterNetworkV6));
+ }
+#else
+# if COMPACT
+ foreach(IPAddress a in Dns.GetHostEntry(host).AddressList)
+# else
+ foreach(IPAddress a in Dns.GetHostAddresses(host))
+# endif
+ {
+ if((a.AddressFamily == AddressFamily.InterNetwork && protocol != EnableIPv6) ||
+ (a.AddressFamily == AddressFamily.InterNetworkV6 && protocol != EnableIPv4))
+ {
+ addresses.Add(new IPEndPoint(a, port));
+ }
+ }
+#endif
+
+ if(selType == Ice.EndpointSelectionType.Random)
+ {
+ IceUtilInternal.Collections.Shuffle(ref addresses);
+ }
+
+ if(protocol == EnableBoth)
+ {
+ if(preferIPv6)
+ {
+ IceUtilInternal.Collections.Sort(ref addresses, _preferIPv6Comparator);
+ }
+ else
+ {
+ IceUtilInternal.Collections.Sort(ref addresses, _preferIPv4Comparator);
+ }
+ }
+ }
+ catch(SocketException ex)
+ {
+ if(socketErrorCode(ex) == SocketError.TryAgain && --retry >= 0)
+ {
+ goto repeatGetHostByName;
+ }
+ Ice.DNSException e = new Ice.DNSException(ex);
+ e.host = host;
+ throw e;
+ }
+ catch(System.Exception ex)
+ {
+ Ice.DNSException e = new Ice.DNSException(ex);
+ e.host = host;
+ throw e;
+ }
+
+ //
+ // No InterNetwork/InterNetworkV6 available.
+ //
+ if(addresses.Count == 0)
+ {
+ Ice.DNSException e = new Ice.DNSException();
+ e.host = host;
+ throw e;
+ }
+ return addresses;
+ }
+
+ public static IPAddress[] getLocalAddresses(int protocol, bool includeLoopback)
+ {
+#if SILVERLIGHT
+ return new List<IPAddress>().ToArray();
+#else
+ List<IPAddress> addresses;
+ int retry = 5;
+
+ repeatGetHostByName:
+ try
+ {
+ addresses = new List<IPAddress>();
+# if !COMPACT && !UNITY
+ NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
+ foreach(NetworkInterface ni in nics)
+ {
+ IPInterfaceProperties ipProps = ni.GetIPProperties();
+ UnicastIPAddressInformationCollection uniColl = ipProps.UnicastAddresses;
+ foreach(UnicastIPAddressInformation uni in uniColl)
+ {
+ if((uni.Address.AddressFamily == AddressFamily.InterNetwork && protocol != EnableIPv6) ||
+ (uni.Address.AddressFamily == AddressFamily.InterNetworkV6 && protocol != EnableIPv4))
+ {
+ if(includeLoopback || !IPAddress.IsLoopback(uni.Address))
+ {
+ addresses.Add(uni.Address);
+ }
+ }
+ }
+ }
+# else
+# if COMPACT
+ foreach(IPAddress a in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
+# else
+ foreach(IPAddress a in Dns.GetHostAddresses(Dns.GetHostName()))
+# endif
+ {
+ if((a.AddressFamily == AddressFamily.InterNetwork && protocol != EnableIPv6) ||
+ (a.AddressFamily == AddressFamily.InterNetworkV6 && protocol != EnableIPv4))
+ {
+ if(includeLoopback || !IPAddress.IsLoopback(a))
+ {
+ addresses.Add(a);
+ }
+ }
+ }
+# endif
+ }
+ catch(SocketException ex)
+ {
+ if(socketErrorCode(ex) == SocketError.TryAgain && --retry >= 0)
+ {
+ goto repeatGetHostByName;
+ }
+ Ice.DNSException e = new Ice.DNSException(ex);
+ e.host = "0.0.0.0";
+ throw e;
+ }
+ catch(System.Exception ex)
+ {
+ Ice.DNSException e = new Ice.DNSException(ex);
+ e.host = "0.0.0.0";
+ throw e;
+ }
+
+ return addresses.ToArray();
+#endif
+ }
+
+ public static bool
+ isLinklocal(IPAddress addr)
+ {
+ if (addr.IsIPv6LinkLocal)
+ {
+ return true;
+ }
+ else if (addr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ Byte[] bytes = addr.GetAddressBytes();
+ return bytes[0] == 169 && bytes[1] == 254;
+ }
+ return false;
+ }
+
+ public static void
+ setTcpBufSize(Socket socket, ProtocolInstance instance)
+ {
+ //
+ // By default, on Windows we use a 128KB buffer size. On Unix
+ // platforms, we use the system defaults.
+ //
+ int dfltBufSize = 0;
+ if(AssemblyUtil.platform_ == AssemblyUtil.Platform.Windows)
+ {
+ dfltBufSize = 128 * 1024;
+ }
+
+ int rcvSize = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.RcvSize", dfltBufSize);
+ int sndSize = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.SndSize", dfltBufSize);
+
+ setTcpBufSize(socket, rcvSize, sndSize, instance);
+ }
+
+ public static void
+ setTcpBufSize(Socket socket, int rcvSize, int sndSize, ProtocolInstance instance)
+ {
+ if(rcvSize > 0)
+ {
+ //
+ // Try to set the buffer size. The kernel will silently adjust
+ // the size to an acceptable value. Then read the size back to
+ // get the size that was actually set.
+ //
+ setRecvBufferSize(socket, rcvSize);
+ int size = getRecvBufferSize(socket);
+ if(size < rcvSize)
+ {
+ // Warn if the size that was set is less than the requested size and
+ // we have not already warned.
+ BufSizeWarnInfo winfo = instance.getBufSizeWarn(Ice.TCPEndpointType.value);
+ if(!winfo.rcvWarn || rcvSize != winfo.rcvSize)
+ {
+ instance.logger().warning("TCP receive buffer size: requested size of " + rcvSize +
+ " adjusted to " + size);
+ instance.setRcvBufSizeWarn(Ice.TCPEndpointType.value, rcvSize);
+ }
+ }
+ }
+
+ if(sndSize > 0)
+ {
+ //
+ // Try to set the buffer size. The kernel will silently adjust
+ // the size to an acceptable value. Then read the size back to
+ // get the size that was actually set.
+ //
+ setSendBufferSize(socket, sndSize);
+ int size = getSendBufferSize(socket);
+ if(size < sndSize) // Warn if the size that was set is less than the requested size.
+ {
+ // Warn if the size that was set is less than the requested size and
+ // we have not already warned.
+ BufSizeWarnInfo winfo = instance.getBufSizeWarn(Ice.TCPEndpointType.value);
+ if(!winfo.sndWarn || sndSize != winfo.sndSize)
+ {
+ instance.logger().warning("TCP send buffer size: requested size of " + sndSize +
+ " adjusted to " + size);
+ instance.setSndBufSizeWarn(Ice.TCPEndpointType.value, sndSize);
+ }
+ }
+ }
+ }
+
+ public static List<string> getHostsForEndpointExpand(string host, int protocol, bool includeLoopback)
+ {
+ bool wildcard = host.Length == 0;
+ bool ipv4Wildcard = false;
+ if(!wildcard)
+ {
+ try
+ {
+ IPAddress addr = IPAddress.Parse(host);
+ ipv4Wildcard = addr.Equals(IPAddress.Any);
+ wildcard = ipv4Wildcard || addr.Equals(IPAddress.IPv6Any);
+ }
+ catch(Exception)
+ {
+ }
+ }
+
+ List<string> hosts = new List<string>();
+ if(wildcard)
+ {
+ IPAddress[] addrs =
+ getLocalAddresses(ipv4Wildcard ? Network.EnableIPv4 : protocol, includeLoopback);
+ foreach(IPAddress a in addrs)
+ {
+#if COMPACT
+ if(!IPAddress.IsLoopback(a))
+#else
+ if(!isLinklocal(a))
+#endif
+ {
+ hosts.Add(a.ToString());
+ }
+ }
+ }
+ return hosts;
+ }
+
+ public static string fdToString(Socket socket, NetworkProxy proxy, EndPoint target)
+ {
+ try
+ {
+ if(socket == null)
+ {
+ return "<closed>";
+ }
+
+ EndPoint remote = getRemoteAddress(socket);
+
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("local address = " + localAddrToString(getLocalAddress(socket)));
+ if(proxy != null)
+ {
+ if(remote == null)
+ {
+ remote = proxy.getAddress();
+ }
+ s.Append("\n" + proxy.getName() + " proxy address = " + remoteAddrToString(remote));
+ s.Append("\nremote address = " + remoteAddrToString(target));
+ }
+ else
+ {
+ if(remote == null)
+ {
+ remote = target;
+ }
+ s.Append("\nremote address = " + remoteAddrToString(remote));
+ }
+ return s.ToString();
+ }
+ catch(ObjectDisposedException)
+ {
+ return "<closed>";
+ }
+ }
+
+ public static string fdToString(Socket socket)
+ {
+ try
+ {
+ if(socket == null)
+ {
+ return "<closed>";
+ }
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("local address = " + localAddrToString(getLocalAddress(socket)));
+ s.Append("\nremote address = " + remoteAddrToString(getRemoteAddress(socket)));
+ return s.ToString();
+ }
+ catch(ObjectDisposedException)
+ {
+ return "<closed>";
+ }
+ }
+
+ public static string fdLocalAddressToString(Socket socket)
+ {
+ return "local address = " + localAddrToString(getLocalAddress(socket));
+ }
+
+ public static string
+ addrToString(EndPoint addr)
+ {
+ return endpointAddressToString(addr) + ":" + endpointPort(addr);
+ }
+
+ public static string
+ localAddrToString(EndPoint endpoint)
+ {
+ if(endpoint == null)
+ {
+#if SILVERLIGHT
+ return "<not available>";
+#else
+ return "<not bound>";
+#endif
+ }
+ return endpointAddressToString(endpoint) + ":" + endpointPort(endpoint);
+ }
+
+ public static string
+ remoteAddrToString(EndPoint endpoint)
+ {
+ if(endpoint == null)
+ {
+ return "<not connected>";
+ }
+ return endpointAddressToString(endpoint) + ":" + endpointPort(endpoint);
+ }
+
+ public static EndPoint
+ getLocalAddress(Socket socket)
+ {
+ // Silverlight socket doesn't exposes a local endpoint
+#if !SILVERLIGHT
+ try
+ {
+ return socket.LocalEndPoint;
+ }
+ catch(SocketException ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+#else
+ return null;
+#endif
+ }
+
+ public static EndPoint
+ getRemoteAddress(Socket socket)
+ {
+ try
+ {
+ return (EndPoint)socket.RemoteEndPoint;
+ }
+ catch(SocketException)
+ {
+ }
+ return null;
+ }
+
+ private static int
+ getInterfaceIndex(string iface, AddressFamily family)
+ {
+ if(iface.Length == 0)
+ {
+ return -1;
+ }
+
+ //
+ // The iface parameter must either be an IP address, an
+ // index or the name of an interface. If it's an index we
+ // just return it. If it's an IP addess we search for an
+ // interface which has this IP address. If it's a name we
+ // search an interface with this name.
+ //
+ try
+ {
+ return System.Int32.Parse(iface, CultureInfo.InvariantCulture);
+ }
+ catch(System.FormatException)
+ {
+ }
+
+#if !COMPACT && !SILVERLIGHT && !UNITY
+ NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
+ try
+ {
+ IPAddress addr = IPAddress.Parse(iface);
+ foreach(NetworkInterface ni in nics)
+ {
+ IPInterfaceProperties ipProps = ni.GetIPProperties();
+ foreach(UnicastIPAddressInformation uni in ipProps.UnicastAddresses)
+ {
+ if(uni.Address.Equals(addr))
+ {
+ if(addr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ IPv4InterfaceProperties ipv4Props = ipProps.GetIPv4Properties();
+ if(ipv4Props != null)
+ {
+ return ipv4Props.Index;
+ }
+ }
+ else
+ {
+ IPv6InterfaceProperties ipv6Props = ipProps.GetIPv6Properties();
+ if(ipv6Props != null)
+ {
+ return ipv6Props.Index;
+ }
+ }
+ }
+ }
+ }
+ }
+ catch(FormatException)
+ {
+ }
+
+ foreach(NetworkInterface ni in nics)
+ {
+ if(ni.Name == iface)
+ {
+ IPInterfaceProperties ipProps = ni.GetIPProperties();
+ if(family == AddressFamily.InterNetwork)
+ {
+ IPv4InterfaceProperties ipv4Props = ipProps.GetIPv4Properties();
+ if(ipv4Props != null)
+ {
+ return ipv4Props.Index;
+ }
+ }
+ else
+ {
+ IPv6InterfaceProperties ipv6Props = ipProps.GetIPv6Properties();
+ if(ipv6Props != null)
+ {
+ return ipv6Props.Index;
+ }
+ }
+ }
+ }
+#endif
+ return -1;
+ }
+
+ public static EndPoint
+ getNumericAddress(string sourceAddress)
+ {
+ EndPoint addr = null;
+ if(!String.IsNullOrEmpty(sourceAddress))
+ {
+ List<EndPoint> addrs = getAddresses(sourceAddress, 0, Network.EnableBoth,
+ Ice.EndpointSelectionType.Ordered, false, false);
+ if(addrs.Count != 0)
+ {
+ return addrs[0];
+ }
+ }
+ return addr;
+ }
+
+ public static bool
+ addressEquals(EndPoint addr1, EndPoint addr2)
+ {
+ if(addr1 == null)
+ {
+ if(addr2 == null)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if(addr2 == null)
+ {
+ return false;
+ }
+
+ return addr1.Equals(addr2);
+ }
+
+ public static string
+ endpointAddressToString(EndPoint endpoint)
+ {
+ if(endpoint != null)
+ {
+#if SILVERLIGHT
+ if(endpoint is DnsEndPoint)
+ {
+ DnsEndPoint dnsEndpoint = (DnsEndPoint)endpoint;
+ return dnsEndpoint.Host;
+ }
+#endif
+ if(endpoint is IPEndPoint)
+ {
+ IPEndPoint ipEndpoint = (IPEndPoint) endpoint;
+ return ipEndpoint.Address.ToString();
+ }
+ }
+ return "";
+ }
+
+ public static int
+ endpointPort(EndPoint endpoint)
+ {
+ if(endpoint != null)
+ {
+#if SILVERLIGHT
+ if(endpoint is DnsEndPoint)
+ {
+ DnsEndPoint dnsEndpoint = (DnsEndPoint)endpoint;
+ return dnsEndpoint.Port;
+ }
+#endif
+ if(endpoint is IPEndPoint)
+ {
+ IPEndPoint ipEndpoint = (IPEndPoint) endpoint;
+ return ipEndpoint.Port;
+ }
+ }
+ return -1;
+ }
+
+ private class EndPointComparator : IComparer<EndPoint>
+ {
+ public EndPointComparator(bool ipv6)
+ {
+ _ipv6 = ipv6;
+ }
+
+ public int Compare(EndPoint lhs, EndPoint rhs)
+ {
+ if(lhs.AddressFamily == AddressFamily.InterNetwork &&
+ rhs.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ return _ipv6 ? 1 : -1;
+ }
+ else if(lhs.AddressFamily == AddressFamily.InterNetworkV6 &&
+ rhs.AddressFamily == AddressFamily.InterNetwork)
+ {
+ return _ipv6 ? -1 : 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ private bool _ipv6;
+ }
+
+ private readonly static EndPointComparator _preferIPv4Comparator = new EndPointComparator(false);
+ private readonly static EndPointComparator _preferIPv6Comparator = new EndPointComparator(true);
+ }
+}
diff --git a/csharp/src/Ice/NetworkProxy.cs b/csharp/src/Ice/NetworkProxy.cs
new file mode 100644
index 00000000000..6e4a3ed9ffa
--- /dev/null
+++ b/csharp/src/Ice/NetworkProxy.cs
@@ -0,0 +1,311 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Diagnostics;
+ using System.Text;
+
+ public interface NetworkProxy
+ {
+ //
+ // Write the connection request on the connection established
+ // with the network proxy server. This is called right after
+ // the connection establishment succeeds.
+ //
+ void beginWrite(EndPoint endpoint, Buffer buf);
+ int endWrite(Buffer buf);
+
+ //
+ // Once the connection request has been sent, this is called
+ // to prepare and read the response from the proxy server.
+ //
+ void beginRead(Buffer buf);
+ int endRead(Buffer buf);
+
+ //
+ // This is called when the response from the proxy has been
+ // read. The proxy should copy the extra read data (if any) in the
+ // given byte vector.
+ //
+ void finish(Buffer readBuffer, Buffer writeBuffer);
+
+#if !SILVERLIGHT
+ //
+ // If the proxy host needs to be resolved, this should return
+ // a new NetworkProxy containing the IP address of the proxy.
+ // This is called from the endpoint host resolver thread, so
+ // it's safe if this this method blocks.
+ //
+ NetworkProxy resolveHost(int protocolSupport);
+#endif
+ //
+ // Returns the IP address of the network proxy. This method
+ // must not block. It's only called on a network proxy object
+ // returned by resolveHost().
+ //
+ EndPoint getAddress();
+
+ //
+ // Returns the name of the proxy, used for tracing purposes.
+ //
+ string getName();
+
+ //
+ // Returns the protocols supported by the proxy.
+ //
+ int getProtocolSupport();
+ }
+
+ public sealed class SOCKSNetworkProxy : NetworkProxy
+ {
+ public SOCKSNetworkProxy(string host, int port)
+ {
+#if SILVERLIGHT
+ _address = new DnsEndPoint(host, port, AddressFamily.InterNetwork);
+#else
+ _host = host;
+ _port = port;
+#endif
+ }
+
+ private SOCKSNetworkProxy(EndPoint address)
+ {
+ _address = address;
+ }
+
+ public void beginWrite(EndPoint endpoint, Buffer buf)
+ {
+ if(!(endpoint is IPEndPoint))
+ {
+ throw new Ice.FeatureNotSupportedException("SOCKS4 does not support domain names");
+ }
+ else if(endpoint.AddressFamily != AddressFamily.InterNetwork)
+ {
+ throw new Ice.FeatureNotSupportedException("SOCKS4 only supports IPv4 addresses");
+ }
+
+ //
+ // SOCKS connect request
+ //
+ IPEndPoint addr = (IPEndPoint)endpoint;
+ buf.resize(9, false);
+ ByteBuffer.ByteOrder order = buf.b.order();
+ buf.b.order(ByteBuffer.ByteOrder.BIG_ENDIAN); // Network byte order.
+ buf.b.position(0);
+ buf.b.put(0x04); // SOCKS version 4.
+ buf.b.put(0x01); // Command, establish a TCP/IP stream connection
+ buf.b.putShort((short)addr.Port); // Port
+ buf.b.put(addr.Address.GetAddressBytes()); // IPv4 address
+ buf.b.put(0x00); // User ID.
+ buf.b.position(0);
+ buf.b.limit(buf.size());
+ buf.b.order(order);
+ }
+
+ public int endWrite(Buffer buf)
+ {
+ // Once the request is sent, read the response
+ return buf.b.hasRemaining() ? SocketOperation.Write : SocketOperation.Read;
+ }
+
+ public void beginRead(Buffer buf)
+ {
+ //
+ // Read the SOCKS4 response whose size is 8 bytes.
+ //
+ buf.resize(8, true);
+ buf.b.position(0);
+ }
+
+ public int endRead(Buffer buf)
+ {
+ // We're done once we read the response
+ return buf.b.hasRemaining() ? SocketOperation.Read : SocketOperation.None;
+ }
+
+ public void finish(Buffer readBuffer, Buffer writeBuffer)
+ {
+ readBuffer.b.position(0);
+ byte b1 = readBuffer.b.get();
+ byte b2 = readBuffer.b.get();
+ if(b1 != 0x00 || b2 != 0x5a)
+ {
+ throw new Ice.ConnectFailedException();
+ }
+ }
+
+#if !SILVERLIGHT
+ public NetworkProxy resolveHost(int protocolSupport)
+ {
+ Debug.Assert(_host != null);
+ return new SOCKSNetworkProxy(Network.getAddresses(_host,
+ _port,
+ protocolSupport,
+ Ice.EndpointSelectionType.Random,
+ false,
+ true)[0]);
+ }
+#endif
+
+ public EndPoint getAddress()
+ {
+ Debug.Assert(_address != null); // Host must be resolved.
+ return _address;
+ }
+
+ public string getName()
+ {
+ return "SOCKS";
+ }
+
+ public int getProtocolSupport()
+ {
+ return Network.EnableIPv4;
+ }
+
+#if !SILVERLIGHT
+ private readonly string _host;
+ private readonly int _port;
+#endif
+ private readonly EndPoint _address;
+ }
+
+ public sealed class HTTPNetworkProxy : NetworkProxy
+ {
+ public HTTPNetworkProxy(string host, int port)
+ {
+#if SILVERLIGHT
+ _address = new DnsEndPoint(host, port, AddressFamily.InterNetwork);
+ _protocolSupport = Network.EnableIPv4;
+#else
+ _host = host;
+ _port = port;
+ _protocolSupport = Network.EnableBoth;
+#endif
+ }
+
+ private HTTPNetworkProxy(EndPoint address, int protocolSupport)
+ {
+ _address = address;
+ _protocolSupport = protocolSupport;
+ }
+
+ public void beginWrite(EndPoint endpoint, Buffer buf)
+ {
+ string addr = Network.addrToString(endpoint);
+ StringBuilder str = new StringBuilder();
+ str.Append("CONNECT ");
+ str.Append(addr);
+ str.Append(" HTTP/1.1\r\nHost: ");
+ str.Append(addr);
+ str.Append("\r\n\r\n");
+
+#if SILVERLIGHT
+ byte[] b = System.Text.Encoding.UTF8.GetBytes(str.ToString());
+#else
+ byte[] b = System.Text.Encoding.ASCII.GetBytes(str.ToString());
+#endif
+
+ //
+ // HTTP connect request
+ //
+ buf.resize(b.Length, false);
+ buf.b.position(0);
+ buf.b.put(b);
+ buf.b.position(0);
+ buf.b.limit(buf.size());
+ }
+
+ public int endWrite(Buffer buf)
+ {
+ // Once the request is sent, read the response
+ return buf.b.hasRemaining() ? SocketOperation.Write : SocketOperation.Read;
+ }
+
+ public void beginRead(Buffer buf)
+ {
+ //
+ // Read the HTTP response
+ //
+ buf.resize(7, true); // Enough space for reading at least HTTP1.1
+ buf.b.position(0);
+ }
+
+ public int endRead(Buffer buf)
+ {
+ //
+ // Check if we received the full HTTP response, if not, continue
+ // reading otherwise we're done.
+ //
+ int end = new HttpParser().isCompleteMessage(buf.b, 0, buf.b.position());
+ if(end < 0 && !buf.b.hasRemaining())
+ {
+ //
+ // Read one more byte, we can't easily read bytes in advance
+ // since the transport implenentation might be be able to read
+ // the data from the memory instead of the socket.
+ //
+ buf.resize(buf.size() + 1, true);
+ return SocketOperation.Read;
+ }
+ return SocketOperation.None;
+ }
+
+ public void finish(Buffer readBuffer, Buffer writeBuffer)
+ {
+ HttpParser parser = new HttpParser();
+ parser.parse(readBuffer.b, 0, readBuffer.b.position());
+ if(parser.status() != 200)
+ {
+ throw new Ice.ConnectFailedException();
+ }
+ }
+
+#if !SILVERLIGHT
+ public NetworkProxy resolveHost(int protocolSupport)
+ {
+ Debug.Assert(_host != null);
+ return new HTTPNetworkProxy(Network.getAddresses(_host,
+ _port,
+ protocolSupport,
+ Ice.EndpointSelectionType.Random,
+ false,
+ true)[0],
+ protocolSupport);
+ }
+#endif
+
+ public EndPoint getAddress()
+ {
+ Debug.Assert(_address != null); // Host must be resolved.
+ return _address;
+ }
+
+ public string getName()
+ {
+ return "HTTP";
+ }
+
+ public int getProtocolSupport()
+ {
+ return _protocolSupport;
+ }
+
+#if !SILVERLIGHT
+ private readonly string _host;
+ private readonly int _port;
+#endif
+ private readonly EndPoint _address;
+ private readonly int _protocolSupport;
+ }
+}
diff --git a/csharp/src/Ice/Object.cs b/csharp/src/Ice/Object.cs
new file mode 100644
index 00000000000..c2089e81f14
--- /dev/null
+++ b/csharp/src/Ice/Object.cs
@@ -0,0 +1,548 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Ice
+{
+ /// <summary>
+ /// Indicates the status of operation dispatch.
+ /// </summary>
+ public enum DispatchStatus
+ {
+ /// <summary>
+ /// Indicates that an operation was dispatched synchronously and successfully.
+ /// </summary>
+ DispatchOK,
+
+ /// <summary>
+ /// Indicates that an operation was dispatched synchronously and raised a user exception.
+ /// </summary>
+ DispatchUserException,
+
+ /// <summary>
+ /// Indicates that an operation was dispatched asynchronously.
+ /// </summary>
+ DispatchAsync
+ }
+
+ public interface DispatchInterceptorAsyncCallback
+ {
+ bool response(bool ok);
+ bool exception(System.Exception ex);
+ }
+
+ /// <summary>
+ /// Interface for incoming requests.
+ /// </summary>
+ public interface Request
+ {
+ /// <summary>
+ /// Returns the {@link Current} object for this the request.
+ /// </summary>
+ /// <returns>The Current object for this request.</returns>
+ Current getCurrent();
+ }
+
+ /// <summary>
+ /// the base interface for servants.
+ /// </summary>
+ public interface Object : System.ICloneable
+ {
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ ///
+ /// <param name="s">The type ID of the Slice interface to test against.</param>
+ /// <returns>True if this object has the interface
+ /// specified by s or derives from the interface specified by s.</returns>
+ bool ice_isA(string s);
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ ///
+ /// <param name="s">The type ID of the Slice interface to test against.</param>
+ /// <param name="current">The Current object for the invocation.</param>
+ /// <returns>True if this object has the interface
+ /// specified by s or derives from the interface specified by s.</returns>
+ bool ice_isA(string s, Current current);
+
+ /// <summary>
+ /// Tests whether this object can be reached.
+ /// </summary>
+ void ice_ping();
+
+ /// <summary>
+ /// Tests whether this object can be reached.
+ /// </summary>
+ /// <param name="current">The Current object for the invocation.</param>
+ void ice_ping(Current current);
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by this object.
+ /// </summary>
+ /// <returns>The Slice type IDs of the interfaces supported by this object, in base-to-derived
+ /// order. The first element of the returned array is always ::Ice::Object.</returns>
+ string[] ice_ids();
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by this object.
+ /// </summary>
+ /// <param name="current">The Current object for the invocation.</param>
+ /// <returns>The Slice type IDs of the interfaces supported by this object, in base-to-derived
+ /// order. The first element of the returned array is always ::Ice::Object.</returns>
+ string[] ice_ids(Current current);
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by this object.
+ /// </summary>
+ /// <returns>The Slice type ID of the most-derived interface.</returns>
+ string ice_id();
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by this object.
+ /// </summary>
+ /// <param name="current">The Current object for the invocation.</param>
+ /// <returns>The Slice type ID of the most-derived interface.</returns>
+ string ice_id(Current current);
+
+ /// <summary>
+ /// The Ice run time invokes this method prior to marshaling an object's data members. This allows a subclass
+ /// to override this method in order to validate its data members.
+ /// </summary>
+ void ice_preMarshal();
+
+ /// <summary>
+ /// This Ice run time invokes this method vafter unmarshaling an object's data members. This allows a
+ /// subclass to override this method in order to perform additional initialization.
+ /// </summary>
+ void ice_postUnmarshal();
+
+ /// <summary>
+ /// Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation
+ /// to a servant (or to another interceptor).
+ /// </summary>
+ /// <param name="request">The details of the invocation.</param>
+ /// <param name="cb">The callback object for asynchchronous dispatch. For synchronous dispatch,
+ /// the callback object must be null.</param>
+ /// <returns>The dispatch status for the operation.</returns>
+ DispatchStatus ice_dispatch(Request request, DispatchInterceptorAsyncCallback cb);
+
+ /// <summary>
+ /// Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation
+ /// to a servant (or to another interceptor).
+ /// </summary>
+ /// <param name="request">The details of the invocation.</param>
+ /// <returns>The dispatch status for the operation.</returns>
+ DispatchStatus ice_dispatch(Request request);
+
+ DispatchStatus dispatch__(IceInternal.Incoming inc, Current current);
+
+ void write__(IceInternal.BasicStream os__);
+ void read__(IceInternal.BasicStream is__);
+
+ void write__(OutputStream outS__);
+ void read__(InputStream inS__);
+ }
+
+ /// <summary>
+ /// Base class for all Slice classes.
+ /// </summary>
+ public abstract class ObjectImpl : Object
+ {
+ /// <summary>
+ /// Instantiates an Ice object.
+ /// </summary>
+ public ObjectImpl()
+ {
+ }
+
+ /// <summary>
+ /// Returns a copy of the object. The cloned object contains field-for-field copies
+ /// of the state.
+ /// </summary>
+ /// <returns>The cloned object.</returns>
+ public object Clone()
+ {
+ return MemberwiseClone();
+ }
+
+ public static readonly string[] ids__ =
+ {
+ "::Ice::Object"
+ };
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="s">The type ID of the Slice interface to test against.</param>
+ /// <returns>The return value is true if s is ::Ice::Object.</returns>
+ public virtual bool ice_isA(string s)
+ {
+ return s.Equals(ids__[0]);
+ }
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="s">The type ID of the Slice interface to test against.</param>
+ /// <param name="current">The Current object for the invocation.</param>
+ /// <returns>The return value is true if s is ::Ice::Object.</returns>
+ public virtual bool ice_isA(string s, Current current)
+ {
+ return s.Equals(ids__[0]);
+ }
+
+ public static DispatchStatus ice_isA___(Ice.Object __obj, IceInternal.Incoming inS__, Current __current)
+ {
+ IceInternal.BasicStream is__ = inS__.startReadParams();
+ string __id = is__.readString();
+ inS__.endReadParams();
+ bool __ret = __obj.ice_isA(__id, __current);
+ IceInternal.BasicStream os__ = inS__.startWriteParams__(FormatType.DefaultFormat);
+ os__.writeBool(__ret);
+ inS__.endWriteParams__(true);
+ return DispatchStatus.DispatchOK;
+ }
+
+ /// <summary>
+ /// Tests whether this object can be reached.
+ /// </summary>
+ public virtual void ice_ping()
+ {
+ // Nothing to do.
+ }
+
+ /// <summary>
+ /// Tests whether this object can be reached.
+ /// <param name="current">The Current object for the invocation.</param>
+ /// </summary>
+ public virtual void ice_ping(Current current)
+ {
+ // Nothing to do.
+ }
+
+ public static DispatchStatus ice_ping___(Ice.Object __obj, IceInternal.Incoming inS__, Current __current)
+ {
+ inS__.readEmptyParams();
+ __obj.ice_ping(__current);
+ inS__.writeEmptyParams__();
+ return DispatchStatus.DispatchOK;
+ }
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by this object.
+ /// </summary>
+ /// <returns>An array whose only element is ::Ice::Object.</returns>
+ public virtual string[] ice_ids()
+ {
+ return ids__;
+ }
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by this object.
+ /// </summary>
+ /// <param name="current">The Current object for the invocation.</param>
+ /// <returns>An array whose only element is ::Ice::Object.</returns>
+ public virtual string[] ice_ids(Current current)
+ {
+ return ids__;
+ }
+
+ public static DispatchStatus ice_ids___(Ice.Object __obj, IceInternal.Incoming inS__, Current __current)
+ {
+ inS__.readEmptyParams();
+ string[] ret__ = __obj.ice_ids(__current);
+ IceInternal.BasicStream os__ = inS__.startWriteParams__(FormatType.DefaultFormat);
+ os__.writeStringSeq(ret__);
+ inS__.endWriteParams__(true);
+ return DispatchStatus.DispatchOK;
+ }
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by this object.
+ /// </summary>
+ /// <returns>The return value is always ::Ice::Object.</returns>
+ public virtual string ice_id()
+ {
+ return ids__[0];
+ }
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by this object.
+ /// </summary>
+ /// <param name="current">The Current object for the invocation.</param>
+ /// <returns>The return value is always ::Ice::Object.</returns>
+ public virtual string ice_id(Current current)
+ {
+ return ids__[0];
+ }
+
+ public static DispatchStatus ice_id___(Ice.Object __obj, IceInternal.Incoming inS__, Current __current)
+ {
+ inS__.readEmptyParams();
+ string __ret = __obj.ice_id(__current);
+ IceInternal.BasicStream os__ = inS__.startWriteParams__(FormatType.DefaultFormat);
+ os__.writeString(__ret);
+ inS__.endWriteParams__(true);
+ return DispatchStatus.DispatchOK;
+ }
+
+ /// <summary>
+ /// Returns the Slice type ID of the interface supported by this object.
+ /// </summary>
+ /// <returns>The return value is always ::Ice::Object.</returns>
+ public static string ice_staticId()
+ {
+ return ids__[0];
+ }
+
+ /// <summary>
+ /// The Ice run time invokes this method prior to marshaling an object's data members. This allows a subclass
+ /// to override this method in order to validate its data members.
+ /// </summary>
+ public virtual void ice_preMarshal()
+ {
+ }
+
+ /// <summary>
+ /// This Ice run time invokes this method vafter unmarshaling an object's data members. This allows a
+ /// subclass to override this method in order to perform additional initialization.
+ /// </summary>
+ public virtual void ice_postUnmarshal()
+ {
+ }
+
+ private static readonly string[] all__ = new string[]
+ {
+ "ice_id", "ice_ids", "ice_isA", "ice_ping"
+ };
+
+ /// <summary>
+ /// Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation
+ /// to a servant (or to another interceptor).
+ /// </summary>
+ /// <param name="request">The details of the invocation.</param>
+ /// <param name="cb">The callback object for asynchchronous dispatch. For synchronous dispatch, the
+ /// callback object must be null.</param>
+ /// <returns>The dispatch status for the operation.</returns>
+ public virtual DispatchStatus ice_dispatch(Request request, DispatchInterceptorAsyncCallback cb)
+ {
+ IceInternal.Incoming inc = (IceInternal.Incoming)request;
+ if(cb != null)
+ {
+ inc.push(cb);
+ }
+ try
+ {
+ inc.startOver(); // may raise ResponseSentException
+ return dispatch__(inc, inc.getCurrent());
+ }
+ finally
+ {
+ if(cb != null)
+ {
+ inc.pop();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation
+ /// to a servant (or to another interceptor).
+ /// </summary>
+ /// <param name="request">The details of the invocation.</param>
+ /// <returns>The dispatch status for the operation.</returns>
+ public virtual DispatchStatus ice_dispatch(Request request)
+ {
+ return ice_dispatch(request, null);
+ }
+
+ public virtual DispatchStatus dispatch__(IceInternal.Incoming inc, Current current)
+ {
+ int pos = System.Array.BinarySearch(all__, current.operation);
+ if(pos < 0)
+ {
+ throw new Ice.OperationNotExistException(current.id, current.facet, current.operation);
+ }
+
+ switch(pos)
+ {
+ case 0:
+ {
+ return ice_id___(this, inc, current);
+ }
+ case 1:
+ {
+ return ice_ids___(this, inc, current);
+ }
+ case 2:
+ {
+ return ice_isA___(this, inc, current);
+ }
+ case 3:
+ {
+ return ice_ping___(this, inc, current);
+ }
+ }
+
+ Debug.Assert(false);
+ throw new Ice.OperationNotExistException(current.id, current.facet, current.operation);
+ }
+
+ public virtual void write__(IceInternal.BasicStream os__)
+ {
+ os__.startWriteObject(null);
+ writeImpl__(os__);
+ os__.endWriteObject();
+ }
+
+ public virtual void read__(IceInternal.BasicStream is__)
+ {
+ is__.startReadObject();
+ readImpl__(is__);
+ is__.endReadObject(false);
+ }
+
+ public virtual void write__(OutputStream os__)
+ {
+ os__.startObject(null);
+ writeImpl__(os__);
+ os__.endObject();
+ }
+
+ public virtual void read__(InputStream is__)
+ {
+ is__.startObject();
+ readImpl__(is__);
+ is__.endObject(false);
+ }
+
+ protected virtual void writeImpl__(IceInternal.BasicStream os__)
+ {
+ }
+
+ protected virtual void readImpl__(IceInternal.BasicStream is__)
+ {
+ }
+
+ protected virtual void writeImpl__(OutputStream os__)
+ {
+ throw new MarshalException("class was not generated with stream support");
+ }
+
+ protected virtual void readImpl__(InputStream is__)
+ {
+ throw new MarshalException("class was not generated with stream support");
+ }
+
+ private static string operationModeToString(OperationMode mode)
+ {
+ if(mode == Ice.OperationMode.Normal)
+ {
+ return "::Ice::Normal";
+ }
+ if(mode == Ice.OperationMode.Nonmutating)
+ {
+ return "::Ice::Nonmutating";
+ }
+
+ if(mode == Ice.OperationMode.Idempotent)
+ {
+ return "::Ice::Idempotent";
+ }
+
+ return "???";
+ }
+
+ public static void checkMode__(OperationMode expected, OperationMode received)
+ {
+ if(expected != received)
+ {
+ if(expected == OperationMode.Idempotent && received == OperationMode.Nonmutating)
+ {
+ //
+ // Fine: typically an old client still using the
+ // deprecated nonmutating keyword
+ //
+ }
+ else
+ {
+ Ice.MarshalException ex = new Ice.MarshalException();
+ ex.reason = "unexpected operation mode. expected = " + operationModeToString(expected) +
+ " received = " + operationModeToString(received);
+ throw ex;
+ }
+ }
+ }
+
+ public static Ice.Current defaultCurrent = new Ice.Current();
+ }
+
+ /// <summary>
+ /// Base class for dynamic dispatch servants. A server application
+ /// derives a concrete servant class from Blobject that
+ /// implements the Blobject.ice_invoke method.
+ /// </summary>
+ public abstract class Blobject : Ice.ObjectImpl
+ {
+ /// <summary>
+ /// Dispatch an incoming request.
+ /// </summary>
+ /// <param name="inParams">The encoded in-parameters for the operation.</param>
+ /// <param name="outParams">The encoded out-paramaters and return value
+ /// for the operation. The return value follows any out-parameters.</param>
+ /// <param name="current">The Current object to pass to the operation.</param>
+ /// <returns>If the operation completed successfully, the return value
+ /// is true. If the operation raises a user exception,
+ /// the return value is false; in this case, outParams
+ /// must contain the encoded user exception. If the operation raises an
+ /// Ice run-time exception, it must throw it directly.</returns>
+ public abstract bool ice_invoke(byte[] inParams, out byte[] outParams, Current current);
+
+ public override DispatchStatus dispatch__(IceInternal.Incoming inS__, Current current)
+ {
+ byte[] inEncaps = inS__.readParamEncaps();
+ byte[] outEncaps;
+ bool ok = ice_invoke(inEncaps, out outEncaps, current);
+ inS__.writeParamEncaps__(outEncaps, ok);
+ if(ok)
+ {
+ return DispatchStatus.DispatchOK;
+ }
+ else
+ {
+ return DispatchStatus.DispatchUserException;
+ }
+ }
+ }
+
+ public abstract class BlobjectAsync : Ice.ObjectImpl
+ {
+ public abstract void ice_invoke_async(AMD_Object_ice_invoke cb, byte[] inEncaps, Current current);
+
+ public override DispatchStatus dispatch__(IceInternal.Incoming inS__, Current current)
+ {
+ byte[] inEncaps = inS__.readParamEncaps();
+ AMD_Object_ice_invoke cb = new _AMD_Object_ice_invoke(inS__);
+ try
+ {
+ ice_invoke_async(cb, inEncaps, current);
+ }
+ catch(System.Exception ex)
+ {
+ cb.ice_exception(ex);
+ }
+ return DispatchStatus.DispatchAsync;
+ }
+ }
+}
diff --git a/csharp/src/Ice/ObjectAdapterFactory.cs b/csharp/src/Ice/ObjectAdapterFactory.cs
new file mode 100644
index 00000000000..f9cfe278209
--- /dev/null
+++ b/csharp/src/Ice/ObjectAdapterFactory.cs
@@ -0,0 +1,246 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+
+ public sealed class ObjectAdapterFactory
+ {
+ public void shutdown()
+ {
+ List<Ice.ObjectAdapterI> adapters;
+ lock(this)
+ {
+ //
+ // Ignore shutdown requests if the object adapter factory has
+ // already been shut down.
+ //
+ if(instance_ == null)
+ {
+ return;
+ }
+
+ adapters = new List<Ice.ObjectAdapterI>(_adapters);
+
+ instance_ = null;
+ _communicator = null;
+
+ System.Threading.Monitor.PulseAll(this);
+ }
+
+ //
+ // Deactivate outside the thread synchronization, to avoid
+ // deadlocks.
+ //
+ foreach(Ice.ObjectAdapter adapter in adapters)
+ {
+ adapter.deactivate();
+ }
+ }
+
+ public void waitForShutdown()
+ {
+ List<Ice.ObjectAdapterI> adapters;
+ lock(this)
+ {
+ //
+ // First we wait for the shutdown of the factory itself.
+ //
+ while(instance_ != null)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ adapters = new List<Ice.ObjectAdapterI>(_adapters);
+ }
+
+ //
+ // Now we wait for deactivation of each object adapter.
+ //
+ foreach(Ice.ObjectAdapter adapter in adapters)
+ {
+ adapter.waitForDeactivate();
+ }
+ }
+
+ public bool isShutdown()
+ {
+ lock(this)
+ {
+ return instance_ == null;
+ }
+ }
+
+ public void destroy()
+ {
+ //
+ // First wait for shutdown to finish.
+ //
+ waitForShutdown();
+
+ List<Ice.ObjectAdapterI> adapters;
+ lock(this)
+ {
+ adapters = new List<Ice.ObjectAdapterI>(_adapters);
+ }
+
+ foreach(Ice.ObjectAdapter adapter in adapters)
+ {
+ adapter.destroy();
+ }
+
+ lock(this)
+ {
+ _adapters.Clear();
+ }
+ }
+
+ public void
+ updateConnectionObservers()
+ {
+ List<Ice.ObjectAdapterI> adapters;
+ lock(this)
+ {
+ adapters = new List<Ice.ObjectAdapterI>(_adapters);
+ }
+
+ foreach(Ice.ObjectAdapterI adapter in adapters)
+ {
+ adapter.updateConnectionObservers();
+ }
+ }
+
+ public void
+ updateThreadObservers()
+ {
+ List<Ice.ObjectAdapterI> adapters;
+ lock(this)
+ {
+ adapters = new List<Ice.ObjectAdapterI>(_adapters);
+ }
+
+ foreach(Ice.ObjectAdapterI adapter in adapters)
+ {
+ adapter.updateThreadObservers();
+ }
+ }
+
+ public Ice.ObjectAdapter createObjectAdapter(string name, Ice.RouterPrx router)
+ {
+ lock(this)
+ {
+ if(instance_ == null)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Ice.ObjectAdapterI adapter = null;
+ if(name.Length == 0)
+ {
+ string uuid = System.Guid.NewGuid().ToString();
+ adapter = new Ice.ObjectAdapterI(instance_, _communicator, this, uuid, null, true);
+ }
+ else
+ {
+ if(_adapterNamesInUse.Contains(name))
+ {
+ Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException();
+ ex.kindOfObject = "object adapter";
+ ex.id = name;
+ throw ex;
+ }
+ adapter = new Ice.ObjectAdapterI(instance_, _communicator, this, name, router, false);
+ _adapterNamesInUse.Add(name);
+ }
+ _adapters.Add(adapter);
+ return adapter;
+ }
+ }
+
+ public Ice.ObjectAdapter findObjectAdapter(Ice.ObjectPrx proxy)
+ {
+ List<Ice.ObjectAdapterI> adapters;
+ lock(this)
+ {
+ if(instance_ == null)
+ {
+ return null;
+ }
+
+ adapters = new List<Ice.ObjectAdapterI>(_adapters);
+ }
+
+ foreach(Ice.ObjectAdapterI adapter in adapters)
+ {
+ try
+ {
+ if(adapter.isLocal(proxy))
+ {
+ return adapter;
+ }
+ }
+ catch(Ice.ObjectAdapterDeactivatedException)
+ {
+ // Ignore.
+ }
+ }
+
+ return null;
+ }
+
+ public void removeObjectAdapter(Ice.ObjectAdapterI adapter)
+ {
+ lock(this)
+ {
+ if(instance_ == null)
+ {
+ return;
+ }
+
+ _adapters.Remove(adapter);
+ _adapterNamesInUse.Remove(adapter.getName());
+ }
+ }
+
+ public void flushAsyncBatchRequests(CommunicatorFlushBatch outAsync)
+ {
+ List<Ice.ObjectAdapterI> adapters;
+ lock(this)
+ {
+ adapters = new List<Ice.ObjectAdapterI>(_adapters);
+ }
+
+ foreach(Ice.ObjectAdapterI adapter in adapters)
+ {
+ adapter.flushAsyncBatchRequests(outAsync);
+ }
+ }
+
+ //
+ // Only for use by Instance.
+ //
+ internal ObjectAdapterFactory(Instance instance, Ice.Communicator communicator)
+ {
+ instance_ = instance;
+ _communicator = communicator;
+ _adapterNamesInUse = new HashSet<string>();
+ _adapters = new List<Ice.ObjectAdapterI>();
+ }
+
+ private Instance instance_;
+ private Ice.Communicator _communicator;
+ private HashSet<string> _adapterNamesInUse;
+ private List<Ice.ObjectAdapterI> _adapters;
+ }
+
+}
diff --git a/csharp/src/Ice/ObjectAdapterI.cs b/csharp/src/Ice/ObjectAdapterI.cs
new file mode 100644
index 00000000000..c6794a1a4db
--- /dev/null
+++ b/csharp/src/Ice/ObjectAdapterI.cs
@@ -0,0 +1,1579 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Text;
+
+ using IceInternal;
+
+ public sealed class ObjectAdapterI : ObjectAdapter
+ {
+ public string getName()
+ {
+ //
+ // No mutex lock necessary, _name is immutable.
+ //
+ return _noConfig ? "" : _name;
+ }
+
+ public Communicator getCommunicator()
+ {
+ return _communicator;
+ }
+
+ public void activate()
+ {
+ LocatorInfo locatorInfo = null;
+ bool registerProcess = false;
+ bool printAdapterReady = false;
+
+ lock(this)
+ {
+ checkForDeactivation();
+
+ //
+ // If we've previously been initialized we just need to activate the
+ // incoming connection factories and we're done.
+ //
+ if(state_ != StateUninitialized)
+ {
+ foreach(IncomingConnectionFactory icf in _incomingConnectionFactories)
+ {
+ icf.activate();
+ }
+ return;
+ }
+
+ //
+ // One off initializations of the adapter: update the
+ // locator registry and print the "adapter ready"
+ // message. We set set state to StateActivating to prevent
+ // deactivation from other threads while these one off
+ // initializations are done.
+ //
+ state_ = StateActivating;
+
+ locatorInfo = _locatorInfo;
+ if(!_noConfig)
+ {
+ Properties properties = instance_.initializationData().properties;
+ registerProcess = properties.getPropertyAsInt(_name + ".RegisterProcess") > 0;
+ printAdapterReady = properties.getPropertyAsInt("Ice.PrintAdapterReady") > 0;
+ }
+ }
+
+ try
+ {
+ Ice.Identity dummy = new Ice.Identity();
+ dummy.name = "dummy";
+ updateLocatorRegistry(locatorInfo, createDirectProxy(dummy), registerProcess);
+ }
+ catch(Ice.LocalException)
+ {
+ //
+ // If we couldn't update the locator registry, we let the
+ // exception go through and don't activate the adapter to
+ // allow to user code to retry activating the adapter
+ // later.
+ //
+ lock(this)
+ {
+ state_ = StateUninitialized;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ throw;
+ }
+
+ if(printAdapterReady)
+ {
+ System.Console.Out.WriteLine(_name + " ready");
+ }
+
+ lock(this)
+ {
+ Debug.Assert(state_ == StateActivating);
+
+ foreach(IncomingConnectionFactory icf in _incomingConnectionFactories)
+ {
+ icf.activate();
+ }
+
+ state_ = StateActive;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public void hold()
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ state_ = StateHeld;
+ foreach(IncomingConnectionFactory factory in _incomingConnectionFactories)
+ {
+ factory.hold();
+ }
+ }
+ }
+
+ public void waitForHold()
+ {
+ List<IncomingConnectionFactory> incomingConnectionFactories;
+ lock(this)
+ {
+ checkForDeactivation();
+
+ incomingConnectionFactories = new List<IncomingConnectionFactory>(_incomingConnectionFactories);
+ }
+
+ foreach(IncomingConnectionFactory factory in incomingConnectionFactories)
+ {
+ factory.waitUntilHolding();
+ }
+ }
+
+ public void deactivate()
+ {
+ lock(this)
+ {
+ //
+ //
+ // Wait for activation to complete. This is necessary to not
+ // get out of order locator updates.
+ //
+ while(state_ == StateActivating || state_ == StateDeactivating)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ if(state_ > StateDeactivating)
+ {
+ return;
+ }
+ state_ = StateDeactivating;
+ }
+
+ //
+ // NOTE: the router/locator infos and incoming connection
+ // facatory list are immutable at this point.
+ //
+
+ if(_routerInfo != null)
+ {
+ //
+ // Remove entry from the router manager.
+ //
+ instance_.routerManager().erase(_routerInfo.getRouter());
+
+ //
+ // Clear this object adapter with the router.
+ //
+ _routerInfo.setAdapter(null);
+ }
+
+ try
+ {
+ updateLocatorRegistry(_locatorInfo, null, false);
+ }
+ catch(Ice.LocalException)
+ {
+ //
+ // We can't throw exceptions in deactivate so we ignore
+ // failures to update the locator registry.
+ //
+ }
+
+ //
+ // Must be called outside the thread synchronization, because
+ // Connection::destroy() might block when sending a CloseConnection
+ // message.
+ //
+ foreach(IncomingConnectionFactory factory in _incomingConnectionFactories)
+ {
+ factory.destroy();
+ }
+
+ //
+ // Must be called outside the thread synchronization, because
+ // changing the object adapter might block if there are still
+ // requests being dispatched.
+ //
+ instance_.outgoingConnectionFactory().removeAdapter(this);
+
+ lock(this)
+ {
+ Debug.Assert(state_ == StateDeactivating);
+ state_ = StateDeactivated;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public void waitForDeactivate()
+ {
+ IncomingConnectionFactory[] incomingConnectionFactories = null;
+ lock(this)
+ {
+ //
+ // Wait for deactivation of the adapter itself, and
+ // for the return of all direct method calls using this
+ // adapter.
+ //
+ while((state_ < StateDeactivated) || _directCount > 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ if(state_ > StateDeactivated)
+ {
+ return;
+ }
+
+ incomingConnectionFactories = _incomingConnectionFactories.ToArray();
+ }
+
+ //
+ // Now we wait for until all incoming connection factories are
+ // finished.
+ //
+ foreach(IncomingConnectionFactory factory in incomingConnectionFactories)
+ {
+ factory.waitUntilFinished();
+ }
+ }
+
+ public bool isDeactivated()
+ {
+ lock(this)
+ {
+ return state_ >= StateDeactivated;
+ }
+ }
+
+ public void destroy()
+ {
+ //
+ // Deactivate and wait for completion.
+ //
+ deactivate();
+ waitForDeactivate();
+
+ lock(this)
+ {
+ //
+ // Only a single thread is allowed to destroy the object
+ // adapter. Other threads wait for the destruction to be
+ // completed.
+ //
+ while(state_ == StateDestroying)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ if(state_ == StateDestroyed)
+ {
+ return;
+ }
+ state_ = StateDestroying;
+ }
+
+ //
+ // Now it's also time to clean up our servants and servant
+ // locators.
+ //
+ _servantManager.destroy();
+
+ //
+ // Destroy the thread pool.
+ //
+ if(_threadPool != null)
+ {
+ _threadPool.destroy();
+ _threadPool.joinWithAllThreads();
+ }
+
+ if(_objectAdapterFactory != null)
+ {
+ _objectAdapterFactory.removeObjectAdapter(this);
+ }
+
+ lock(this)
+ {
+ //
+ // We're done, now we can throw away all incoming connection
+ // factories.
+ //
+ _incomingConnectionFactories.Clear();
+
+ //
+ // Remove object references (some of them cyclic).
+ //
+ instance_ = null;
+ _threadPool = null;
+ _routerEndpoints = null;
+ _routerInfo = null;
+ _publishedEndpoints = null;
+ _locatorInfo = null;
+ _reference = null;
+ _objectAdapterFactory = null;
+
+ state_ = StateDestroyed;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public ObjectPrx add(Ice.Object obj, Identity ident)
+ {
+ return addFacet(obj, ident, "");
+ }
+
+ public ObjectPrx addFacet(Ice.Object obj, Identity ident, string facet)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+ checkServant(obj);
+
+ //
+ // Create a copy of the Identity argument, in case the caller
+ // reuses it.
+ //
+ Identity id = new Identity();
+ id.category = ident.category;
+ id.name = ident.name;
+
+ _servantManager.addServant(obj, id, facet);
+
+ return newProxy(id, facet);
+ }
+ }
+
+ public ObjectPrx addWithUUID(Ice.Object obj)
+ {
+ return addFacetWithUUID(obj, "");
+ }
+
+ public ObjectPrx addFacetWithUUID(Ice.Object obj, string facet)
+ {
+ Identity ident = new Identity();
+ ident.category = "";
+ ident.name = Guid.NewGuid().ToString();
+
+ return addFacet(obj, ident, facet);
+ }
+
+ public void addDefaultServant(Ice.Object servant, string category)
+ {
+ checkServant(servant);
+
+ lock(this)
+ {
+ checkForDeactivation();
+
+ _servantManager.addDefaultServant(servant, category);
+ }
+ }
+
+ public Ice.Object remove(Identity ident)
+ {
+ return removeFacet(ident, "");
+ }
+
+ public Ice.Object removeFacet(Identity ident, string facet)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+
+ return _servantManager.removeServant(ident, facet);
+ }
+ }
+
+ public Dictionary<string, Ice.Object> removeAllFacets(Identity ident)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+
+ return _servantManager.removeAllFacets(ident);
+ }
+ }
+
+ public Ice.Object removeDefaultServant(string category)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ return _servantManager.removeDefaultServant(category);
+ }
+ }
+
+ public Ice.Object find(Identity ident)
+ {
+ return findFacet(ident, "");
+ }
+
+ public Ice.Object findFacet(Identity ident, string facet)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+
+ return _servantManager.findServant(ident, facet);
+ }
+ }
+
+ public Dictionary<string, Ice.Object> findAllFacets(Identity ident)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+
+ return _servantManager.findAllFacets(ident);
+ }
+ }
+
+ public Ice.Object findByProxy(ObjectPrx proxy)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ Reference @ref = ((ObjectPrxHelperBase)proxy).reference__();
+ return findFacet(@ref.getIdentity(), @ref.getFacet());
+ }
+ }
+
+ public Ice.Object findDefaultServant(string category)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ return _servantManager.findDefaultServant(category);
+ }
+ }
+
+ public void addServantLocator(ServantLocator locator, string prefix)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ _servantManager.addServantLocator(locator, prefix);
+ }
+ }
+
+ public ServantLocator removeServantLocator(string prefix)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ return _servantManager.removeServantLocator(prefix);
+ }
+ }
+
+ public ServantLocator findServantLocator(string prefix)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ return _servantManager.findServantLocator(prefix);
+ }
+ }
+
+ public ObjectPrx createProxy(Identity ident)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+
+ return newProxy(ident, "");
+ }
+ }
+
+ public ObjectPrx createDirectProxy(Identity ident)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+
+ return newDirectProxy(ident, "");
+ }
+ }
+
+ public ObjectPrx createIndirectProxy(Identity ident)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+ checkIdentity(ident);
+
+ return newIndirectProxy(ident, "", _id);
+ }
+ }
+
+ public void setLocator(LocatorPrx locator)
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ _locatorInfo = instance_.locatorManager().get(locator);
+ }
+ }
+
+ public LocatorPrx getLocator()
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ if(_locatorInfo == null)
+ {
+ return null;
+ }
+ else
+ {
+ return _locatorInfo.getLocator();
+ }
+ }
+ }
+
+ public void refreshPublishedEndpoints()
+ {
+ LocatorInfo locatorInfo = null;
+ bool registerProcess = false;
+ List<EndpointI> oldPublishedEndpoints;
+
+ lock(this)
+ {
+ checkForDeactivation();
+
+ oldPublishedEndpoints = _publishedEndpoints;
+ _publishedEndpoints = parsePublishedEndpoints();
+
+ locatorInfo = _locatorInfo;
+ if(!_noConfig)
+ {
+ registerProcess =
+ instance_.initializationData().properties.getPropertyAsInt(_name + ".RegisterProcess") > 0;
+ }
+ }
+
+ try
+ {
+ Ice.Identity dummy = new Ice.Identity();
+ dummy.name = "dummy";
+ updateLocatorRegistry(locatorInfo, createDirectProxy(dummy), registerProcess);
+ }
+ catch(Ice.LocalException)
+ {
+ lock(this)
+ {
+ //
+ // Restore the old published endpoints.
+ //
+ _publishedEndpoints = oldPublishedEndpoints;
+ throw;
+ }
+ }
+ }
+
+ public Endpoint[] getEndpoints()
+ {
+ lock(this)
+ {
+ List<Endpoint> endpoints = new List<Endpoint>();
+ foreach(IncomingConnectionFactory factory in _incomingConnectionFactories)
+ {
+ endpoints.Add(factory.endpoint());
+ }
+ return endpoints.ToArray();
+ }
+ }
+
+ public Endpoint[] getPublishedEndpoints()
+ {
+ lock(this)
+ {
+ return _publishedEndpoints.ToArray();
+ }
+ }
+
+ public bool isLocal(ObjectPrx proxy)
+ {
+ //
+ // NOTE: it's important that isLocal() doesn't perform any blocking operations as
+ // it can be called for AMI invocations if the proxy has no delegate set yet.
+ //
+
+ Reference r = ((ObjectPrxHelperBase)proxy).reference__();
+ if(r.isWellKnown())
+ {
+ //
+ // Check the active servant map to see if the well-known
+ // proxy is for a local object.
+ //
+ return _servantManager.hasServant(r.getIdentity());
+ }
+ else if(r.isIndirect())
+ {
+ //
+ // Proxy is local if the reference adapter id matches this
+ // adapter id or replica group id.
+ //
+ return r.getAdapterId().Equals(_id) || r.getAdapterId().Equals(_replicaGroupId);
+ }
+ else
+ {
+ EndpointI[] endpoints = r.getEndpoints();
+
+ lock(this)
+ {
+ checkForDeactivation();
+
+ //
+ // Proxies which have at least one endpoint in common with the
+ // endpoints used by this object adapter's incoming connection
+ // factories are considered local.
+ //
+ for(int i = 0; i < endpoints.Length; ++i)
+ {
+ foreach(EndpointI endpoint in _publishedEndpoints)
+ {
+ if(endpoints[i].equivalent(endpoint))
+ {
+ return true;
+ }
+ }
+ foreach(IncomingConnectionFactory factory in _incomingConnectionFactories)
+ {
+ if(endpoints[i].equivalent(factory.endpoint()))
+ {
+ return true;
+ }
+ }
+ }
+
+ //
+ // Proxies which have at least one endpoint in common with the
+ // router's server proxy endpoints (if any), are also considered
+ // local.
+ //
+ if(_routerInfo != null && _routerInfo.getRouter().Equals(proxy.ice_getRouter()))
+ {
+ for(int i = 0; i < endpoints.Length; ++i)
+ {
+ foreach(EndpointI endpoint in _routerEndpoints)
+ {
+ if(endpoints[i].equivalent(endpoint))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+
+ public void flushAsyncBatchRequests(CommunicatorFlushBatch outAsync)
+ {
+ List<IncomingConnectionFactory> f;
+ lock(this)
+ {
+ f = new List<IncomingConnectionFactory>(_incomingConnectionFactories);
+ }
+
+ foreach(IncomingConnectionFactory factory in f)
+ {
+ factory.flushAsyncBatchRequests(outAsync);
+ }
+ }
+
+ public void updateConnectionObservers()
+ {
+ List<IncomingConnectionFactory> f;
+ lock(this)
+ {
+ f = new List<IncomingConnectionFactory>(_incomingConnectionFactories);
+ }
+
+ foreach(IncomingConnectionFactory p in f)
+ {
+ p.updateConnectionObservers();
+ }
+ }
+
+ public void updateThreadObservers()
+ {
+ ThreadPool threadPool = null;
+ lock(this)
+ {
+ threadPool = _threadPool;
+ }
+
+ if(threadPool != null)
+ {
+ threadPool.updateObservers();
+ }
+ }
+
+ public void incDirectCount()
+ {
+ lock(this)
+ {
+ checkForDeactivation();
+
+ Debug.Assert(_directCount >= 0);
+ ++_directCount;
+ }
+ }
+
+ public void decDirectCount()
+ {
+ lock(this)
+ {
+ // Not check for deactivation here!
+
+ Debug.Assert(instance_ != null); // Must not be called after destroy().
+
+ Debug.Assert(_directCount > 0);
+ if(--_directCount == 0)
+ {
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+ }
+
+ public ThreadPool getThreadPool()
+ {
+ // No mutex lock necessary, _threadPool and instance_ are
+ // immutable after creation until they are removed in
+ // destroy().
+
+ // Not check for deactivation here!
+
+ Debug.Assert(instance_ != null); // Must not be called after destroy().
+
+ if(_threadPool != null)
+ {
+ return _threadPool;
+ }
+ else
+ {
+ return instance_.serverThreadPool();
+ }
+
+ }
+
+ public ServantManager getServantManager()
+ {
+ //
+ // No mutex lock necessary, _servantManager is immutable.
+ //
+ return _servantManager;
+ }
+
+ public ACMConfig getACM()
+ {
+ // Not check for deactivation here!
+
+ Debug.Assert(instance_ != null); // Must not be called after destroy().
+ return _acm;
+ }
+
+ public int messageSizeMax()
+ {
+ // No mutex lock, immutable.
+ return _messageSizeMax;
+ }
+
+ //
+ // Only for use by ObjectAdapterFactory
+ //
+ public ObjectAdapterI(Instance instance, Communicator communicator,
+ ObjectAdapterFactory objectAdapterFactory, string name,
+ RouterPrx router, bool noConfig)
+ {
+ instance_ = instance;
+ _communicator = communicator;
+ _objectAdapterFactory = objectAdapterFactory;
+ _servantManager = new ServantManager(instance, name);
+ _name = name;
+ _incomingConnectionFactories = new List<IncomingConnectionFactory>();
+ _publishedEndpoints = new List<EndpointI>();
+ _routerEndpoints = new List<EndpointI>();
+ _routerInfo = null;
+ _directCount = 0;
+ _noConfig = noConfig;
+ _processId = null;
+
+ if(_noConfig)
+ {
+ _id = "";
+ _replicaGroupId = "";
+ _reference = instance_.referenceFactory().create("dummy -t", "");
+ _acm = instance_.serverACM();
+ return;
+ }
+
+ Properties properties = instance_.initializationData().properties;
+ List<string> unknownProps = new List<string>();
+ bool noProps = filterProperties(unknownProps);
+
+ //
+ // Warn about unknown object adapter properties.
+ //
+ if(unknownProps.Count != 0 && properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0)
+ {
+ StringBuilder message = new StringBuilder("found unknown properties for object adapter `");
+ message.Append(_name);
+ message.Append("':");
+ foreach(string s in unknownProps)
+ {
+ message.Append("\n ");
+ message.Append(s);
+ }
+ instance_.initializationData().logger.warning(message.ToString());
+ }
+
+ //
+ // Make sure named adapter has configuration.
+ //
+ if(router == null && noProps)
+ {
+ //
+ // These need to be set to prevent warnings/asserts in the destructor.
+ //
+ state_ = StateDestroyed;
+ instance_ = null;
+ _incomingConnectionFactories = null;
+
+ InitializationException ex = new InitializationException();
+ ex.reason = "object adapter `" + _name + "' requires configuration";
+ throw ex;
+ }
+
+ _id = properties.getProperty(_name + ".AdapterId");
+ _replicaGroupId = properties.getProperty(_name + ".ReplicaGroupId");
+
+ //
+ // Setup a reference to be used to get the default proxy options
+ // when creating new proxies. By default, create twoway proxies.
+ //
+ string proxyOptions = properties.getPropertyWithDefault(_name + ".ProxyOptions", "-t");
+ try
+ {
+ _reference = instance_.referenceFactory().create("dummy " + proxyOptions, "");
+ }
+ catch(ProxyParseException)
+ {
+ InitializationException ex = new InitializationException();
+ ex.reason = "invalid proxy options `" + proxyOptions + "' for object adapter `" + _name + "'";
+ throw ex;
+ }
+
+ _acm = new ACMConfig(properties, communicator.getLogger(), _name + ".ACM", instance_.serverACM());
+
+ {
+ int defaultMessageSizeMax = instance.messageSizeMax() / 1024;
+ int num = properties.getPropertyAsIntWithDefault(_name + ".MessageSizeMax", defaultMessageSizeMax);
+ if(num < 1 || num > 0x7fffffff / 1024)
+ {
+ _messageSizeMax = 0x7fffffff;
+ }
+ else
+ {
+ _messageSizeMax = num * 1024; // Property is in kilobytes, _messageSizeMax in bytes
+ }
+ }
+
+ try
+ {
+ int threadPoolSize = properties.getPropertyAsInt(_name + ".ThreadPool.Size");
+ int threadPoolSizeMax = properties.getPropertyAsInt(_name + ".ThreadPool.SizeMax");
+ if(threadPoolSize > 0 || threadPoolSizeMax > 0)
+ {
+ _threadPool = new ThreadPool(instance_, _name + ".ThreadPool", 0);
+ }
+
+ if(router == null)
+ {
+ router = RouterPrxHelper.uncheckedCast(
+ instance_.proxyFactory().propertyToProxy(_name + ".Router"));
+ }
+ if(router != null)
+ {
+ _routerInfo = instance_.routerManager().get(router);
+ if(_routerInfo != null)
+ {
+ //
+ // Make sure this router is not already registered with another adapter.
+ //
+ if(_routerInfo.getAdapter() != null)
+ {
+ Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException();
+ ex.kindOfObject = "object adapter with router";
+ ex.id = instance_.identityToString(router.ice_getIdentity());
+ throw ex;
+ }
+
+ //
+ // Add the router's server proxy endpoints to this object
+ // adapter.
+ //
+ EndpointI[] endpoints = _routerInfo.getServerEndpoints();
+ for(int i = 0; i < endpoints.Length; ++i)
+ {
+ _routerEndpoints.Add(endpoints[i]);
+ }
+ _routerEndpoints.Sort(); // Must be sorted.
+
+ //
+ // Remove duplicate endpoints, so we have a list of unique endpoints.
+ //
+ for(int i = 0; i < _routerEndpoints.Count-1;)
+ {
+ EndpointI e1 = _routerEndpoints[i];
+ EndpointI e2 = _routerEndpoints[i + 1];
+ if(e1.Equals(e2))
+ {
+ _routerEndpoints.RemoveAt(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+
+ //
+ // Associate this object adapter with the router. This way,
+ // new outgoing connections to the router's client proxy will
+ // use this object adapter for callbacks.
+ //
+ _routerInfo.setAdapter(this);
+
+ //
+ // Also modify all existing outgoing connections to the
+ // router's client proxy to use this object adapter for
+ // callbacks.
+ //
+ instance_.outgoingConnectionFactory().setRouterInfo(_routerInfo);
+ }
+ }
+ else
+ {
+ //
+ // Parse the endpoints, but don't store them in the adapter. The connection
+ // factory might change it, for example, to fill in the real port number.
+ //
+ List<EndpointI> endpoints = parseEndpoints(properties.getProperty(_name + ".Endpoints"), true);
+ foreach(EndpointI endp in endpoints)
+ {
+ IncomingConnectionFactory factory = new IncomingConnectionFactory(instance, endp, this);
+ _incomingConnectionFactories.Add(factory);
+ }
+ if(endpoints.Count == 0)
+ {
+ TraceLevels tl = instance_.traceLevels();
+ if(tl.network >= 2)
+ {
+ instance_.initializationData().logger.trace(tl.networkCat, "created adapter `" + _name +
+ "' without endpoints");
+ }
+ }
+
+ //
+ // Parse published endpoints.
+ //
+ _publishedEndpoints = parsePublishedEndpoints();
+ }
+
+ if(properties.getProperty(_name + ".Locator").Length > 0)
+ {
+ setLocator(LocatorPrxHelper.uncheckedCast(
+ instance_.proxyFactory().propertyToProxy(_name + ".Locator")));
+ }
+ else
+ {
+ setLocator(instance_.referenceFactory().getDefaultLocator());
+ }
+ }
+ catch(LocalException)
+ {
+ destroy();
+ throw;
+ }
+ }
+
+ /*
+ ~ObjectAdapterI()
+ {
+ if(!_deactivated)
+ {
+ string msg = "object adapter `" + getName() + "' has not been deactivated";
+ if(!Environment.HasShutdownStarted)
+ {
+ instance_.initializationData().logger.warning(msg);
+ }
+ else
+ {
+ Console.Error.WriteLine(msg);
+ }
+ }
+ else if(!_destroyed)
+ {
+ string msg = "object adapter `" + getName() + "' has not been destroyed";
+ if(!Environment.HasShutdownStarted)
+ {
+ instance_.initializationData().logger.warning(msg);
+ }
+ else
+ {
+ Console.Error.WriteLine(msg);
+ }
+ }
+ }
+ */
+
+ private ObjectPrx newProxy(Identity ident, string facet)
+ {
+ if(_id.Length == 0)
+ {
+ return newDirectProxy(ident, facet);
+ }
+ else if(_replicaGroupId.Length == 0)
+ {
+ return newIndirectProxy(ident, facet, _id);
+ }
+ else
+ {
+ return newIndirectProxy(ident, facet, _replicaGroupId);
+ }
+ }
+
+ private ObjectPrx newDirectProxy(Identity ident, string facet)
+ {
+ EndpointI[] endpoints;
+
+ //
+ // Use the published endpoints, otherwise use the endpoints from all
+ // incoming connection factories.
+ //
+ int sz = _publishedEndpoints.Count;
+ endpoints = new EndpointI[sz + _routerEndpoints.Count];
+ for(int i = 0; i < sz; ++i)
+ {
+ endpoints[i] = _publishedEndpoints[i];
+ }
+
+ //
+ // Now we also add the endpoints of the router's server proxy, if
+ // any. This way, object references created by this object adapter
+ // will also point to the router's server proxy endpoints.
+ //
+ for(int i = 0; i < _routerEndpoints.Count; ++i)
+ {
+ endpoints[sz + i] = _routerEndpoints[i];
+ }
+
+ //
+ // Create a reference and return a proxy for this reference.
+ //
+ Reference reference = instance_.referenceFactory().create(ident, facet, _reference, endpoints);
+ return instance_.proxyFactory().referenceToProxy(reference);
+ }
+
+ private ObjectPrx newIndirectProxy(Identity ident, string facet, string id)
+ {
+ //
+ // Create a reference with the adapter id and return a
+ // proxy for the reference.
+ //
+ Reference reference = instance_.referenceFactory().create(ident, facet, _reference, id);
+ return instance_.proxyFactory().referenceToProxy(reference);
+ }
+
+ private void checkForDeactivation()
+ {
+ if(state_ >= StateDeactivating)
+ {
+ ObjectAdapterDeactivatedException ex = new ObjectAdapterDeactivatedException();
+ ex.name = getName();
+ throw ex;
+ }
+ }
+
+ private static void checkIdentity(Identity ident)
+ {
+ if(ident.name == null || ident.name.Length == 0)
+ {
+ throw new IllegalIdentityException(ident);
+ }
+ if(ident.category == null)
+ {
+ ident.category = "";
+ }
+ }
+
+ private static void checkServant(Ice.Object servant)
+ {
+ if(servant == null)
+ {
+ throw new IllegalServantException("cannot add null servant to Object Adapter");
+ }
+ }
+
+ private List<EndpointI> parseEndpoints(string endpts, bool oaEndpoints)
+ {
+ int beg;
+ int end = 0;
+
+ string delim = " \t\n\r";
+
+ List<EndpointI> endpoints = new List<EndpointI>();
+ while(end < endpts.Length)
+ {
+ beg = IceUtilInternal.StringUtil.findFirstNotOf(endpts, delim, end);
+ if(beg == -1)
+ {
+ break;
+ }
+
+ end = beg;
+ while(true)
+ {
+ end = endpts.IndexOf((System.Char) ':', end);
+ if(end == -1)
+ {
+ end = endpts.Length;
+ break;
+ }
+ else
+ {
+ bool quoted = false;
+ int quote = beg;
+ while(true)
+ {
+ quote = endpts.IndexOf((System.Char) '\"', quote);
+ if(quote == -1 || end < quote)
+ {
+ break;
+ }
+ else
+ {
+ quote = endpts.IndexOf((System.Char) '\"', ++quote);
+ if(quote == -1)
+ {
+ break;
+ }
+ else if(end < quote)
+ {
+ quoted = true;
+ break;
+ }
+ ++quote;
+ }
+ }
+ if(!quoted)
+ {
+ break;
+ }
+ ++end;
+ }
+ }
+
+ if(end == beg)
+ {
+ ++end;
+ continue;
+ }
+
+ string s = endpts.Substring(beg, (end) - (beg));
+ EndpointI endp = instance_.endpointFactoryManager().create(s, oaEndpoints);
+ if(endp == null)
+ {
+#if COMPACT
+ if(s.StartsWith("ssl", StringComparison.Ordinal) || s.StartsWith("wss", StringComparison.Ordinal))
+ {
+ instance_.initializationData().logger.warning(
+ "ignoring endpoint `" + s +
+ "': IceSSL is not supported with the .NET Compact Framework");
+ ++end;
+ continue;
+ }
+#else
+ if(AssemblyUtil.runtime_ == AssemblyUtil.Runtime.Mono &&
+ (s.StartsWith("ssl", StringComparison.Ordinal) || s.StartsWith("wss", StringComparison.Ordinal)))
+ {
+ instance_.initializationData().logger.warning(
+ "ignoring endpoint `" + s + "': IceSSL is not supported with Mono");
+ ++end;
+ continue;
+ }
+#endif
+ Ice.EndpointParseException e2 = new Ice.EndpointParseException();
+ e2.str = "invalid object adapter endpoint `" + s + "'";
+ throw e2;
+ }
+ endpoints.Add(endp);
+
+ ++end;
+ }
+
+ return endpoints;
+ }
+
+ private List<EndpointI> parsePublishedEndpoints()
+ {
+ //
+ // Parse published endpoints. If set, these are used in proxies
+ // instead of the connection factory endpoints.
+ //
+ string endpts = instance_.initializationData().properties.getProperty(_name + ".PublishedEndpoints");
+ List<EndpointI> endpoints = parseEndpoints(endpts, false);
+ if(endpoints.Count == 0)
+ {
+ //
+ // If the PublishedEndpoints property isn't set, we compute the published enpdoints
+ // from the OA endpoints, expanding any endpoints that may be listening on INADDR_ANY
+ // to include actual addresses in the published endpoints.
+ //
+ foreach(IncomingConnectionFactory factory in _incomingConnectionFactories)
+ {
+ endpoints.AddRange(factory.endpoint().expand());
+ }
+ }
+
+ if(instance_.traceLevels().network >= 1 && endpoints.Count > 0)
+ {
+ StringBuilder s = new StringBuilder("published endpoints for object adapter `");
+ s.Append(_name);
+ s.Append("':\n");
+ bool first = true;
+ foreach(EndpointI endpoint in endpoints)
+ {
+ if(!first)
+ {
+ s.Append(":");
+ }
+ s.Append(endpoint.ToString());
+ first = false;
+ }
+ instance_.initializationData().logger.trace(instance_.traceLevels().networkCat, s.ToString());
+ }
+ return endpoints;
+ }
+
+ private void updateLocatorRegistry(LocatorInfo locatorInfo, ObjectPrx proxy, bool registerProcess)
+ {
+ if(!registerProcess && _id.Length == 0)
+ {
+ return; // Nothing to update.
+ }
+
+ //
+ // Call on the locator registry outside the synchronization to
+ // blocking other threads that need to lock this OA.
+ //
+ LocatorRegistryPrx locatorRegistry = locatorInfo != null ? locatorInfo.getLocatorRegistry() : null;
+ string serverId = "";
+ if(registerProcess)
+ {
+ Debug.Assert(instance_ != null);
+ serverId = instance_.initializationData().properties.getProperty("Ice.ServerId");
+
+ if(locatorRegistry == null)
+ {
+ instance_.initializationData().logger.warning(
+ "object adapter `" + getName() + "' cannot register the process without a locator registry");
+ }
+ else if(serverId.Length == 0)
+ {
+ instance_.initializationData().logger.warning(
+ "object adapter `" + getName() +
+ "' cannot register the process without a value for Ice.ServerId");
+ }
+ }
+
+ if(locatorRegistry == null)
+ {
+ return;
+ }
+
+ if(_id.Length > 0)
+ {
+ try
+ {
+ if(_replicaGroupId.Length == 0)
+ {
+ locatorRegistry.setAdapterDirectProxy(_id, proxy);
+ }
+ else
+ {
+ locatorRegistry.setReplicatedAdapterDirectProxy(_id, _replicaGroupId, proxy);
+ }
+ }
+ catch(AdapterNotFoundException)
+ {
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
+ s.Append("the object adapter is not known to the locator registry");
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+
+ NotRegisteredException ex1 = new NotRegisteredException();
+ ex1.kindOfObject = "object adapter";
+ ex1.id = _id;
+ throw ex1;
+ }
+ catch(InvalidReplicaGroupIdException)
+ {
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
+ s.Append("the replica group `" + _replicaGroupId + "' is not known to the locator registry");
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+
+ NotRegisteredException ex1 = new NotRegisteredException();
+ ex1.kindOfObject = "replica group";
+ ex1.id = _replicaGroupId;
+ throw ex1;
+ }
+ catch(AdapterAlreadyActiveException)
+ {
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
+ s.Append("the object adapter endpoints are already set");
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+
+ ObjectAdapterIdInUseException ex1 = new ObjectAdapterIdInUseException();
+ ex1.id = _id;
+ throw;
+ }
+ catch(LocalException e)
+ {
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
+ s.Append(e.ToString());
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+ throw; // TODO: Shall we raise a special exception instead of a non obvious local exception?
+ }
+
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("updated object adapter `" + _id + "' endpoints with the locator registry\n");
+ s.Append("endpoints = ");
+ if(proxy != null)
+ {
+ Ice.Endpoint[] endpoints = proxy.ice_getEndpoints();
+ for(int i = 0; i < endpoints.Length; i++)
+ {
+ s.Append(endpoints[i].ToString());
+ if(i + 1 < endpoints.Length)
+ {
+ s.Append(":");
+ }
+ }
+ }
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+ }
+
+ if(registerProcess && serverId.Length > 0)
+ {
+ lock(this)
+ {
+ if(_processId == null)
+ {
+ Process servant = new ProcessI(_communicator);
+ _processId = addWithUUID(servant).ice_getIdentity();
+ }
+ }
+
+ try
+ {
+ locatorRegistry.setServerProcessProxy(serverId,
+ ProcessPrxHelper.uncheckedCast(createDirectProxy(_processId)));
+ }
+ catch(ServerNotFoundException)
+ {
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't register server `" + serverId + "' with the locator registry:\n");
+ s.Append("the server is not known to the locator registry");
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+
+ NotRegisteredException ex1 = new NotRegisteredException();
+ ex1.id = serverId;
+ ex1.kindOfObject = "server";
+ throw ex1;
+ }
+ catch(LocalException ex)
+ {
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("couldn't register server `" + serverId + "' with the locator registry:\n" + ex);
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+ throw; // TODO: Shall we raise a special exception instead of a non obvious local exception?
+ }
+
+ if(instance_.traceLevels().location >= 1)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("registered server `" + serverId + "' with the locator registry");
+ instance_.initializationData().logger.trace(instance_.traceLevels().locationCat, s.ToString());
+ }
+ }
+ }
+
+ static private readonly string[] _suffixes =
+ {
+ "ACM",
+ "ACM.Timeout",
+ "ACM.Heartbeat",
+ "ACM.Close",
+ "AdapterId",
+ "Endpoints",
+ "Locator",
+ "Locator.EncodingVersion",
+ "Locator.EndpointSelection",
+ "Locator.ConnectionCached",
+ "Locator.PreferSecure",
+ "Locator.CollocationOptimized",
+ "Locator.Router",
+ "MessageSizeMax",
+ "PublishedEndpoints",
+ "RegisterProcess",
+ "ReplicaGroupId",
+ "Router",
+ "Router.EncodingVersion",
+ "Router.EndpointSelection",
+ "Router.ConnectionCached",
+ "Router.PreferSecure",
+ "Router.CollocationOptimized",
+ "Router.Locator",
+ "Router.Locator.EndpointSelection",
+ "Router.Locator.ConnectionCached",
+ "Router.Locator.PreferSecure",
+ "Router.Locator.CollocationOptimized",
+ "Router.Locator.LocatorCacheTimeout",
+ "Router.Locator.InvocationTimeout",
+ "Router.LocatorCacheTimeout",
+ "Router.InvocationTimeout",
+ "ProxyOptions",
+ "ThreadPool.Size",
+ "ThreadPool.SizeMax",
+ "ThreadPool.SizeWarn",
+ "ThreadPool.StackSize",
+ "ThreadPool.Serialize"
+ };
+
+ private bool filterProperties(List<string> unknownProps)
+ {
+ //
+ // Do not create unknown properties list if Ice prefix, ie Ice, Glacier2, etc
+ //
+ bool addUnknown = true;
+ String prefix = _name + ".";
+ for(int i = 0; PropertyNames.clPropNames[i] != null; ++i)
+ {
+ if(prefix.StartsWith(PropertyNames.clPropNames[i] + ".", StringComparison.Ordinal))
+ {
+ addUnknown = false;
+ break;
+ }
+ }
+
+ bool noProps = true;
+ Dictionary<string, string> props =
+ instance_.initializationData().properties.getPropertiesForPrefix(prefix);
+ foreach(String prop in props.Keys)
+ {
+ bool valid = false;
+ for(int i = 0; i < _suffixes.Length; ++i)
+ {
+ if(prop.Equals(prefix + _suffixes[i]))
+ {
+ noProps = false;
+ valid = true;
+ break;
+ }
+ }
+
+ if(!valid && addUnknown)
+ {
+ unknownProps.Add(prop);
+ }
+ }
+
+ return noProps;
+ }
+
+ private const int StateUninitialized = 0; // Just constructed.
+ private const int StateHeld = 1;
+ private const int StateActivating = 2;
+ private const int StateActive = 3;
+ private const int StateDeactivating = 4;
+ private const int StateDeactivated = 5;
+ private const int StateDestroying = 6;
+ private const int StateDestroyed = 7;
+
+ private int state_ = StateUninitialized;
+ private Instance instance_;
+ private Communicator _communicator;
+ private ObjectAdapterFactory _objectAdapterFactory;
+ private ThreadPool _threadPool;
+ private ACMConfig _acm;
+ private ServantManager _servantManager;
+ private readonly string _name;
+ private readonly string _id;
+ private readonly string _replicaGroupId;
+ private Reference _reference;
+ private List<IncomingConnectionFactory> _incomingConnectionFactories;
+ private List<EndpointI> _routerEndpoints;
+ private RouterInfo _routerInfo;
+ private List<EndpointI> _publishedEndpoints;
+ private LocatorInfo _locatorInfo;
+ private int _directCount; // The number of direct proxies dispatching on this object adapter.
+ private bool _noConfig;
+ private Identity _processId;
+ private int _messageSizeMax;
+ }
+}
diff --git a/csharp/src/Ice/ObjectFactoryManager.cs b/csharp/src/Ice/ObjectFactoryManager.cs
new file mode 100644
index 00000000000..e211713ed55
--- /dev/null
+++ b/csharp/src/Ice/ObjectFactoryManager.cs
@@ -0,0 +1,86 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections.Generic;
+
+ public sealed class ObjectFactoryManager
+ {
+ public void add(Ice.ObjectFactory factory, string id)
+ {
+ lock(this)
+ {
+ if(_factoryMap.ContainsKey(id))
+ {
+ Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException();
+ ex.id = id;
+ ex.kindOfObject = "object factory";
+ throw ex;
+ }
+ _factoryMap[id] = factory;
+ }
+ }
+
+ public void remove(string id)
+ {
+ object o = null;
+ lock(this)
+ {
+ if(!_factoryMap.ContainsKey(id))
+ {
+ Ice.NotRegisteredException ex = new Ice.NotRegisteredException();
+ ex.id = id;
+ ex.kindOfObject = "object factory";
+ throw ex;
+ }
+ _factoryMap.Remove(id);
+ }
+ ((Ice.ObjectFactory)o).destroy();
+ }
+
+ public Ice.ObjectFactory find(string id)
+ {
+ lock(this)
+ {
+ Ice.ObjectFactory factory = null;
+ _factoryMap.TryGetValue(id, out factory);
+ return factory;
+ }
+ }
+
+ //
+ // Only for use by Instance
+ //
+ internal ObjectFactoryManager()
+ {
+ _factoryMap = new Dictionary<string, Ice.ObjectFactory>();
+ }
+
+ internal void destroy()
+ {
+ Dictionary<string, Ice.ObjectFactory> oldMap = null;
+
+ lock(this)
+ {
+ oldMap = _factoryMap;
+ _factoryMap = new Dictionary<string, Ice.ObjectFactory>();
+ }
+
+ foreach(Ice.ObjectFactory factory in oldMap.Values)
+ {
+ factory.destroy();
+ }
+ }
+
+ private Dictionary<string, Ice.ObjectFactory> _factoryMap;
+ }
+
+}
diff --git a/csharp/src/Ice/ObserverHelper.cs b/csharp/src/Ice/ObserverHelper.cs
new file mode 100644
index 00000000000..82067242da7
--- /dev/null
+++ b/csharp/src/Ice/ObserverHelper.cs
@@ -0,0 +1,63 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Collections.Generic;
+ using Ice.Instrumentation;
+
+ public sealed class ObserverHelper
+ {
+ static public InvocationObserver get(Instance instance, string op)
+ {
+ CommunicatorObserver obsv = instance.initializationData().observer;
+ if(obsv != null)
+ {
+ InvocationObserver observer = obsv.getInvocationObserver(null, op, _emptyContext);
+ if(observer != null)
+ {
+ observer.attach();
+ }
+ return observer;
+ }
+ return null;
+ }
+
+ static public InvocationObserver get(Ice.ObjectPrx proxy, string op)
+ {
+ return get(proxy, op, null);
+ }
+
+ static public InvocationObserver get(Ice.ObjectPrx proxy, string op, Dictionary<string, string> context)
+ {
+ CommunicatorObserver obsv =
+ ((Ice.ObjectPrxHelperBase)proxy).reference__().getInstance().initializationData().observer;
+ if(obsv != null)
+ {
+ InvocationObserver observer;
+ if(context == null)
+ {
+ observer = obsv.getInvocationObserver(proxy, op, _emptyContext);
+ }
+ else
+ {
+ observer = obsv.getInvocationObserver(proxy, op, context);
+ }
+ if(observer != null)
+ {
+ observer.attach();
+ }
+ return observer;
+ }
+ return null;
+ }
+
+ private static Dictionary<string, string> _emptyContext = new Dictionary<string, string>();
+ }
+} \ No newline at end of file
diff --git a/csharp/src/Ice/OpaqueEndpointI.cs b/csharp/src/Ice/OpaqueEndpointI.cs
new file mode 100644
index 00000000000..2bf92073e34
--- /dev/null
+++ b/csharp/src/Ice/OpaqueEndpointI.cs
@@ -0,0 +1,428 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Globalization;
+
+ sealed class OpaqueEndpointI : EndpointI
+ {
+ public OpaqueEndpointI(List<string> args)
+ {
+ _type = -1;
+ _rawEncoding = Ice.Util.Encoding_1_0;
+ _rawBytes = new byte[0];
+
+ initWithOptions(args);
+
+ if(_type < 0)
+ {
+ throw new Ice.EndpointParseException("no -t option in endpoint " + ToString());
+ }
+ if(_rawBytes.Length == 0)
+ {
+ throw new Ice.EndpointParseException("no -v option in endpoint " + ToString());
+ }
+
+ calcHashValue();
+ }
+
+ public OpaqueEndpointI(short type, BasicStream s)
+ {
+ _type = type;
+ _rawEncoding = s.getReadEncoding();
+ int sz = s.getReadEncapsSize();
+ _rawBytes = new byte[sz];
+ s.readBlob(_rawBytes);
+
+ calcHashValue();
+ }
+
+ //
+ // Marshal the endpoint
+ //
+ public override void streamWrite(BasicStream s)
+ {
+ s.startWriteEncaps(_rawEncoding, Ice.FormatType.DefaultFormat);
+ s.writeBlob(_rawBytes);
+ s.endWriteEncaps();
+ }
+
+ //
+ // Convert the endpoint to its string form
+ //
+ public override string ice_toString_()
+ {
+ string val = IceUtilInternal.Base64.encode(_rawBytes);
+ return "opaque -t " + _type + " -e " + Ice.Util.encodingVersionToString(_rawEncoding) + " -v " + val;
+ }
+
+ private sealed class InfoI : Ice.OpaqueEndpointInfo
+ {
+ public InfoI(short type, Ice.EncodingVersion rawEncoding, byte[] rawBytes) :
+ base(-1, false, rawEncoding, rawBytes)
+ {
+ _type = type;
+ }
+
+ override public short type()
+ {
+ return _type;
+ }
+
+ override public bool datagram()
+ {
+ return false;
+ }
+
+ override public bool secure()
+ {
+ return false;
+ }
+
+ private readonly short _type;
+ }
+
+ //
+ // Return the endpoint information.
+ //
+ public override Ice.EndpointInfo getInfo()
+ {
+ return new InfoI(_type, _rawEncoding, _rawBytes);
+ }
+
+ //
+ // Return the endpoint type
+ //
+ public override short type()
+ {
+ return _type;
+ }
+
+ //
+ // Return the protocol name;
+ //
+ public override string protocol()
+ {
+ return "opaque";
+ }
+
+ //
+ // Return the timeout for the endpoint in milliseconds. 0 means
+ // non-blocking, -1 means no timeout.
+ //
+ public override int timeout()
+ {
+ return -1;
+ }
+
+ //
+ // Return a new endpoint with a different timeout value, provided
+ // that timeouts are supported by the endpoint. Otherwise the same
+ // endpoint is returned.
+ //
+ public override EndpointI timeout(int t)
+ {
+ return this;
+ }
+
+ public override string connectionId()
+ {
+ return "";
+ }
+
+ //
+ // Return a new endpoint with a different connection id.
+ //
+ public override EndpointI connectionId(string id)
+ {
+ return this;
+ }
+
+ //
+ // Return true if the endpoints support bzip2 compress, or false
+ // otherwise.
+ //
+ public override bool compress()
+ {
+ return false;
+ }
+
+ //
+ // Return a new endpoint with a different compression value,
+ // provided that compression is supported by the
+ // endpoint. Otherwise the same endpoint is returned.
+ //
+ public override EndpointI compress(bool compress)
+ {
+ return this;
+ }
+
+ //
+ // Return true if the endpoint is datagram-based.
+ //
+ public override bool datagram()
+ {
+ return false;
+ }
+
+ //
+ // Return true if the endpoint is secure.
+ //
+ public override bool secure()
+ {
+ return false;
+ }
+
+ //
+ // Get the encoded endpoint.
+ //
+ public byte[] rawBytes()
+ {
+ return _rawBytes;
+ }
+
+ //
+ // Return a server side transceiver for this endpoint, or null if a
+ // transceiver can only be created by an acceptor.
+ //
+ public override Transceiver transceiver()
+ {
+ return null;
+ }
+
+ //
+ // Return connectors for this endpoint, or empty list if no connector
+ // is available.
+ //
+ public override void connectors_async(Ice.EndpointSelectionType endSel, EndpointI_connectors callback)
+ {
+ callback.connectors(new List<Connector>());
+ }
+
+ //
+ // Return an acceptor for this endpoint, or null if no acceptors
+ // is available.
+ //
+ public override Acceptor acceptor(string adapterName)
+ {
+ return null;
+ }
+
+ //
+ // Expand endpoint out in to separate endpoints for each local
+ // host if listening on INADDR_ANY on server side or if no host
+ // was specified on client side.
+ //
+ public override List<EndpointI> expand()
+ {
+ List<EndpointI> endps = new List<EndpointI>();
+ endps.Add(this);
+ return endps;
+ }
+
+ //
+ // Check whether the endpoint is equivalent to another one.
+ //
+ public override bool equivalent(EndpointI endpoint)
+ {
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return _hashCode;
+ }
+
+ public override string options()
+ {
+ string s = "";
+ if(_type > -1)
+ {
+ s += " -t " + _type;
+ }
+ s += " -e " + Ice.Util.encodingVersionToString(_rawEncoding);
+ if(_rawBytes.Length > 0)
+ {
+ s += " -v " + IceUtilInternal.Base64.encode(_rawBytes);
+ }
+ return s;
+ }
+
+ //
+ // Compare endpoints for sorting purposes
+ //
+ public override int CompareTo(EndpointI obj)
+ {
+ if(!(obj is OpaqueEndpointI))
+ {
+ return type() < obj.type() ? -1 : 1;
+ }
+
+ OpaqueEndpointI p = (OpaqueEndpointI)obj;
+ if(this == p)
+ {
+ return 0;
+ }
+
+ if(_type < p._type)
+ {
+ return -1;
+ }
+ else if(p._type < _type)
+ {
+ return 1;
+ }
+
+ if(_rawEncoding.major < p._rawEncoding.major)
+ {
+ return -1;
+ }
+ else if(p._rawEncoding.major < _rawEncoding.major)
+ {
+ return 1;
+ }
+
+ if(_rawEncoding.minor < p._rawEncoding.minor)
+ {
+ return -1;
+ }
+ else if(p._rawEncoding.minor < _rawEncoding.minor)
+ {
+ return 1;
+ }
+
+ if(_rawBytes.Length < p._rawBytes.Length)
+ {
+ return -1;
+ }
+ else if(p._rawBytes.Length < _rawBytes.Length)
+ {
+ return 1;
+ }
+ for(int i = 0; i < _rawBytes.Length; i++)
+ {
+ if(_rawBytes[i] < p._rawBytes[i])
+ {
+ return -1;
+ }
+ else if(p._rawBytes[i] < _rawBytes[i])
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ protected override bool checkOption(string option, string argument, string endpoint)
+ {
+ switch(option[1])
+ {
+ case 't':
+ {
+ if(_type > -1)
+ {
+ throw new Ice.EndpointParseException("multiple -t options in endpoint " + endpoint);
+ }
+ if(argument == null)
+ {
+ throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " + endpoint);
+ }
+
+ int t;
+ try
+ {
+ t = System.Int32.Parse(argument, CultureInfo.InvariantCulture);
+ }
+ catch(System.FormatException)
+ {
+ throw new Ice.EndpointParseException("invalid type value `" + argument + "' in endpoint " +
+ endpoint);
+ }
+
+ if(t < 0 || t > 65535)
+ {
+ throw new Ice.EndpointParseException("type value `" + argument + "' out of range in endpoint " +
+ endpoint);
+ }
+
+ _type = (short)t;
+ return true;
+ }
+
+ case 'v':
+ {
+ if(_rawBytes.Length > 0)
+ {
+ throw new Ice.EndpointParseException("multiple -v options in endpoint " + endpoint);
+ }
+ if(argument == null)
+ {
+ throw new Ice.EndpointParseException("no argument provided for -v option in endpoint " + endpoint);
+ }
+
+ for(int j = 0; j < argument.Length; ++j)
+ {
+ if(!IceUtilInternal.Base64.isBase64(argument[j]))
+ {
+ throw new Ice.EndpointParseException("invalid base64 character `" + argument[j] +
+ "' (ordinal " + ((int)argument[j]) +
+ ") in endpoint " + endpoint);
+ }
+ }
+ _rawBytes = IceUtilInternal.Base64.decode(argument);
+ return true;
+ }
+
+ case 'e':
+ {
+ if(argument == null)
+ {
+ throw new Ice.EndpointParseException("no argument provided for -e option in endpoint " + endpoint);
+ }
+
+ try
+ {
+ _rawEncoding = Ice.Util.stringToEncodingVersion(argument);
+ }
+ catch(Ice.VersionParseException e)
+ {
+ throw new Ice.EndpointParseException("invalid encoding version `" + argument +
+ "' in endpoint " + endpoint + ":\n" + e.str);
+ }
+ return true;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
+ private void calcHashValue()
+ {
+ int h = 5381;
+ IceInternal.HashUtil.hashAdd(ref h, _type);
+ IceInternal.HashUtil.hashAdd(ref h, _rawEncoding);
+ IceInternal.HashUtil.hashAdd(ref h, _rawBytes);
+ _hashCode = h;
+ }
+
+ private short _type;
+ private Ice.EncodingVersion _rawEncoding;
+ private byte[] _rawBytes;
+ private int _hashCode;
+ }
+
+}
diff --git a/csharp/src/Ice/Optional.cs b/csharp/src/Ice/Optional.cs
new file mode 100644
index 00000000000..8527f87ccf9
--- /dev/null
+++ b/csharp/src/Ice/Optional.cs
@@ -0,0 +1,262 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Runtime.Serialization;
+
+ public struct NoneType
+ {
+ }
+
+ /// <summary>
+ /// Encapsulates an optional value. Instances of this type are immutable.
+ /// </summary>
+#if SILVERLIGHT
+ public struct Optional<T>
+#else
+ [Serializable]
+ public struct Optional<T> : ISerializable
+#endif
+ {
+ /// <summary>
+ /// Creates an optional value whose state is unset.
+ /// </summary>
+ public Optional(NoneType none)
+ {
+ _value = default(T);
+ _isSet = false;
+ }
+
+ /// <summary>
+ /// Creates an optional value and sets its value to the given argument.
+ /// </summary>
+ public Optional(T v)
+ {
+ _value = v;
+ _isSet = true;
+ }
+
+ /// <summary>
+ /// Creates an optional value whose state is copied from the given argument.
+ /// </summary>
+ public Optional(Optional<T> v)
+ {
+ _value = v._value;
+ _isSet = v._isSet;
+ }
+
+#if !SILVERLIGHT
+ /// <summary>
+ /// Initializes a new instance of the exception with serialized data.
+ /// </summary>
+ /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
+ /// <param name="context">Contains contextual information about the source or destination.</param>
+ public Optional(SerializationInfo info, StreamingContext context)
+ {
+ _isSet = info.GetBoolean("isSet");
+ if(_isSet)
+ {
+ _value = (T)info.GetValue("value", typeof(T));
+ }
+ else
+ {
+ _value = default(T);
+ }
+ }
+#endif
+
+ /// <summary>
+ /// Conversion operator to the underlying type; a cast is required. An exception
+ /// is raised if no value is set.
+ /// </summary>
+ /// <returns>The encapsulated value.</returns>
+ /// <exception cref="System.InvalidOperationException">Thrown if no value is set.</exception>
+ public static explicit operator T(Optional<T> v)
+ {
+ return v.Value;
+ }
+
+ /// <summary>
+ /// Conversion operator from a value of the underlying type; no cast is required.
+ /// </summary>
+ public static implicit operator Optional<T>(T v)
+ {
+ return new Optional<T>(v);
+ }
+
+ /// <summary>
+ /// Conversion operator from a None value; no cast is required.
+ /// </summary>
+ public static implicit operator Optional<T>(NoneType v)
+ {
+ return new Optional<T>();
+ }
+
+ /// <summary>
+ /// Reads and writes the encapsulated value.
+ /// </summary>
+ /// <exception cref="System.InvalidOperationException">Thrown if the property is read and no value is
+ /// set.</exception>
+ public T Value
+ {
+ get
+ {
+ if(!_isSet)
+ {
+ throw new System.InvalidOperationException();
+ }
+ return _value;
+ }
+ }
+
+ /// <summary>
+ /// Determines whether a value is set.
+ /// </summary>
+ /// <returns>True if a value is set, false otherwise.</returns>
+ public bool HasValue
+ {
+ get
+ {
+ return _isSet;
+ }
+ }
+
+ public override bool Equals(object other)
+ {
+ if(object.ReferenceEquals(this, other))
+ {
+ return true;
+ }
+ if(other == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ Optional<T> o2 = (Optional<T>)other;
+
+ if(_isSet != o2._isSet)
+ {
+ return false;
+ }
+ else if(_isSet)
+ {
+ EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+ return comparer.Equals(_value, o2._value);
+ }
+
+ return true;
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ if(!_isSet)
+ {
+ return base.GetHashCode();
+ }
+ else
+ {
+ return _value.GetHashCode();
+ }
+ }
+
+#if !SILVERLIGHT
+ /// <summary>
+ /// Serializes an optional value.
+ /// </summary>
+ /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
+ /// <param name="context">Contains contextual information about the source or destination.</param>
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ info.AddValue("isSet", _isSet);
+ if(_isSet)
+ {
+ info.AddValue("value", _value, typeof(T));
+ }
+ }
+#endif
+
+ private T _value;
+ private bool _isSet;
+ }
+
+ /// <summary>
+ /// Handles callbacks for an optional object parameter.
+ /// </summary>
+ public class OptionalPatcher<T> : IceInternal.Patcher
+ where T : Ice.Object
+ {
+ /// <summary>
+ /// Instantiates the class with the given optional.
+ /// </summary>
+ /// <param name="type">The Slice type ID corresponding to the formal type.</param>
+ public OptionalPatcher(string type) :
+ base(type)
+ {
+ }
+
+ /// <summary>
+ /// Sets the Ice object of the optional to the passed instance.
+ /// </summary>
+ /// <param name="v">The new object for the optional.</param>
+ public override void patch(Ice.Object v)
+ {
+ if(v == null || typeof(T).IsAssignableFrom(v.GetType()))
+ {
+ //
+ // The line below must assign to the Value property. We could also
+ // have written it this way:
+ //
+ // this.opt = (T)v;
+ //
+ // However, when v is null, the optional might be cleared, which
+ // is not the result we want.
+ //
+ this.value = new Optional<T>((T)v);
+ }
+ else
+ {
+ IceInternal.Ex.throwUOE(type(), v.ice_id());
+ }
+ }
+
+ /// <summary>
+ /// The target optional.
+ /// </summary>
+ public Optional<T> value = new Optional<T>();
+ }
+
+ /// <summary>
+ /// The optional format.
+ ///
+ /// An optional value is encoded with a specific optional format. This optional
+ /// format describes how the data is encoded and how it can be skipped by the
+ /// unmarshaling code if the optional is not known to the receiver.
+ /// </summary>
+ public enum OptionalFormat
+ {
+ F1 = 0,
+ F2 = 1,
+ F4 = 2,
+ F8 = 3,
+ Size = 4,
+ VSize = 5,
+ FSize = 6,
+ Class = 7
+ }
+}
diff --git a/csharp/src/Ice/Options.cs b/csharp/src/Ice/Options.cs
new file mode 100644
index 00000000000..8303758c928
--- /dev/null
+++ b/csharp/src/Ice/Options.cs
@@ -0,0 +1,406 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+
+namespace IceUtilInternal
+{
+ public sealed class Options
+ {
+ public sealed class BadQuote : System.Exception
+ {
+ public BadQuote(string message) : base(message)
+ {
+ }
+ }
+
+ enum State { Normal, DoubleQuote, SingleQuote, ANSIQuote };
+
+ static public string[]
+ split(string line)
+ {
+ string IFS = " \t\n";
+
+ string l = line.Trim();
+ if(l.Length == 0)
+ {
+ return new string[0];
+ }
+
+ State state = State.Normal;
+
+ string arg = "";
+ List<string> vec = new List<string>();
+
+ for(int i = 0; i < l.Length; ++i)
+ {
+ char c = l[i];
+ switch(state)
+ {
+ case State.Normal:
+ {
+ switch(c)
+ {
+ case '\\':
+ {
+ //
+ // Ignore a backslash at the end of the string,
+ // and strip backslash-newline pairs. If a
+ // backslash is followed by a space, single quote,
+ // double quote, or dollar sign, we drop the backslash
+ // and write the space, single quote, double quote,
+ // or dollar sign. This is necessary to allow quotes
+ // to be escaped. Dropping the backslash preceding a
+ // space deviates from bash quoting rules, but is
+ // necessary so we don't drop backslashes from Windows
+ // path names.)
+ //
+ if(i < l.Length - 1 && l[++i] != '\n')
+ {
+ switch(l[i])
+ {
+ case ' ':
+ case '$':
+ case '\'':
+ case '"':
+ {
+ arg += l[i];
+ break;
+ }
+ default:
+ {
+ arg += '\\';
+ arg += l[i];
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case '\'':
+ {
+ state = State.SingleQuote;
+ break;
+ }
+ case '"':
+ {
+ state = State.DoubleQuote;
+ break;
+ }
+ case '$':
+ {
+ if(i < l.Length - 1 && l[i + 1] == '\'')
+ {
+ state = State.ANSIQuote; // Bash uses $'<text>' to allow ANSI escape sequences
+ // within <text>.
+ ++i;
+ }
+ else
+ {
+ arg += '$';
+ }
+ break;
+ }
+ default:
+ {
+ if(IFS.IndexOf(l[i]) != -1)
+ {
+ vec.Add(arg);
+ arg = "";
+
+ //
+ // Move to start of next argument.
+ //
+ while(++i < l.Length && IFS.IndexOf(l[i]) != -1)
+ {
+ ;
+ }
+ --i;
+ }
+ else
+ {
+ arg += l[i];
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case State.DoubleQuote:
+ {
+ //
+ // Within double quotes, only backslash retains its special
+ // meaning, and only if followed by double quote, backslash,
+ // or newline. If not followed by one of these characters,
+ // both the backslash and the character are preserved.
+ //
+ if(c == '\\' && i < l.Length - 1)
+ {
+ switch(c = l[++i])
+ {
+ case '"':
+ case '\\':
+ case '\n':
+ {
+ arg += c;
+ break;
+ }
+ default:
+ {
+ arg += '\\';
+ arg += c;
+ break;
+ }
+ }
+ }
+ else if(c == '"') // End of double-quote mode.
+ {
+ state = State.Normal;
+ }
+ else
+ {
+ arg += c; // Everything else is taken literally.
+ }
+ break;
+ }
+ case State.SingleQuote:
+ {
+ if(c == '\'') // End of single-quote mode.
+ {
+ state = State.Normal;
+ }
+ else
+ {
+ arg += c; // Everything else is taken literally.
+ }
+ break;
+ }
+ case State.ANSIQuote:
+ {
+ switch(c)
+ {
+ case '\\':
+ {
+ if(i == l.Length - 1)
+ {
+ break;
+ }
+ switch(c = l[++i])
+ {
+ //
+ // Single-letter escape sequences.
+ //
+ case 'a':
+ {
+ arg += '\a';
+ break;
+ }
+ case 'b':
+ {
+ arg += '\b';
+ break;
+ }
+ case 'f':
+ {
+ arg += '\f';
+ break;
+ }
+ case 'n':
+ {
+ arg += '\n';
+ break;
+ }
+ case 'r':
+ {
+ arg += '\r';
+ break;
+ }
+ case 't':
+ {
+ arg += '\t';
+ break;
+ }
+ case 'v':
+ {
+ arg += '\v';
+ break;
+ }
+ case '\\':
+ {
+ arg += '\\';
+ break;
+ }
+ case '\'':
+ {
+ arg += '\'';
+ break;
+ }
+ case 'e': // Not ANSI-C, but used by bash.
+ {
+ arg += '\u001B';
+ break;
+ }
+
+ //
+ // Process up to three octal digits.
+ //
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ const string octalDigits = "01234567";
+ short s = 0;
+ int j;
+ for(j = i; j < i + 3 && j < l.Length && octalDigits.IndexOf(c = l[j]) != -1; ++j)
+ {
+ s = (short)(s * 8 + c - '0');
+ }
+ i = j - 1;
+ arg += (char)s;
+ break;
+ }
+
+ //
+ // Process up to two hex digits.
+ //
+ case 'x':
+ {
+ const string hexDigits = "0123456789abcdefABCDEF";
+ if(i < l.Length - 1 && hexDigits.IndexOf(l[i + 1]) == -1)
+ {
+ arg += '\\';
+ arg += 'x';
+ break;
+ }
+
+ short s = 0;
+ int j;
+ for(j = i + 1;
+ j < i + 3 && j < l.Length && hexDigits.IndexOf(c = l[j]) != -1;
+ ++j)
+ {
+ s *= 16;
+ if(char.IsDigit(c))
+ {
+ s += (short)(c - '0');
+ }
+ else if(char.IsLower(c))
+ {
+ s += (short)(c - 'a' + 10);
+ }
+ else
+ {
+ s += (short)(c - 'A' + 10);
+ }
+ }
+ i = j - 1;
+ arg += (char)s;
+ break;
+ }
+
+ //
+ // Process control-chars.
+ //
+ case 'c':
+ {
+ c = l[++i];
+ if((char.ToUpper(c, CultureInfo.InvariantCulture) >= 'A' && char.ToUpper(c, CultureInfo.InvariantCulture) <= 'Z') ||
+ c == '@' ||
+ (c >= '[' && c <= '_'))
+ {
+ arg += (char)(char.ToUpper(c, CultureInfo.InvariantCulture) - '@');
+ }
+ else
+ {
+ //
+ // Bash does not define what should happen if a \c
+ // is not followed by a recognized control character.
+ // We simply treat this case like other unrecognized
+ // escape sequences, that is, we preserve the escape
+ // sequence unchanged.
+ //
+ arg += '\\';
+ arg += 'c';
+ arg += c;
+ }
+ break;
+ }
+
+ //
+ // If inside an ANSI-quoted string, a backslash isn't followed by
+ // one of the recognized characters, both the backslash and the
+ // character are preserved.
+ //
+ default:
+ {
+ arg += '\\';
+ arg += c;
+ break;
+ }
+ }
+ break;
+ }
+ case '\'': // End of ANSI-quote mode.
+ {
+ state = State.Normal;
+ break;
+ }
+ default:
+ {
+ arg += c; // Everything else is taken literally.
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+ }
+
+ switch(state)
+ {
+ case State.Normal:
+ {
+ vec.Add(arg);
+ break;
+ }
+ case State.SingleQuote:
+ {
+ throw new BadQuote("missing closing single quote");
+ }
+ case State.DoubleQuote:
+ {
+ throw new BadQuote("missing closing double quote");
+ }
+ case State.ANSIQuote:
+ {
+ throw new BadQuote("unterminated $' quote");
+ }
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+
+ return (string[])vec.ToArray();
+ }
+ }
+}
diff --git a/csharp/src/Ice/OutgoingAsync.cs b/csharp/src/Ice/OutgoingAsync.cs
new file mode 100644
index 00000000000..8b71e65c81f
--- /dev/null
+++ b/csharp/src/Ice/OutgoingAsync.cs
@@ -0,0 +1,1267 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Threading;
+
+ public class OutgoingAsyncBase : AsyncResultI
+ {
+ public virtual Ice.AsyncCallback sent()
+ {
+ return sent(true);
+ }
+
+ public virtual Ice.AsyncCallback completed(Ice.Exception ex)
+ {
+ return finished(ex);
+ }
+
+ public virtual Ice.AsyncCallback completed()
+ {
+ Debug.Assert(false); // Must be implemented by classes that handle responses
+ return null;
+ }
+
+ public void attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, int requestId)
+ {
+ if(observer_ != null)
+ {
+ int size = os_.size() - Protocol.headerSize - 4;
+ childObserver_ = getObserver().getRemoteObserver(info, endpt, requestId, size);
+ if(childObserver_ != null)
+ {
+ childObserver_.attach();
+ }
+ }
+ }
+
+ public void attachCollocatedObserver(Ice.ObjectAdapter adapter, int requestId)
+ {
+ if(observer_ != null)
+ {
+ int size = os_.size() - Protocol.headerSize - 4;
+ childObserver_ = getObserver().getCollocatedObserver(adapter, requestId, size);
+ if(childObserver_ != null)
+ {
+ childObserver_.attach();
+ }
+ }
+ }
+
+ public IceInternal.BasicStream getOs()
+ {
+ return os_;
+ }
+
+ public virtual IceInternal.BasicStream getIs()
+ {
+ return null; // Must be implemented by classes that handle responses
+ }
+
+ protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, string op, object cookie) :
+ base(com, instance, op, cookie)
+ {
+ os_ = new BasicStream(instance, Ice.Util.currentProtocolEncoding);
+ }
+
+ protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, string op, object cookie, BasicStream os) :
+ base(com, instance, op, cookie)
+ {
+ os_ = os;
+ }
+
+ protected new Ice.AsyncCallback sent(bool done)
+ {
+ if(done)
+ {
+ if(childObserver_ != null)
+ {
+ childObserver_.detach();
+ childObserver_ = null;
+ }
+ }
+ return base.sent(done);
+ }
+
+ protected new Ice.AsyncCallback finished(Ice.Exception ex)
+ {
+ if(childObserver_ != null)
+ {
+ childObserver_.failed(ex.ice_name());
+ childObserver_.detach();
+ childObserver_ = null;
+ }
+ return base.finished(ex);
+ }
+
+ protected BasicStream os_;
+ protected Ice.Instrumentation.ChildInvocationObserver childObserver_;
+ }
+
+ //
+ // Base class for proxy based invocations. This class handles the
+ // retry for proxy invocations. It also ensures the child observer is
+ // correct notified of failures and make sure the retry task is
+ // correctly canceled when the invocation completes.
+ //
+ public abstract class ProxyOutgoingAsyncBase : OutgoingAsyncBase, TimerTask
+ {
+ public static ProxyOutgoingAsyncBase check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation)
+ {
+ return ProxyOutgoingAsyncBase.check<ProxyOutgoingAsyncBase>(r, prx, operation);
+ }
+
+ public abstract bool invokeRemote(Ice.ConnectionI con, bool compress, bool resp, out Ice.AsyncCallback cb);
+
+ public abstract bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback cb);
+
+ public override Ice.ObjectPrx getProxy()
+ {
+ return proxy_;
+ }
+
+ public override Ice.AsyncCallback completed(Ice.Exception exc)
+ {
+ if(childObserver_ != null)
+ {
+ childObserver_.failed(exc.ice_name());
+ childObserver_.detach();
+ childObserver_ = null;
+ }
+
+ cachedConnection_ = null;
+ if(proxy_.reference__().getInvocationTimeout() == -2)
+ {
+ instance_.timer().cancel(this);
+ }
+
+ //
+ // NOTE: at this point, synchronization isn't needed, no other threads should be
+ // calling on the callback.
+ //
+ try
+ {
+ //
+ // It's important to let the retry queue do the retry even if
+ // the retry interval is 0. This method can be called with the
+ // connection locked so we can't just retry here.
+ //
+ instance_.retryQueue().add(this, handleException(exc));
+ return null;
+ }
+ catch(Ice.Exception ex)
+ {
+ return finished(ex); // No retries, we're done
+ }
+ }
+
+ public void retryException(Ice.Exception ex)
+ {
+ try
+ {
+ //
+ // It's important to let the retry queue do the retry. This is
+ // called from the connect request handler and the retry might
+ // require could end up waiting for the flush of the
+ // connection to be done.
+ //
+ proxy_.updateRequestHandler__(handler_, null); // Clear request handler and always retry.
+ instance_.retryQueue().add(this, 0);
+ }
+ catch(Ice.Exception exc)
+ {
+ Ice.AsyncCallback cb = completed(exc);
+ if(cb != null)
+ {
+ invokeCompletedAsync(cb);
+ }
+ }
+ }
+
+ public override void cancelable(CancellationHandler handler)
+ {
+ if(proxy_.reference__().getInvocationTimeout() == -2 && cachedConnection_ != null)
+ {
+ int timeout = cachedConnection_.timeout();
+ if(timeout > 0)
+ {
+ instance_.timer().schedule(this, timeout);
+ }
+ }
+ base.cancelable(handler);
+ }
+
+ public void retry()
+ {
+ invokeImpl(false);
+ }
+
+ public virtual void abort(Ice.Exception ex)
+ {
+ Debug.Assert(childObserver_ == null);
+ Ice.AsyncCallback cb = finished(ex);
+ if(cb != null)
+ {
+ invokeCompletedAsync(cb);
+ }
+ else if(ex is Ice.CommunicatorDestroyedException)
+ {
+ //
+ // If it's a communicator destroyed exception, don't swallow
+ // it but instead notify the user thread. Even if no callback
+ // was provided.
+ //
+ throw ex;
+ }
+ }
+
+ public void runTimerTask()
+ {
+ if(proxy_.reference__().getInvocationTimeout() == -2)
+ {
+ cancel(new Ice.ConnectionTimeoutException());
+ }
+ else
+ {
+ cancel(new Ice.InvocationTimeoutException());
+ }
+ }
+
+ protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, string op, object cookie) :
+ base(prx.ice_getCommunicator(), prx.reference__().getInstance(), op, cookie)
+ {
+ proxy_ = prx;
+ mode_ = Ice.OperationMode.Normal;
+ _cnt = 0;
+ _sent = false;
+ }
+
+ protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, string op, object cookie, BasicStream os) :
+ base(prx.ice_getCommunicator(), prx.reference__().getInstance(), op, cookie, os)
+ {
+ proxy_ = prx;
+ mode_ = Ice.OperationMode.Normal;
+ _cnt = 0;
+ _sent = false;
+ }
+
+ protected static T check<T>(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation)
+ {
+ if(r != null && r.getProxy() != prx)
+ {
+ throw new System.ArgumentException("Proxy for call to end_" + operation +
+ " does not match proxy that was used to call corresponding begin_" +
+ operation + " method");
+ }
+ return check<T>(r, operation);
+ }
+
+ protected void invokeImpl(bool userThread)
+ {
+ try
+ {
+ if(userThread)
+ {
+ int invocationTimeout = proxy_.reference__().getInvocationTimeout();
+ if(invocationTimeout > 0)
+ {
+ instance_.timer().schedule(this, invocationTimeout);
+ }
+ }
+ else // If not called from the user thread, it's called from the retry queue
+ {
+ if(observer_ != null)
+ {
+ observer_.retried();
+ }
+ }
+
+ while(true)
+ {
+ try
+ {
+ _sent = false;
+ handler_ = proxy_.getRequestHandler__();
+ Ice.AsyncCallback sentCallback;
+ if(handler_.sendAsyncRequest(this, out sentCallback))
+ {
+ if(userThread)
+ {
+ sentSynchronously_ = true;
+ if(sentCallback != null)
+ {
+ invokeSent(sentCallback); // Call from the user thread.
+ }
+ }
+ else
+ {
+ if(sentCallback != null)
+ {
+ invokeSentAsync(sentCallback); // Call from a client thread pool thread.
+ }
+ }
+ }
+ return; // We're done!
+ }
+ catch(RetryException)
+ {
+ proxy_.updateRequestHandler__(handler_, null); // Clear request handler and always retry.
+ }
+ catch(Ice.Exception ex)
+ {
+ if(childObserver_ != null)
+ {
+ childObserver_.failed(ex.ice_name());
+ childObserver_.detach();
+ childObserver_ = null;
+ }
+ int interval = handleException(ex);
+ if(interval > 0)
+ {
+ instance_.retryQueue().add(this, interval);
+ return;
+ }
+ else if(observer_ != null)
+ {
+ observer_.retried();
+ }
+ }
+ }
+ }
+ catch(Ice.Exception ex)
+ {
+ //
+ // If called from the user thread we re-throw, the exception
+ // will be catch by the caller and abort() will be called.
+ //
+ if(userThread)
+ {
+ throw ex;
+ }
+ Ice.AsyncCallback cb = finished(ex); // No retries, we're done
+ if(cb != null)
+ {
+ invokeCompletedAsync(cb);
+ }
+ }
+ }
+
+ protected new Ice.AsyncCallback sent(bool done)
+ {
+ _sent = true;
+ if(done)
+ {
+ if(proxy_.reference__().getInvocationTimeout() != -1)
+ {
+ instance_.timer().cancel(this);
+ }
+ }
+ return base.sent(done);
+ }
+
+ protected new Ice.AsyncCallback finished(Ice.Exception ex)
+ {
+ if(proxy_.reference__().getInvocationTimeout() != -1)
+ {
+ instance_.timer().cancel(this);
+ }
+ return base.finished(ex);
+ }
+
+ protected new Ice.AsyncCallback finished(bool ok)
+ {
+ if(proxy_.reference__().getInvocationTimeout() != -1)
+ {
+ instance_.timer().cancel(this);
+ }
+ return base.finished(ok);
+ }
+
+ protected virtual int handleException(Ice.Exception exc)
+ {
+ return proxy_.handleException__(exc, handler_, mode_, _sent, ref _cnt);
+ }
+
+ protected Ice.ObjectPrxHelperBase proxy_;
+ protected RequestHandler handler_;
+ protected Ice.OperationMode mode_;
+
+ private int _cnt;
+ private bool _sent;
+ }
+
+ public class OutgoingAsync : ProxyOutgoingAsyncBase
+ {
+ public new static OutgoingAsync check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation)
+ {
+ return ProxyOutgoingAsyncBase.check<OutgoingAsync>(r, prx, operation);
+ }
+
+ public OutgoingAsync(Ice.ObjectPrx prx, string operation, object cookie) :
+ base((Ice.ObjectPrxHelperBase)prx, operation, cookie)
+ {
+ _encoding = Protocol.getCompatibleEncoding(proxy_.reference__().getEncoding());
+ _is = null;
+ }
+
+ public OutgoingAsync(Ice.ObjectPrx prx, string operation, object cookie, BasicStream istr, BasicStream ostr) :
+ base((Ice.ObjectPrxHelperBase)prx, operation, cookie, ostr)
+ {
+ _encoding = Protocol.getCompatibleEncoding(proxy_.reference__().getEncoding());
+ _is = istr;
+ }
+
+ public void prepare(string operation, Ice.OperationMode mode, Dictionary<string, string> ctx,
+ bool explicitCtx, bool synchronous)
+ {
+ Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(proxy_.reference__().getProtocol()));
+
+ mode_ = mode;
+ _synchronous = synchronous;
+
+ if(explicitCtx && ctx == null)
+ {
+ ctx = _emptyContext;
+ }
+ observer_ = ObserverHelper.get(proxy_, operation, ctx);
+
+ switch(proxy_.reference__().getMode())
+ {
+ case Reference.Mode.ModeTwoway:
+ case Reference.Mode.ModeOneway:
+ case Reference.Mode.ModeDatagram:
+ {
+ os_.writeBlob(Protocol.requestHdr);
+ break;
+ }
+
+ case Reference.Mode.ModeBatchOneway:
+ case Reference.Mode.ModeBatchDatagram:
+ {
+ proxy_.getBatchRequestQueue__().prepareBatchRequest(os_);
+ break;
+ }
+ }
+
+ Reference rf = proxy_.reference__();
+
+ rf.getIdentity().write__(os_);
+
+ //
+ // For compatibility with the old FacetPath.
+ //
+ string facet = rf.getFacet();
+ if(facet == null || facet.Length == 0)
+ {
+ os_.writeStringSeq(null);
+ }
+ else
+ {
+ string[] facetPath = { facet };
+ os_.writeStringSeq(facetPath);
+ }
+
+ os_.writeString(operation);
+
+ os_.writeByte((byte)mode);
+
+ if(ctx != null)
+ {
+ //
+ // Explicit context
+ //
+ Ice.ContextHelper.write(os_, ctx);
+ }
+ else
+ {
+ //
+ // Implicit context
+ //
+ Ice.ImplicitContextI implicitContext = rf.getInstance().getImplicitContext();
+ Dictionary<string, string> prxContext = rf.getContext();
+
+ if(implicitContext == null)
+ {
+ Ice.ContextHelper.write(os_, prxContext);
+ }
+ else
+ {
+ implicitContext.write(prxContext, os_);
+ }
+ }
+ }
+
+ public override Ice.AsyncCallback sent()
+ {
+ return sent(!proxy_.ice_isTwoway()); // done = true if not a two-way proxy (no response expected)
+ }
+
+ public override bool invokeRemote(Ice.ConnectionI con, bool compress, bool resp, out Ice.AsyncCallback sentCB)
+ {
+ cachedConnection_ = con;
+ return con.sendAsyncRequest(this, compress, resp, 0, out sentCB);
+ }
+
+ public override bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCB)
+ {
+ // The BasicStream cannot be cached if the proxy is not a twoway or there is an invocation timeout set.
+ if(!proxy_.ice_isTwoway() || proxy_.reference__().getInvocationTimeout() != -1)
+ {
+ // Disable caching by marking the streams as cached!
+ state_ |= StateCachedBuffers;
+ }
+ return handler.invokeAsyncRequest(this, 0, _synchronous, out sentCB);
+ }
+
+ public override void abort(Ice.Exception ex)
+ {
+ Reference.Mode mode = proxy_.reference__().getMode();
+ if(mode == Reference.Mode.ModeBatchOneway || mode == Reference.Mode.ModeBatchDatagram)
+ {
+ proxy_.getBatchRequestQueue__().abortBatchRequest(os_);
+ }
+
+ base.abort(ex);
+ }
+
+ public void invoke()
+ {
+ Reference.Mode mode = proxy_.reference__().getMode();
+ if(mode == Reference.Mode.ModeBatchOneway || mode == Reference.Mode.ModeBatchDatagram)
+ {
+ sentSynchronously_ = true;
+ proxy_.getBatchRequestQueue__().finishBatchRequest(os_, proxy_, getOperation());
+ finished(true);
+ return; // Don't call sent/completed callback for batch AMI requests
+ }
+
+ //
+ // NOTE: invokeImpl doesn't throw so this can be called from the
+ // try block with the catch block calling abort() in case of an
+ // exception.
+ //
+ invokeImpl(true); // userThread = true
+ }
+
+ override public Ice.AsyncCallback completed()
+ {
+ Debug.Assert(_is != null); // _is has been initialized prior to this call
+
+ //
+ // NOTE: this method is called from ConnectionI.parseMessage
+ // with the connection locked. Therefore, it must not invoke
+ // any user callbacks.
+ //
+
+ Debug.Assert(proxy_.ice_isTwoway()); // Can only be called for twoways.
+
+ if(childObserver_ != null)
+ {
+ childObserver_.reply(_is.size() - Protocol.headerSize - 4);
+ childObserver_.detach();
+ childObserver_ = null;
+ }
+
+ byte replyStatus;
+ try
+ {
+ replyStatus = _is.readByte();
+
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyOK:
+ {
+ break;
+ }
+
+ case ReplyStatus.replyUserException:
+ {
+ if(observer_ != null)
+ {
+ observer_.userException();
+ }
+ break;
+ }
+
+ case ReplyStatus.replyObjectNotExist:
+ case ReplyStatus.replyFacetNotExist:
+ case ReplyStatus.replyOperationNotExist:
+ {
+ Ice.Identity id = new Ice.Identity();
+ id.read__(_is);
+
+ //
+ // For compatibility with the old FacetPath.
+ //
+ string[] facetPath = _is.readStringSeq();
+ string facet;
+ if(facetPath.Length > 0)
+ {
+ if(facetPath.Length > 1)
+ {
+ throw new Ice.MarshalException();
+ }
+ facet = facetPath[0];
+ }
+ else
+ {
+ facet = "";
+ }
+
+ string operation = _is.readString();
+
+ Ice.RequestFailedException ex = null;
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyObjectNotExist:
+ {
+ ex = new Ice.ObjectNotExistException();
+ break;
+ }
+
+ case ReplyStatus.replyFacetNotExist:
+ {
+ ex = new Ice.FacetNotExistException();
+ break;
+ }
+
+ case ReplyStatus.replyOperationNotExist:
+ {
+ ex = new Ice.OperationNotExistException();
+ break;
+ }
+
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+
+ ex.id = id;
+ ex.facet = facet;
+ ex.operation = operation;
+ throw ex;
+ }
+
+ case ReplyStatus.replyUnknownException:
+ case ReplyStatus.replyUnknownLocalException:
+ case ReplyStatus.replyUnknownUserException:
+ {
+ string unknown = _is.readString();
+
+ Ice.UnknownException ex = null;
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyUnknownException:
+ {
+ ex = new Ice.UnknownException();
+ break;
+ }
+
+ case ReplyStatus.replyUnknownLocalException:
+ {
+ ex = new Ice.UnknownLocalException();
+ break;
+ }
+
+ case ReplyStatus.replyUnknownUserException:
+ {
+ ex = new Ice.UnknownUserException();
+ break;
+ }
+
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+
+ ex.unknown = unknown;
+ throw ex;
+ }
+
+ default:
+ {
+ throw new Ice.UnknownReplyStatusException();
+ }
+ }
+
+ return finished(replyStatus == ReplyStatus.replyOK);
+ }
+ catch(Ice.Exception ex)
+ {
+ return completed(ex);
+ }
+ }
+
+ public BasicStream startWriteParams(Ice.FormatType format)
+ {
+ os_.startWriteEncaps(_encoding, format);
+ return os_;
+ }
+
+ public void endWriteParams()
+ {
+ os_.endWriteEncaps();
+ }
+
+ public void writeEmptyParams()
+ {
+ os_.writeEmptyEncaps(_encoding);
+ }
+
+ public void writeParamEncaps(byte[] encaps)
+ {
+ if(encaps == null || encaps.Length == 0)
+ {
+ os_.writeEmptyEncaps(_encoding);
+ }
+ else
+ {
+ os_.writeEncaps(encaps);
+ }
+ }
+
+ public IceInternal.BasicStream startReadParams()
+ {
+ _is.startReadEncaps();
+ return _is;
+ }
+
+ public void endReadParams()
+ {
+ _is.endReadEncaps();
+ }
+
+ public void readEmptyParams()
+ {
+ _is.skipEmptyEncaps();
+ }
+
+ public byte[] readParamEncaps()
+ {
+ Ice.EncodingVersion encoding;
+ return _is.readEncaps(out encoding);
+ }
+
+ override public BasicStream getIs()
+ {
+ // _is can already be initialized if the invocation is retried
+ if(_is == null)
+ {
+ _is = new IceInternal.BasicStream(instance_, Ice.Util.currentProtocolEncoding);
+ }
+ return _is;
+ }
+
+ public void throwUserException()
+ {
+ try
+ {
+ _is.startReadEncaps();
+ _is.throwException(null);
+ }
+ catch(Ice.UserException ex)
+ {
+ _is.endReadEncaps();
+ throw ex;
+ }
+ }
+
+ public override void cacheMessageBuffers()
+ {
+ if(proxy_.reference__().getInstance().cacheMessageBuffers() > 0)
+ {
+ lock(this)
+ {
+ if((state_ & StateCachedBuffers) > 0)
+ {
+ return;
+ }
+ state_ |= StateCachedBuffers;
+ }
+
+ if(_is != null)
+ {
+ _is.reset();
+ }
+ os_.reset();
+
+ proxy_.cacheMessageBuffers(_is, os_);
+
+ _is = null;
+ os_ = null;
+ }
+ }
+
+ private Ice.EncodingVersion _encoding;
+ private BasicStream _is;
+
+ //
+ // If true this AMI request is being used for a generated synchronous invocation.
+ //
+ private bool _synchronous;
+
+ private static Dictionary<string, string> _emptyContext = new Dictionary<string, string>();
+ }
+
+ public class CommunicatorFlushBatch : IceInternal.AsyncResultI
+ {
+ public static CommunicatorFlushBatch check(Ice.AsyncResult r, Ice.Communicator com, string operation)
+ {
+ if(r != null && r.getCommunicator() != com)
+ {
+ throw new System.ArgumentException("Communicator for call to end_" + operation +
+ " does not match communicator that was used to call " +
+ "corresponding begin_" + operation + " method");
+ }
+ return AsyncResultI.check<CommunicatorFlushBatch>(r, operation);
+ }
+
+ public CommunicatorFlushBatch(Ice.Communicator communicator, Instance instance, string op, object cookie) :
+ base(communicator, instance, op, cookie)
+ {
+
+ observer_ = ObserverHelper.get(instance, op);
+
+ //
+ // _useCount is initialized to 1 to prevent premature callbacks.
+ // The caller must invoke ready() after all flush requests have
+ // been initiated.
+ //
+ _useCount = 1;
+ }
+
+ public void flushConnection(Ice.ConnectionI con)
+ {
+ lock(this)
+ {
+ ++_useCount;
+ }
+
+ try
+ {
+ Ice.AsyncCallback sentCB = null;
+ FlushBatch flush = new FlushBatch(this);
+ int batchRequestNum = con.getBatchRequestQueue().swap(flush.getOs());
+ if(batchRequestNum == 0)
+ {
+ flush.sent();
+ }
+ else
+ {
+ con.sendAsyncRequest(flush, false, false, batchRequestNum, out sentCB);
+ }
+ Debug.Assert(sentCB == null);
+ }
+ catch(Ice.LocalException ex)
+ {
+ doCheck(false);
+ throw ex;
+ }
+ }
+
+ public void ready()
+ {
+ doCheck(true);
+ }
+
+ private void doCheck(bool userThread)
+ {
+ lock(this)
+ {
+ Debug.Assert(_useCount > 0);
+ if(--_useCount > 0)
+ {
+ return;
+ }
+ }
+
+ Ice.AsyncCallback sentCB = sent(true);
+ if(userThread)
+ {
+ sentSynchronously_ = true;
+ if(sentCB != null)
+ {
+ invokeSent(sentCB);
+ }
+ }
+ else
+ {
+ if(sentCB != null)
+ {
+ invokeSentAsync(sentCB);
+ }
+ }
+ }
+
+ class FlushBatch : OutgoingAsyncBase
+ {
+ public FlushBatch(CommunicatorFlushBatch outAsync) :
+ base(outAsync.getCommunicator(), outAsync.instance_, outAsync.getOperation(), null)
+ {
+ _outAsync = outAsync;
+ }
+
+ public override Ice.AsyncCallback sent()
+ {
+ if(childObserver_ != null)
+ {
+ childObserver_.detach();
+ childObserver_ = null;
+ }
+ _outAsync.doCheck(false);
+ return null;
+ }
+
+ public override Ice.AsyncCallback completed(Ice.Exception ex)
+ {
+ if(childObserver_ != null)
+ {
+ childObserver_.failed(ex.ice_name());
+ childObserver_.detach();
+ childObserver_ = null;
+ }
+ _outAsync.doCheck(false);
+ return null;
+ }
+
+ protected override Ice.Instrumentation.InvocationObserver getObserver()
+ {
+ return _outAsync.getObserver();
+ }
+
+ private CommunicatorFlushBatch _outAsync;
+ };
+ private int _useCount;
+ }
+
+
+ public class ConnectionFlushBatch : OutgoingAsyncBase
+ {
+ public static ConnectionFlushBatch check(Ice.AsyncResult r, Ice.Connection con, string operation)
+ {
+ if(r != null && r.getConnection() != con)
+ {
+ throw new System.ArgumentException("Connection for call to end_" + operation +
+ " does not match connection that was used to call " +
+ "corresponding begin_" + operation + " method");
+ }
+ return AsyncResultI.check<ConnectionFlushBatch>(r, operation);
+ }
+
+ public ConnectionFlushBatch(Ice.ConnectionI con, Ice.Communicator communicator, Instance instance, string op,
+ object cookie) :
+ base(communicator, instance, op, cookie)
+ {
+ _connection = con;
+ }
+
+ public override Ice.Connection getConnection()
+ {
+ return _connection;
+ }
+
+ public void invoke()
+ {
+ try
+ {
+ int batchRequestNum = _connection.getBatchRequestQueue().swap(os_);
+
+ bool isSent = false;
+ Ice.AsyncCallback sentCB;
+ if(batchRequestNum == 0)
+ {
+ isSent = true;
+ sentCB = sent();
+ }
+ else
+ {
+ isSent = _connection.sendAsyncRequest(this, false, false, batchRequestNum, out sentCB);
+ }
+
+ if(isSent)
+ {
+ sentSynchronously_ = true;
+ if(sentCB != null)
+ {
+ invokeSent(sentCB);
+ }
+ }
+ }
+ catch(RetryException ex)
+ {
+ Ice.AsyncCallback cb = completed(ex.get());
+ if(cb != null)
+ {
+ invokeCompletedAsync(cb);
+ }
+ }
+ catch(Ice.Exception ex)
+ {
+ Ice.AsyncCallback cb = completed(ex);
+ if(cb != null)
+ {
+ invokeCompletedAsync(cb);
+ }
+ }
+ }
+
+ private Ice.ConnectionI _connection;
+ }
+
+ public class ProxyFlushBatch : ProxyOutgoingAsyncBase
+ {
+ public new static ProxyFlushBatch check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation)
+ {
+ return ProxyOutgoingAsyncBase.check<ProxyFlushBatch>(r, prx, operation);
+ }
+
+ public ProxyFlushBatch(Ice.ObjectPrxHelperBase prx, string operation, object cookie) :
+ base(prx, operation, cookie)
+ {
+ observer_ = ObserverHelper.get(prx, operation);
+ _batchRequestNum = prx.getBatchRequestQueue__().swap(os_);
+ }
+
+ public override bool invokeRemote(Ice.ConnectionI con, bool compress, bool resp, out Ice.AsyncCallback sentCB)
+ {
+ if(_batchRequestNum == 0)
+ {
+ sentCB = sent();
+ return true;
+ }
+ cachedConnection_ = con;
+ return con.sendAsyncRequest(this, compress, false, _batchRequestNum, out sentCB);
+ }
+
+ public override bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCB)
+ {
+ if(_batchRequestNum == 0)
+ {
+ sentCB = sent();
+ return true;
+ }
+ return handler.invokeAsyncRequest(this, _batchRequestNum, false, out sentCB);
+ }
+
+ public void invoke()
+ {
+ Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(proxy_.reference__().getProtocol()));
+ invokeImpl(true); // userThread = true
+ }
+
+ private int _batchRequestNum;
+ }
+
+ public class ProxyGetConnection : ProxyOutgoingAsyncBase, Ice.AsyncResult<Ice.Callback_Object_ice_getConnection>
+ {
+ public new static ProxyGetConnection check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation)
+ {
+ return ProxyOutgoingAsyncBase.check<ProxyGetConnection>(r, prx, operation);
+ }
+
+ public ProxyGetConnection(Ice.ObjectPrxHelperBase prx, string operation,
+ ProxyTwowayCallback<Ice.Callback_Object_ice_getConnection> cb, object cookie) :
+ base(prx, operation, cookie)
+ {
+ observer_ = ObserverHelper.get(prx, operation);
+ _completed = cb;
+ }
+
+ public override bool invokeRemote(Ice.ConnectionI con, bool compress, bool resp, out Ice.AsyncCallback sentCB)
+ {
+ sentCB = null;
+ cachedConnection_ = con;
+ Ice.AsyncCallback cb = finished(true);
+ if(cb != null)
+ {
+ invokeCompletedAsync(cb);
+ }
+ return true;
+ }
+
+ public override bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCB)
+ {
+ sentCB = null;
+ Ice.AsyncCallback cb = finished(true);
+ if(cb != null)
+ {
+ invokeCompletedAsync(cb);
+ }
+ return true;
+ }
+
+ public void invoke()
+ {
+ invokeImpl(true); // userThread = true
+ }
+
+ new public Ice.AsyncResult<Ice.Callback_Object_ice_getConnection> whenCompleted(Ice.ExceptionCallback excb)
+ {
+ base.whenCompleted(excb);
+ return this;
+ }
+
+ virtual public Ice.AsyncResult<Ice.Callback_Object_ice_getConnection>
+ whenCompleted(Ice.Callback_Object_ice_getConnection cb, Ice.ExceptionCallback excb)
+ {
+ if(cb == null && excb == null)
+ {
+ throw new System.ArgumentException("callback is null");
+ }
+ lock(this)
+ {
+ if(_responseCallback != null || exceptionCallback_ != null)
+ {
+ throw new System.ArgumentException("callback already set");
+ }
+ _responseCallback = cb;
+ exceptionCallback_ = excb;
+ }
+ setCompletedCallback(getCompletedCallback());
+ return this;
+ }
+
+ new public Ice.AsyncResult<Ice.Callback_Object_ice_getConnection> whenSent(Ice.SentCallback cb)
+ {
+ base.whenSent(cb);
+ return this;
+ }
+
+ protected override Ice.AsyncCallback getCompletedCallback()
+ {
+ return (Ice.AsyncResult result) => { _completed(this, _responseCallback, exceptionCallback_); };
+ }
+
+ private ProxyTwowayCallback<Ice.Callback_Object_ice_getConnection> _completed;
+ private Ice.Callback_Object_ice_getConnection _responseCallback = null;
+ }
+
+ public abstract class OutgoingAsync<T> : OutgoingAsync, Ice.AsyncResult<T>
+ {
+ public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie) :
+ base(prx, operation, cookie)
+ {
+ }
+
+ public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie, BasicStream iss,
+ BasicStream os) :
+ base(prx, operation, cookie, iss, os)
+ {
+ }
+
+ new public Ice.AsyncResult<T> whenCompleted(Ice.ExceptionCallback excb)
+ {
+ base.whenCompleted(excb);
+ return this;
+ }
+
+ virtual public Ice.AsyncResult<T> whenCompleted(T cb, Ice.ExceptionCallback excb)
+ {
+ if(cb == null && excb == null)
+ {
+ throw new System.ArgumentException("callback is null");
+ }
+ lock(this)
+ {
+ if(responseCallback_ != null || exceptionCallback_ != null)
+ {
+ throw new System.ArgumentException("callback already set");
+ }
+ responseCallback_ = cb;
+ exceptionCallback_ = excb;
+ }
+ setCompletedCallback(getCompletedCallback());
+ return this;
+ }
+
+ new public Ice.AsyncResult<T> whenSent(Ice.SentCallback cb)
+ {
+ base.whenSent(cb);
+ return this;
+ }
+
+ protected T responseCallback_;
+ }
+
+ public class TwowayOutgoingAsync<T> : OutgoingAsync<T>
+ {
+ public TwowayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyTwowayCallback<T> cb,
+ object cookie) :
+ base(prx, operation, cookie)
+ {
+ Debug.Assert(cb != null);
+ _completed = cb;
+ }
+
+ public TwowayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyTwowayCallback<T> cb,
+ object cookie, BasicStream iss, BasicStream os) :
+ base(prx, operation, cookie, iss, os)
+ {
+ Debug.Assert(cb != null);
+ _completed = cb;
+ }
+
+ override protected Ice.AsyncCallback getCompletedCallback()
+ {
+ return (Ice.AsyncResult result) => { _completed(this, responseCallback_, exceptionCallback_); };
+ }
+
+ private ProxyTwowayCallback<T> _completed;
+ }
+
+ public class OnewayOutgoingAsync<T> : OutgoingAsync<T>
+ {
+ public OnewayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyOnewayCallback<T> cb,
+ object cookie) :
+ base(prx, operation, cookie)
+ {
+ Debug.Assert(cb != null);
+ _completed = cb;
+ }
+
+ public OnewayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyOnewayCallback<T> cb,
+ object cookie, BasicStream iss, BasicStream os) :
+ base(prx, operation, cookie, iss, os)
+ {
+ Debug.Assert(cb != null);
+ _completed = cb;
+ }
+
+ override protected Ice.AsyncCallback getCompletedCallback()
+ {
+ return (Ice.AsyncResult result) =>
+ {
+ try
+ {
+ IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)result;
+ ((Ice.ObjectPrxHelperBase)(outAsync__.getProxy())).end__(outAsync__, outAsync__.getOperation());
+ }
+ catch(Ice.Exception ex__)
+ {
+ if(exceptionCallback_ != null)
+ {
+ exceptionCallback_(ex__);
+ }
+ return;
+ }
+ _completed(responseCallback_);
+ };
+ }
+
+ private ProxyOnewayCallback<T> _completed;
+ }
+}
diff --git a/csharp/src/Ice/OutputBase.cs b/csharp/src/Ice/OutputBase.cs
new file mode 100644
index 00000000000..a7b74985cd4
--- /dev/null
+++ b/csharp/src/Ice/OutputBase.cs
@@ -0,0 +1,193 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceUtilInternal
+{
+
+using System.Collections.Generic;
+using System.IO;
+using System.Diagnostics;
+
+public class OutputBase
+{
+ public
+ OutputBase()
+ {
+ out_ = null;
+ pos_ = 0;
+ indent_ = 0;
+ indentSize_ = 4;
+ useTab_ = true;
+ indentSave_ = new Stack<int>();
+ separator_ = true;
+ }
+
+ public
+ OutputBase(TextWriter writer)
+ {
+ out_ = writer;
+ pos_ = 0;
+ indent_ = 0;
+ indentSize_ = 4;
+ useTab_ = true;
+ indentSave_ = new Stack<int>();
+ separator_ = true;
+ }
+
+ public
+ OutputBase(string s)
+ {
+ out_ = new StreamWriter(s);
+ pos_ = 0;
+ indent_ = 0;
+ indentSize_ = 4;
+ useTab_ = true;
+ indentSave_ = new Stack<int>();
+ separator_ = true;
+ }
+
+ virtual public void
+ setIndent(int indentSize)
+ {
+ indentSize_ = indentSize;
+ }
+
+ virtual public void
+ setUseTab(bool useTab)
+ {
+ useTab_ = useTab;
+ }
+
+ public virtual void
+ open(string s)
+ {
+ try
+ {
+ out_ = new StreamWriter(s);
+ }
+ catch(IOException)
+ {
+ }
+ }
+
+ public virtual void
+ print(string s)
+ {
+ char[] arr = s.ToCharArray();
+ for(int i = 0; i < arr.Length; i++)
+ {
+ if(arr[i] == '\n')
+ {
+ pos_ = 0;
+ }
+ else
+ {
+ }
+ }
+
+ out_.Write(s);
+ }
+
+ public virtual void
+ inc()
+ {
+ indent_ += indentSize_;
+ }
+
+ public virtual void
+ dec()
+ {
+ Debug.Assert(indent_ >= indentSize_);
+ indent_ -= indentSize_;
+ }
+
+ public virtual void
+ useCurrentPosAsIndent()
+ {
+ indentSave_.Push(indent_);
+ indent_ = pos_;
+ }
+
+ public virtual void
+ zeroIndent()
+ {
+ indentSave_.Push(indent_);
+ indent_ = 0;
+ }
+
+ public virtual void
+ restoreIndent()
+ {
+ Debug.Assert(indentSave_.Count != 0);
+ indent_ = (int)indentSave_.Pop();
+ }
+
+ public virtual void
+ nl()
+ {
+ out_.WriteLine();
+ pos_ = 0;
+ separator_ = true;
+
+ int indent = indent_;
+
+ if(useTab_)
+ {
+ while(indent >= 8)
+ {
+ indent -= 8;
+ out_.Write('\t');
+ pos_ += 8;
+ }
+ }
+ else
+ {
+ while(indent >= indentSize_)
+ {
+ indent -= indentSize_;
+ out_.Write(" ");
+ pos_ += indentSize_;
+ }
+ }
+
+ while(indent > 0)
+ {
+ --indent;
+ out_.Write(" ");
+ ++pos_;
+ }
+
+ out_.Flush();
+ }
+
+ public virtual void
+ sp()
+ {
+ if(separator_)
+ {
+ out_.WriteLine();
+ }
+ }
+
+ public virtual bool
+ valid()
+ {
+ return out_ != null;
+ }
+
+ protected internal TextWriter out_;
+ protected internal int pos_;
+ protected internal int indent_;
+ protected internal int indentSize_;
+ protected internal Stack<int> indentSave_;
+ protected internal bool useTab_;
+ protected internal bool separator_;
+}
+
+}
diff --git a/csharp/src/Ice/Patcher.cs b/csharp/src/Ice/Patcher.cs
new file mode 100644
index 00000000000..ae53b6a4692
--- /dev/null
+++ b/csharp/src/Ice/Patcher.cs
@@ -0,0 +1,302 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace IceInternal
+{
+ public interface IPatcher
+ {
+ void patch(Ice.Object v);
+ string type();
+ }
+
+ public abstract class Patcher : IPatcher, Ice.ReadObjectCallback
+ {
+ public Patcher(string type)
+ {
+ _type = type;
+ }
+
+ public abstract void patch(Ice.Object v);
+
+ public virtual string type()
+ {
+ return _type;
+ }
+
+ public virtual void invoke(Ice.Object v)
+ {
+ patch(v);
+ }
+
+ private string _type;
+ }
+
+ public sealed class ParamPatcher<T> : Patcher
+ {
+ public ParamPatcher(string type) : base(type)
+ {
+ }
+
+ public override void patch(Ice.Object v)
+ {
+ if(v != null && !typeof(T).IsAssignableFrom(v.GetType()))
+ {
+ IceInternal.Ex.throwUOE(type(), v.ice_id());
+ }
+ value = (T)v;
+ }
+
+ public T value;
+ }
+
+ public sealed class CustomSeqPatcher<T> : Patcher
+ {
+ public CustomSeqPatcher(string type, IEnumerable<T> seq, int index) : base(type)
+ {
+ _seq = seq;
+ _seqType = seq.GetType();
+ _index = index;
+
+ setInvokeInfo(_seqType);
+ }
+
+ public override void patch(Ice.Object v)
+ {
+ if(v != null && !typeof(T).IsAssignableFrom(v.GetType()))
+ {
+ IceInternal.Ex.throwUOE(type(), v.ice_id());
+ }
+
+ InvokeInfo info = getInvokeInfo(_seqType);
+ int count = info.getCount(_seq);
+ if(_index >= count) // Need to grow the sequence.
+ {
+ for(int i = count; i < _index; i++)
+ {
+ info.invokeAdd(_seq, default(T));
+ }
+ info.invokeAdd(_seq, (T)v);
+ }
+ else
+ {
+ info.invokeSet(_seq, _index, (T)v);
+ }
+ }
+
+ private static InvokeInfo getInvokeInfo(Type t)
+ {
+ lock(_methodTable)
+ {
+ try
+ {
+ return _methodTable[t];
+ }
+ catch(KeyNotFoundException)
+ {
+ throw new Ice.MarshalException("No invoke record for type " + t.ToString());
+ }
+ }
+ }
+
+ private static void setInvokeInfo(Type t)
+ {
+ lock(_methodTable)
+ {
+ if(_methodTable.ContainsKey(t))
+ {
+ return;
+ }
+
+ MethodInfo am = t.GetMethod("Add", _params);
+ if(am == null)
+ {
+ throw new Ice.MarshalException("Cannot patch a collection without an Add() method");
+ }
+
+ PropertyInfo pi = t.GetProperty("Item");
+ if(pi == null)
+ {
+ throw new Ice.MarshalException("Cannot patch a collection without an indexer");
+ }
+ MethodInfo sm = pi.GetSetMethod();
+ if(sm == null)
+ {
+ throw new Ice.MarshalException("Cannot patch a collection without an indexer to set a value");
+ }
+
+ pi = t.GetProperty("Count");
+ if(pi == null)
+ {
+ throw new Ice.MarshalException("Cannot patch a collection without a Count property");
+ }
+ MethodInfo cm = pi.GetGetMethod();
+ if(cm == null)
+ {
+ throw new Ice.MarshalException("Cannot patch a collection without a readable Count property");
+ }
+
+ _methodTable.Add(t, new InvokeInfo(am, sm, cm));
+ }
+ }
+
+ private class InvokeInfo
+ {
+ public InvokeInfo(MethodInfo am, MethodInfo sm, MethodInfo cm)
+ {
+ _addMethod = am;
+ _setMethod = sm;
+ _countMethod = cm;
+ }
+
+ internal int getCount(System.Collections.IEnumerable seq)
+ {
+ try
+ {
+ return (int)_countMethod.Invoke(seq, null);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.MarshalException("Could not read Count property during patching", ex);
+ }
+ }
+
+ internal void invokeAdd(System.Collections.IEnumerable seq, T v)
+ {
+ try
+ {
+ object[] arg = new object[] { v };
+ _addMethod.Invoke(seq, arg);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.MarshalException("Could not invoke Add method during patching", ex);
+ }
+ }
+
+ internal void invokeSet(System.Collections.IEnumerable seq, int index, T v)
+ {
+ try
+ {
+ object[] args = new object[] { index, v };
+ _setMethod.Invoke(seq, args);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.MarshalException("Could not call indexer during patching", ex);
+ }
+ }
+
+ private MethodInfo _addMethod;
+ private MethodInfo _setMethod;
+ private MethodInfo _countMethod;
+ }
+
+ private static Type[] _params = new Type[] { typeof(T) };
+ private static Dictionary<Type, InvokeInfo> _methodTable = new Dictionary<Type, InvokeInfo>();
+
+ private IEnumerable<T> _seq;
+ private Type _seqType;
+ private int _index; // The index at which to patch the sequence.
+ }
+
+ public sealed class ArrayPatcher<T> : Patcher
+ {
+ public ArrayPatcher(string type, T[] seq, int index) : base(type)
+ {
+ _seq = seq;
+ _index = index;
+ }
+
+ public override void patch(Ice.Object v)
+ {
+ if(v != null && !typeof(T).IsAssignableFrom(v.GetType()))
+ {
+ IceInternal.Ex.throwUOE(type(), v.ice_id());
+ }
+
+ _seq[_index] = (T)v;
+ }
+
+ private T[] _seq;
+ private int _index; // The index at which to patch the array.
+ }
+
+ public sealed class SequencePatcher<T> : Patcher
+ {
+ public SequencePatcher(string type, IceInternal.CollectionBase<T> seq, int index) : base(type)
+ {
+ _seq = seq;
+ _index = index;
+ }
+
+ public override void patch(Ice.Object v)
+ {
+ if(v != null && !typeof(T).IsAssignableFrom(v.GetType()))
+ {
+ IceInternal.Ex.throwUOE(type(), v.ice_id());
+ }
+
+ int count = _seq.Count;
+ if(_index >= count) // Need to grow the sequence.
+ {
+ for(int i = count; i < _index; i++)
+ {
+ _seq.Add(default(T));
+ }
+ _seq.Add((T)v);
+ }
+ else
+ {
+ _seq[_index] = (T)v;
+ }
+ }
+
+ private IceInternal.CollectionBase<T> _seq;
+ private int _index; // The index at which to patch the sequence.
+ }
+
+ public sealed class ListPatcher<T> : Patcher
+ {
+ public ListPatcher(string type, List<T> seq, int index) : base(type)
+ {
+ _seq = seq;
+ _index = index;
+ }
+
+ public override void patch(Ice.Object v)
+ {
+ if(v != null && !typeof(T).IsAssignableFrom(v.GetType()))
+ {
+ IceInternal.Ex.throwUOE(type(), v.ice_id());
+ }
+
+ int count = _seq.Count;
+ if(_index >= count) // Need to grow the sequence.
+ {
+ for(int i = count; i < _index; i++)
+ {
+ _seq.Add(default(T));
+ }
+ _seq.Add((T)v);
+ }
+ else
+ {
+ _seq[_index] = (T)v;
+ }
+ }
+
+ private List<T> _seq;
+ private int _index; // The index at which to patch the sequence.
+ }
+}
diff --git a/csharp/src/Ice/PluginManagerI.cs b/csharp/src/Ice/PluginManagerI.cs
new file mode 100644
index 00000000000..3069c1e1488
--- /dev/null
+++ b/csharp/src/Ice/PluginManagerI.cs
@@ -0,0 +1,530 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#if !SILVERLIGHT
+namespace Ice
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+
+ /// <summary>
+ /// Applications implement this interface to provide a plug-in factory
+ /// to the Ice run time.
+ /// </summary>
+ public interface PluginFactory
+ {
+ /// <summary>
+ /// Called by the Ice run time to create a new plug-in.
+ /// </summary>
+ ///
+ /// <param name="communicator">The communicator that is in the process of being initialized.</param>
+ /// <param name="name">The name of the plug-in.</param>
+ /// <param name="args">The arguments that are specified in the plug-ins configuration.</param>
+ /// <returns>The plug-in that was created by this method.</returns>
+ Plugin create(Communicator communicator, string name, string[] args);
+ }
+
+ public sealed class PluginManagerI : PluginManager
+ {
+ private static string _kindOfObject = "plugin";
+
+ public void initializePlugins()
+ {
+ if(_initialized)
+ {
+ InitializationException ex = new InitializationException();
+ ex.reason = "plug-ins already initialized";
+ throw ex;
+ }
+
+ //
+ // Invoke initialize() on the plug-ins, in the order they were loaded.
+ //
+ ArrayList initializedPlugins = new ArrayList();
+ try
+ {
+ foreach(PluginInfo p in _plugins)
+ {
+ p.plugin.initialize();
+ initializedPlugins.Add(p.plugin);
+ }
+ }
+ catch(System.Exception)
+ {
+ //
+ // Destroy the plug-ins that have been successfully initialized, in the
+ // reverse order.
+ //
+ initializedPlugins.Reverse();
+ foreach(Plugin p in initializedPlugins)
+ {
+ try
+ {
+ p.destroy();
+ }
+ catch(System.Exception)
+ {
+ // Ignore.
+ }
+ }
+ throw;
+ }
+
+ _initialized = true;
+ }
+
+ public string[] getPlugins()
+ {
+ lock(this)
+ {
+ ArrayList names = new ArrayList();
+ foreach(PluginInfo p in _plugins)
+ {
+ names.Add(p.name);
+ }
+ return (string[])names.ToArray(typeof(string));
+ }
+ }
+
+ public Plugin getPlugin(string name)
+ {
+ lock(this)
+ {
+ if(_communicator == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+
+ Plugin p = findPlugin(name);
+ if(p != null)
+ {
+ return p;
+ }
+
+ NotRegisteredException ex = new NotRegisteredException();
+ ex.id = name;
+ ex.kindOfObject = _kindOfObject;
+ throw ex;
+ }
+ }
+
+ public void addPlugin(string name, Plugin plugin)
+ {
+ lock(this)
+ {
+ if(_communicator == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+
+ if(findPlugin(name) != null)
+ {
+ AlreadyRegisteredException ex = new AlreadyRegisteredException();
+ ex.id = name;
+ ex.kindOfObject = _kindOfObject;
+ throw ex;
+ }
+
+ PluginInfo info = new PluginInfo();
+ info.name = name;
+ info.plugin = plugin;
+ _plugins.Add(info);
+ }
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ if(_communicator != null)
+ {
+ if(_initialized)
+ {
+ ArrayList plugins = (ArrayList)_plugins.Clone();
+ plugins.Reverse();
+ foreach(PluginInfo p in plugins)
+ {
+ try
+ {
+ p.plugin.destroy();
+ }
+ catch(System.Exception ex)
+ {
+ Ice.Util.getProcessLogger().warning("unexpected exception raised by plug-in `" +
+ p.name + "' destruction:\n" + ex.ToString());
+ }
+ }
+ }
+
+ _communicator = null;
+ }
+ }
+ }
+
+ public PluginManagerI(Communicator communicator)
+ {
+ _communicator = communicator;
+ _plugins = new ArrayList();
+ _initialized = false;
+ }
+
+ public void loadPlugins(ref string[] cmdArgs)
+ {
+ Debug.Assert(_communicator != null);
+
+ //
+ // Load and initialize the plug-ins defined in the property set
+ // with the prefix "Ice.Plugin.". These properties should
+ // have the following format:
+ //
+ // Ice.Plugin.name[.<language>]=entry_point [args]
+ //
+ // The code below is different from the Java/C++ algorithm
+ // because C# must support full assembly names such as:
+ //
+ // Ice.Plugin.Logger=logger, Version=0.0.0.0, Culture=neutral:LoginPluginFactory
+ //
+ // If the Ice.PluginLoadOrder property is defined, load the
+ // specified plug-ins in the specified order, then load any
+ // remaining plug-ins.
+ //
+ string prefix = "Ice.Plugin.";
+ Properties properties = _communicator.getProperties();
+ Dictionary<string, string> plugins = properties.getPropertiesForPrefix(prefix);
+
+ string[] loadOrder = properties.getPropertyAsList("Ice.PluginLoadOrder");
+ for(int i = 0; i < loadOrder.Length; ++i)
+ {
+ if(loadOrder[i].Length == 0)
+ {
+ continue;
+ }
+
+ if(findPlugin(loadOrder[i]) != null)
+ {
+ PluginInitializationException e = new PluginInitializationException();
+ e.reason = "plug-in `" + loadOrder[i] + "' already loaded";
+ throw e;
+ }
+
+ string key = "Ice.Plugin." + loadOrder[i] + ".clr";
+ bool hasKey = plugins.ContainsKey(key);
+ if(hasKey)
+ {
+ plugins.Remove("Ice.Plugin." + loadOrder[i]);
+ }
+ else
+ {
+ key = "Ice.Plugin." + loadOrder[i];
+ hasKey = plugins.ContainsKey(key);
+ }
+
+ if(hasKey)
+ {
+ string value = plugins[key];
+ loadPlugin(loadOrder[i], value, ref cmdArgs);
+ plugins.Remove(key);
+ }
+ else
+ {
+ PluginInitializationException e = new PluginInitializationException();
+ e.reason = "plug-in `" + loadOrder[i] + "' not defined";
+ throw e;
+ }
+ }
+
+ //
+ // Load any remaining plug-ins that weren't specified in PluginLoadOrder.
+ //
+ while(plugins.Count > 0)
+ {
+ IEnumerator<KeyValuePair<string, string>> p = plugins.GetEnumerator();
+ p.MoveNext();
+ string key = p.Current.Key;
+ string val = p.Current.Value;
+ string name = key.Substring(prefix.Length);
+
+ int dotPos = name.LastIndexOf('.');
+ if(dotPos != -1)
+ {
+ string suffix = name.Substring(dotPos + 1);
+ if(suffix.Equals("cpp") || suffix.Equals("java"))
+ {
+ //
+ // Ignored
+ //
+ plugins.Remove(key);
+ }
+ else if(suffix.Equals("clr"))
+ {
+ name = name.Substring(0, dotPos);
+ loadPlugin(name, val, ref cmdArgs);
+ plugins.Remove(key);
+ plugins.Remove("Ice.Plugin." + name);
+
+ }
+ else
+ {
+ //
+ // Name is just a regular name that happens to contain a dot
+ //
+ dotPos = -1;
+ }
+ }
+
+ if(dotPos == -1)
+ {
+ plugins.Remove(key);
+
+ //
+ // Is there a .clr entry?
+ //
+ string clrKey = "Ice.Plugin." + name + ".clr";
+ if(plugins.ContainsKey(clrKey))
+ {
+ val = plugins[clrKey];
+ plugins.Remove(clrKey);
+ }
+ loadPlugin(name, val, ref cmdArgs);
+ }
+ }
+ }
+
+ private void loadPlugin(string name, string pluginSpec, ref string[] cmdArgs)
+ {
+ Debug.Assert(_communicator != null);
+
+ //
+ // Split the entire property value into arguments. An entry point containing spaces
+ // must be enclosed in quotes.
+ //
+ string[] args = null;
+ try
+ {
+ args = IceUtilInternal.Options.split(pluginSpec);
+ }
+ catch(IceUtilInternal.Options.BadQuote ex)
+ {
+ PluginInitializationException e = new PluginInitializationException();
+ e.reason = "invalid arguments for plug-in `" + name + "':\n" + ex.Message;
+ throw e;
+ }
+
+ Debug.Assert(args.Length > 0);
+
+ string entryPoint = args[0];
+
+ //
+ // Shift the arguments.
+ //
+ string[] tmp = new string[args.Length - 1];
+ Array.Copy(args, 1, tmp, 0, args.Length - 1);
+ args = tmp;
+
+ //
+ // Convert command-line options into properties. First
+ // we convert the options from the plug-in
+ // configuration, then we convert the options from the
+ // application command-line.
+ //
+ Properties properties = _communicator.getProperties();
+ args = properties.parseCommandLineOptions(name, args);
+ cmdArgs = properties.parseCommandLineOptions(name, cmdArgs);
+
+ //
+ // Extract the assembly name and the class name.
+ //
+ string err = "unable to load plug-in `" + entryPoint + "': ";
+ int sepPos = entryPoint.IndexOf(':');
+ if(sepPos != -1 && IceInternal.AssemblyUtil.platform_ == IceInternal.AssemblyUtil.Platform.Windows)
+ {
+ const string driveLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if(entryPoint.Length > 3 &&
+ sepPos == 1 &&
+ driveLetters.IndexOf(entryPoint[0]) != -1 &&
+ (entryPoint[2] == '\\' || entryPoint[2] == '/'))
+ {
+ sepPos = entryPoint.IndexOf(':', 3);
+ }
+ }
+ if(sepPos == -1)
+ {
+ PluginInitializationException e = new PluginInitializationException();
+ e.reason = err + "invalid entry point format";
+ throw e;
+ }
+
+ System.Reflection.Assembly pluginAssembly = null;
+ string assemblyName = entryPoint.Substring(0, sepPos);
+ string className = entryPoint.Substring(sepPos + 1);
+
+ try
+ {
+ //
+ // First try to load the assembly using Assembly.Load, which will succeed
+ // if a fully-qualified name is provided or if a partial name has been qualified
+ // in configuration. If that fails, try Assembly.LoadFrom(), which will succeed
+ // if a file name is configured or a partial name is configured and DEVPATH is used.
+ //
+ try
+ {
+ pluginAssembly = System.Reflection.Assembly.Load(assemblyName);
+ }
+ catch(System.IO.IOException ex)
+ {
+ try
+ {
+ pluginAssembly = System.Reflection.Assembly.LoadFrom(assemblyName);
+ }
+ catch(System.IO.IOException)
+ {
+ throw ex;
+ }
+ }
+ }
+ catch(System.Exception ex)
+ {
+#if COMPACT
+ //
+ // IceSSL is not supported with the Compact Framework.
+ //
+ if(name == "IceSSL")
+ {
+ if(!_sslWarnOnce)
+ {
+ _communicator.getLogger().warning(
+ "IceSSL plug-in not loaded: IceSSL is not supported with the .NET Compact Framework");
+ _sslWarnOnce = true;
+ }
+ return;
+ }
+#else
+ //
+ // IceSSL is not yet supported with Mono. We avoid throwing an exception in that case,
+ // so the same configuration can be used with Mono or Visual C#.
+ //
+ if(IceInternal.AssemblyUtil.runtime_ == IceInternal.AssemblyUtil.Runtime.Mono && name == "IceSSL")
+ {
+ if(!_sslWarnOnce)
+ {
+ _communicator.getLogger().warning(
+ "IceSSL plug-in not loaded: IceSSL is not supported with Mono");
+ _sslWarnOnce = true;
+ }
+ return;
+ }
+#endif
+
+ PluginInitializationException e = new PluginInitializationException();
+ e.reason = err + "unable to load assembly: `" + assemblyName + "': " + ex.ToString();
+ throw e;
+ }
+
+ //
+ // Instantiate the class.
+ //
+ PluginFactory pluginFactory = null;
+ System.Type c = null;
+ try
+ {
+ c = pluginAssembly.GetType(className, true);
+ }
+ catch(System.Exception ex)
+ {
+ PluginInitializationException e = new PluginInitializationException(ex);
+ e.reason = err + "GetType failed for `" + className + "'";
+ throw e;
+ }
+
+ try
+ {
+ pluginFactory = (PluginFactory)IceInternal.AssemblyUtil.createInstance(c);
+ if(pluginFactory == null)
+ {
+ PluginInitializationException e = new PluginInitializationException();
+ e.reason = err + "can't find constructor for `" + className + "'";
+ throw e;
+ }
+ }
+ catch(System.InvalidCastException ex)
+ {
+ PluginInitializationException e = new PluginInitializationException(ex);
+ e.reason = err + "InvalidCastException to Ice.PluginFactory";
+ throw e;
+ }
+ catch(System.UnauthorizedAccessException ex)
+ {
+ PluginInitializationException e = new PluginInitializationException(ex);
+ e.reason = err + "UnauthorizedAccessException: " + ex.ToString();
+ throw e;
+ }
+ catch(System.Exception ex)
+ {
+ PluginInitializationException e = new PluginInitializationException(ex);
+ e.reason = err + "System.Exception: " + ex.ToString();
+ throw e;
+ }
+
+ Plugin plugin = null;
+ try
+ {
+ plugin = pluginFactory.create(_communicator, name, args);
+ }
+ catch(PluginInitializationException ex)
+ {
+ ex.reason = err + ex.reason;
+ throw ex;
+ }
+ catch(System.Exception ex)
+ {
+ PluginInitializationException e = new PluginInitializationException(ex);
+ e.reason = err + "System.Exception in factory.create: " + ex.ToString();
+ throw e;
+ }
+
+ if(plugin == null)
+ {
+ PluginInitializationException ex = new PluginInitializationException();
+ ex.reason = err + "factory.create returned null plug-in";
+ throw ex;
+ }
+
+ PluginInfo info = new PluginInfo();
+ info.name = name;
+ info.plugin = plugin;
+ _plugins.Add(info);
+ }
+
+ private Plugin findPlugin(string name)
+ {
+ foreach(PluginInfo p in _plugins)
+ {
+ if(name.Equals(p.name))
+ {
+ return p.plugin;
+ }
+ }
+ return null;
+ }
+
+ internal class PluginInfo
+ {
+ internal string name;
+ internal Plugin plugin;
+ }
+
+ private Communicator _communicator;
+ private ArrayList _plugins;
+ private bool _initialized;
+ private static bool _sslWarnOnce = false;
+ }
+}
+#endif
diff --git a/csharp/src/Ice/ProcessI.cs b/csharp/src/Ice/ProcessI.cs
new file mode 100644
index 00000000000..a4e2b9f6300
--- /dev/null
+++ b/csharp/src/Ice/ProcessI.cs
@@ -0,0 +1,43 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ public sealed class ProcessI : Ice.ProcessDisp_
+ {
+ public ProcessI(Ice.Communicator communicator)
+ {
+ _communicator = communicator;
+ }
+
+ public override void shutdown(Ice.Current current)
+ {
+ _communicator.shutdown();
+ }
+
+ public override void writeMessage(string message, int fd, Ice.Current current)
+ {
+ switch(fd)
+ {
+ case 1:
+ {
+ System.Console.Out.WriteLine(message);
+ break;
+ }
+ case 2:
+ {
+ System.Console.Error.WriteLine(message);
+ break;
+ }
+ }
+ }
+
+ private Ice.Communicator _communicator;
+ }
+}
diff --git a/csharp/src/Ice/PropertiesAdminI.cs b/csharp/src/Ice/PropertiesAdminI.cs
new file mode 100644
index 00000000000..7578cf1938f
--- /dev/null
+++ b/csharp/src/Ice/PropertiesAdminI.cs
@@ -0,0 +1,240 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections.Generic;
+
+namespace Ice
+{
+
+public interface PropertiesAdminUpdateCallback
+{
+ void updated(Dictionary<string, string> changes);
+}
+
+public interface NativePropertiesAdmin
+{
+ void addUpdateCallback(PropertiesAdminUpdateCallback callback);
+ void removeUpdateCallback(PropertiesAdminUpdateCallback callback);
+}
+
+}
+
+namespace IceInternal
+{
+ sealed class PropertiesAdminI : Ice.PropertiesAdminDisp_, Ice.NativePropertiesAdmin
+ {
+ internal PropertiesAdminI(Ice.Properties properties, Ice.Logger logger)
+ {
+ _properties = properties;
+ _logger = logger;
+ }
+
+ public override string
+ getProperty(string name, Ice.Current current)
+ {
+ return _properties.getProperty(name);
+ }
+
+ public override Dictionary<string, string>
+ getPropertiesForPrefix(string name, Ice.Current current)
+ {
+ return _properties.getPropertiesForPrefix(name);
+ }
+
+ public override void setProperties_async(Ice.AMD_PropertiesAdmin_setProperties cb,
+ Dictionary<string, string> props,
+ Ice.Current current)
+ {
+ lock(this)
+ {
+ Dictionary<string, string> old = _properties.getPropertiesForPrefix("");
+ int traceLevel = _properties.getPropertyAsInt("Ice.Trace.Admin.Properties");
+
+ //
+ // Compute the difference between the new property set and the existing property set:
+ //
+ // 1) Any properties in the new set that were not defined in the existing set.
+ //
+ // 2) Any properties that appear in both sets but with different values.
+ //
+ // 3) Any properties not present in the new set but present in the existing set.
+ // In other words, the property has been removed.
+ //
+ Dictionary<string, string> added = new Dictionary<string, string>();
+ Dictionary<string, string> changed = new Dictionary<string, string>();
+ Dictionary<string, string> removed = new Dictionary<string, string>();
+ foreach(KeyValuePair<string, string> e in props)
+ {
+ string key = e.Key;
+ string value = e.Value;
+ if(!old.ContainsKey(key))
+ {
+ if(value.Length > 0)
+ {
+ //
+ // This property is new.
+ //
+ added.Add(key, value);
+ }
+ }
+ else
+ {
+ string v;
+ if(!old.TryGetValue(key, out v) || !value.Equals(v))
+ {
+ if(value.Length == 0)
+ {
+ //
+ // This property was removed.
+ //
+ removed.Add(key, value);
+ }
+ else
+ {
+ //
+ // This property has changed.
+ //
+ changed.Add(key, value);
+ }
+ }
+
+ old.Remove(key);
+ }
+ }
+
+ if(traceLevel > 0 && (added.Count > 0 || changed.Count > 0 || removed.Count > 0))
+ {
+ System.Text.StringBuilder message = new System.Text.StringBuilder("Summary of property changes");
+
+ if(added.Count > 0)
+ {
+ message.Append("\nNew properties:");
+ foreach(KeyValuePair<string, string> e in added)
+ {
+ message.Append("\n ");
+ message.Append(e.Key);
+ if(traceLevel > 1)
+ {
+ message.Append(" = ");
+ message.Append(e.Value);
+ }
+ }
+ }
+
+ if(changed.Count > 0)
+ {
+ message.Append("\nChanged properties:");
+ foreach(KeyValuePair<string, string> e in changed)
+ {
+ message.Append("\n ");
+ message.Append(e.Key);
+ if(traceLevel > 1)
+ {
+ message.Append(" = ");
+ message.Append(e.Value);
+ message.Append(" (old value = ");
+ message.Append(_properties.getProperty(e.Key));
+ message.Append(")");
+ }
+ }
+ }
+
+ if(removed.Count > 0)
+ {
+ message.Append("\nRemoved properties:");
+ foreach(KeyValuePair<string, string> e in removed)
+ {
+ message.Append("\n ");
+ message.Append(e.Key);
+ }
+ }
+
+ _logger.trace(_traceCategory, message.ToString());
+ }
+
+ //
+ // Update the property set.
+ //
+
+ foreach(KeyValuePair<string, string> e in added)
+ {
+ _properties.setProperty(e.Key, e.Value);
+ }
+
+ foreach(KeyValuePair<string, string> e in changed)
+ {
+ _properties.setProperty(e.Key, e.Value);
+ }
+
+ foreach(KeyValuePair<string, string> e in removed)
+ {
+ _properties.setProperty(e.Key, "");
+ }
+
+ //
+ // Send the response now so that we do not block the client during the call to the update callback.
+ //
+ cb.ice_response();
+
+ if(_updateCallbacks.Count > 0)
+ {
+ //
+ // Copy the callbacks to allow callbacks to update the callbacks.
+ //
+ List<Ice.PropertiesAdminUpdateCallback> callbacks =
+ new List<Ice.PropertiesAdminUpdateCallback>(_updateCallbacks);
+
+ Dictionary<string, string> changes = new Dictionary<string, string>(added);
+ foreach(KeyValuePair<string, string> e in changed)
+ {
+ changes.Add(e.Key, e.Value);
+ }
+ foreach(KeyValuePair<string, string> e in removed)
+ {
+ changes.Add(e.Key, e.Value);
+ }
+
+ foreach(Ice.PropertiesAdminUpdateCallback callback in callbacks)
+ {
+ try
+ {
+ callback.updated(changes);
+ }
+ catch(System.Exception)
+ {
+ // Ignore.
+ }
+ }
+ }
+ }
+ }
+
+ public void addUpdateCallback(Ice.PropertiesAdminUpdateCallback cb)
+ {
+ lock(this)
+ {
+ _updateCallbacks.Add(cb);
+ }
+ }
+
+ public void removeUpdateCallback(Ice.PropertiesAdminUpdateCallback cb)
+ {
+ lock(this)
+ {
+ _updateCallbacks.Remove(cb);
+ }
+ }
+
+ private readonly Ice.Properties _properties;
+ private readonly Ice.Logger _logger;
+ private List<Ice.PropertiesAdminUpdateCallback> _updateCallbacks = new List<Ice.PropertiesAdminUpdateCallback>();
+
+ private static readonly string _traceCategory = "Admin.Properties";
+ }
+}
diff --git a/csharp/src/Ice/PropertiesI.cs b/csharp/src/Ice/PropertiesI.cs
new file mode 100644
index 00000000000..0ca06bddd9e
--- /dev/null
+++ b/csharp/src/Ice/PropertiesI.cs
@@ -0,0 +1,692 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using System.Globalization;
+using Microsoft.Win32;
+
+namespace Ice
+{
+ sealed class PropertiesI : Properties
+ {
+ class PropertyValue
+ {
+ public PropertyValue(PropertyValue v)
+ {
+ val = v.val;
+ used = v.used;
+ }
+
+ public PropertyValue(string v, bool u)
+ {
+ val = v;
+ used = u;
+ }
+
+ public string val;
+ public bool used;
+ }
+
+ public string getProperty(string key)
+ {
+ lock(this)
+ {
+ string result = "";
+ PropertyValue pv;
+ if(_properties.TryGetValue(key, out pv))
+ {
+ pv.used = true;
+ result = pv.val;
+ }
+ return result;
+ }
+ }
+
+ public string getPropertyWithDefault(string key, string val)
+ {
+ lock(this)
+ {
+ string result = val;
+ PropertyValue pv;
+ if(_properties.TryGetValue(key, out pv))
+ {
+ pv.used = true;
+ result = pv.val;
+ }
+ return result;
+ }
+ }
+
+ public int getPropertyAsInt(string key)
+ {
+ return getPropertyAsIntWithDefault(key, 0);
+ }
+
+ public int getPropertyAsIntWithDefault(string key, int val)
+ {
+ lock(this)
+ {
+ PropertyValue pv;
+ if(!_properties.TryGetValue(key, out pv))
+ {
+ return val;
+ }
+ pv.used = true;
+ try
+ {
+ return System.Int32.Parse(pv.val, CultureInfo.InvariantCulture);
+ }
+ catch(System.FormatException)
+ {
+ Ice.Util.getProcessLogger().warning("numeric property " + key +
+ " set to non-numeric value, defaulting to " + val);
+ return val;
+ }
+ }
+ }
+
+ public string[] getPropertyAsList(string key)
+ {
+ return getPropertyAsListWithDefault(key, null);
+ }
+
+ public string[] getPropertyAsListWithDefault(string key, string[] val)
+ {
+ if(val == null)
+ {
+ val = new string[0];
+ }
+
+ lock(this)
+ {
+ PropertyValue pv;
+ if(!_properties.TryGetValue(key, out pv))
+ {
+ return val;
+ }
+
+ pv.used = true;
+
+ string[] result = IceUtilInternal.StringUtil.splitString(pv.val, ", \t\r\n");
+ if(result == null)
+ {
+ Ice.Util.getProcessLogger().warning("mismatched quotes in property " + key
+ + "'s value, returning default value");
+ return val;
+ }
+ else
+ {
+ return result;
+ }
+ }
+ }
+
+
+ public Dictionary<string, string> getPropertiesForPrefix(string prefix)
+ {
+ lock(this)
+ {
+ Dictionary<string, string> result = new Dictionary<string, string>();
+
+ foreach(string s in _properties.Keys)
+ {
+ if(prefix.Length == 0 || s.StartsWith(prefix, StringComparison.Ordinal))
+ {
+ PropertyValue pv = (PropertyValue)_properties[s];
+ pv.used = true;
+ result[s] = pv.val;
+ }
+ }
+ return result;
+ }
+ }
+
+ public void setProperty(string key, string val)
+ {
+ //
+ // Trim whitespace
+ //
+ if(key != null)
+ {
+ key = key.Trim();
+ }
+ if(key == null || key.Length == 0)
+ {
+ throw new Ice.InitializationException("Attempt to set property with empty key");
+ }
+
+ //
+ // Check if the property is legal.
+ //
+ Logger logger = Ice.Util.getProcessLogger();
+ int dotPos = key.IndexOf('.');
+ if(dotPos != -1)
+ {
+ string prefix = key.Substring(0, dotPos);
+ for(int i = 0; IceInternal.PropertyNames.validProps[i] != null; ++i)
+ {
+ string pattern = IceInternal.PropertyNames.validProps[i][0].pattern();
+ dotPos = pattern.IndexOf('.');
+ Debug.Assert(dotPos != -1);
+ string propPrefix = pattern.Substring(1, dotPos - 2);
+ bool mismatchCase = false;
+ string otherKey = "";
+ if(!propPrefix.ToUpper().Equals(prefix.ToUpper()))
+ {
+ continue;
+ }
+
+ bool found = false;
+ for(int j = 0; IceInternal.PropertyNames.validProps[i][j] != null && !found; ++j)
+ {
+ Regex r = new Regex(IceInternal.PropertyNames.validProps[i][j].pattern());
+ Match m = r.Match(key);
+ found = m.Success;
+ if(found && IceInternal.PropertyNames.validProps[i][j].deprecated())
+ {
+ logger.warning("deprecated property: " + key);
+ if(IceInternal.PropertyNames.validProps[i][j].deprecatedBy() != null)
+ {
+ key = IceInternal.PropertyNames.validProps[i][j].deprecatedBy();
+ }
+ }
+
+ if(!found)
+ {
+ r = new Regex(IceInternal.PropertyNames.validProps[i][j].pattern().ToUpper());
+ m = r.Match(key.ToUpper());
+ if(m.Success)
+ {
+ found = true;
+ mismatchCase = true;
+ otherKey = IceInternal.PropertyNames.validProps[i][j].pattern().Replace("\\", "").
+ Replace("^", "").
+ Replace("$", "");
+ break;
+ }
+ }
+ }
+ if(!found)
+ {
+ logger.warning("unknown property: " + key);
+ }
+ else if(mismatchCase)
+ {
+ logger.warning("unknown property: `" + key + "'; did you mean `" + otherKey + "'");
+ }
+ }
+ }
+
+ lock(this)
+ {
+ //
+ //
+ // Set or clear the property.
+ //
+ if(val != null && val.Length > 0)
+ {
+ PropertyValue pv;
+ if(_properties.TryGetValue(key, out pv))
+ {
+ pv.val = val;
+ }
+ else
+ {
+ pv = new PropertyValue(val, false);
+ }
+ _properties[key] = pv;
+ }
+ else
+ {
+ _properties.Remove(key);
+ }
+ }
+ }
+
+ public string[] getCommandLineOptions()
+ {
+ lock(this)
+ {
+ string[] result = new string[_properties.Count];
+ int i = 0;
+ foreach(KeyValuePair<string, PropertyValue> entry in _properties)
+ {
+ result[i++] = "--" + entry.Key + "=" + entry.Value.val;
+ }
+ return result;
+ }
+ }
+
+ public string[] parseCommandLineOptions(string pfx, string[] options)
+ {
+ if(pfx.Length > 0 && pfx[pfx.Length - 1] != '.')
+ {
+ pfx += '.';
+ }
+ pfx = "--" + pfx;
+
+ List<string> result = new List<string>();
+ for(int i = 0; i < options.Length; i++)
+ {
+ string opt = options[i];
+ if(opt.StartsWith(pfx, StringComparison.Ordinal))
+ {
+ if(opt.IndexOf('=') == -1)
+ {
+ opt += "=1";
+ }
+
+ parseLine(opt.Substring(2));
+ }
+ else
+ {
+ result.Add(opt);
+ }
+ }
+ string[] arr = new string[result.Count];
+ if(arr.Length != 0)
+ {
+ result.CopyTo(arr);
+ }
+ return arr;
+ }
+
+ public string[] parseIceCommandLineOptions(string[] options)
+ {
+ string[] args = options;
+ for(int i = 0; IceInternal.PropertyNames.clPropNames[i] != null; ++i)
+ {
+ args = parseCommandLineOptions(IceInternal.PropertyNames.clPropNames[i], args);
+ }
+ return args;
+ }
+
+ public void load(string file)
+ {
+#if UNITY
+ throw new FeatureNotSupportedException("File I/O not supported in UNITY build");
+#else
+# if !SILVERLIGHT
+ if(IceInternal.AssemblyUtil.platform_ == IceInternal.AssemblyUtil.Platform.Windows &&
+ (file.StartsWith("HKLM\\", StringComparison.Ordinal)))
+ {
+ RegistryKey iceKey = Registry.LocalMachine.OpenSubKey(file.Substring(5));
+ if(iceKey == null)
+ {
+ Ice.InitializationException ex = new Ice.InitializationException();
+ ex.reason = "Could not open Windows registry key `" + file + "'";
+ throw ex;
+ }
+
+ foreach(string propKey in iceKey.GetValueNames())
+ {
+ RegistryValueKind kind = iceKey.GetValueKind(propKey);
+ if(kind == RegistryValueKind.String || kind == RegistryValueKind.ExpandString)
+ {
+ setProperty(propKey, iceKey.GetValue(propKey).ToString());
+ }
+ }
+ }
+ else
+ {
+# endif
+ try
+ {
+ using(System.IO.StreamReader sr = new System.IO.StreamReader(file))
+ {
+ parse(sr);
+ }
+ }
+ catch(System.IO.IOException ex)
+ {
+ Ice.FileException fe = new Ice.FileException(ex);
+ fe.path = file;
+ throw fe;
+ }
+# if !SILVERLIGHT
+ }
+# endif
+#endif
+ }
+
+ public Properties ice_clone_()
+ {
+ lock(this)
+ {
+ return new PropertiesI(this);
+ }
+ }
+
+ public List<string> getUnusedProperties()
+ {
+ lock(this)
+ {
+ List<string> unused = new List<string>();
+ foreach(KeyValuePair<string, PropertyValue> entry in _properties)
+ {
+ if(!entry.Value.used)
+ {
+ unused.Add(entry.Key);
+ }
+ }
+ return unused;
+ }
+ }
+
+ internal PropertiesI(PropertiesI p)
+ {
+ //
+ // NOTE: we can't just do a shallow copy of the map as the map values
+ // would otherwise be shared between the two PropertiesI object.
+ //
+ //_properties = new Dictionary<string, PropertyValue>(p._properties);
+ _properties = new Dictionary<string, PropertyValue>();
+ foreach(KeyValuePair<string, PropertyValue> entry in p._properties)
+ {
+ _properties[entry.Key] = new PropertyValue(entry.Value);
+ }
+ }
+
+ internal PropertiesI()
+ {
+ _properties = new Dictionary<string, PropertyValue>();
+ }
+
+ internal PropertiesI(ref string[] args, Properties defaults)
+ {
+ if(defaults == null)
+ {
+ _properties = new Dictionary<string, PropertyValue>();
+ }
+ else
+ {
+ //
+ // NOTE: we can't just do a shallow copy of the map as the map values
+ // would otherwise be shared between the two PropertiesI object.
+ //
+ //_properties = ((PropertiesI)defaults)._properties;
+ _properties = new Dictionary<string, PropertyValue>();
+ foreach(KeyValuePair<string, PropertyValue> entry in ((PropertiesI)defaults)._properties)
+ {
+ _properties[entry.Key] = new PropertyValue(entry.Value);
+ }
+ }
+
+ PropertyValue pv;
+ if(_properties.TryGetValue("Ice.ProgramName", out pv))
+ {
+ pv.used = true;
+ }
+ else
+ {
+ _properties["Ice.ProgramName"] = new PropertyValue(System.AppDomain.CurrentDomain.FriendlyName, true);
+ }
+
+ bool loadConfigFiles = false;
+
+ for(int i = 0; i < args.Length; i++)
+ {
+ if(args[i].StartsWith("--Ice.Config", StringComparison.Ordinal))
+ {
+ string line = args[i];
+ if(line.IndexOf('=') == -1)
+ {
+ line += "=1";
+ }
+ parseLine(line.Substring(2));
+ loadConfigFiles = true;
+
+ string[] arr = new string[args.Length - 1];
+ System.Array.Copy(args, 0, arr, 0, i);
+ if(i < args.Length - 1)
+ {
+ System.Array.Copy(args, i + 1, arr, i, args.Length - i - 1);
+ }
+ args = arr;
+ }
+ }
+
+ if(!loadConfigFiles)
+ {
+ //
+ // If Ice.Config is not set, load from ICE_CONFIG (if set)
+ //
+ loadConfigFiles = !_properties.ContainsKey("Ice.Config");
+ }
+
+ if(loadConfigFiles)
+ {
+ loadConfig();
+ }
+
+ args = parseIceCommandLineOptions(args);
+ }
+
+ private void parse(System.IO.StreamReader input)
+ {
+ try
+ {
+ string line;
+ while((line = input.ReadLine()) != null)
+ {
+ parseLine(line);
+ }
+ }
+ catch(System.IO.IOException ex)
+ {
+ SyscallException se = new SyscallException(ex);
+ throw se;
+ }
+ }
+
+ private const int ParseStateKey = 0;
+ private const int ParseStateValue = 1;
+
+ private void parseLine(string line)
+ {
+ string key = "";
+ string val = "";
+
+ int state = ParseStateKey;
+
+ string whitespace = "";
+ string escapedspace = "";
+ bool finished = false;
+ for(int i = 0; i < line.Length; ++i)
+ {
+ char c = line[i];
+ switch(state)
+ {
+ case ParseStateKey:
+ {
+ switch(c)
+ {
+ case '\\':
+ if(i < line.Length - 1)
+ {
+ c = line[++i];
+ switch(c)
+ {
+ case '\\':
+ case '#':
+ case '=':
+ key += whitespace;
+ whitespace= "";
+ key += c;
+ break;
+
+ case ' ':
+ if(key.Length != 0)
+ {
+ whitespace += c;
+ }
+ break;
+
+ default:
+ key += whitespace;
+ whitespace= "";
+ key += '\\';
+ key += c;
+ break;
+ }
+ }
+ else
+ {
+ key += whitespace;
+ key += c;
+ }
+ break;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ if(key.Length != 0)
+ {
+ whitespace += c;
+ }
+ break;
+
+ case '=':
+ whitespace= "";
+ state = ParseStateValue;
+ break;
+
+ case '#':
+ finished = true;
+ break;
+
+ default:
+ key += whitespace;
+ whitespace= "";
+ key += c;
+ break;
+ }
+ break;
+ }
+
+ case ParseStateValue:
+ {
+ switch(c)
+ {
+ case '\\':
+ if(i < line.Length - 1)
+ {
+ c = line[++i];
+ switch(c)
+ {
+ case '\\':
+ case '#':
+ case '=':
+ val += val.Length == 0 ? escapedspace : whitespace;
+ whitespace= "";
+ escapedspace= "";
+ val += c;
+ break;
+
+ case ' ':
+ whitespace += c;
+ escapedspace += c;
+ break;
+
+ default:
+ val += val.Length == 0 ? escapedspace : whitespace;
+ whitespace= "";
+ escapedspace= "";
+ val += '\\';
+ val += c;
+ break;
+ }
+ }
+ else
+ {
+ val += val.Length == 0 ? escapedspace : whitespace;
+ val += c;
+ }
+ break;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ if(val.Length != 0)
+ {
+ whitespace += c;
+ }
+ break;
+
+ case '#':
+ finished = true;
+ break;
+
+ default:
+ val += val.Length == 0 ? escapedspace : whitespace;
+ whitespace = "";
+ escapedspace = "";
+ val += c;
+ break;
+ }
+ break;
+ }
+ }
+ if(finished)
+ {
+ break;
+ }
+ }
+ val += escapedspace;
+
+ if((state == ParseStateKey && key.Length != 0) || (state == ParseStateValue && key.Length == 0))
+ {
+ Ice.Util.getProcessLogger().warning("invalid config file entry: \"" + line + "\"");
+ return;
+ }
+ else if(key.Length == 0)
+ {
+ return;
+ }
+
+ setProperty(key, val);
+ }
+
+ private void loadConfig()
+ {
+ string val = getProperty("Ice.Config");
+
+#if !COMPACT && !SILVERLIGHT
+ if(val.Length == 0 || val.Equals("1"))
+ {
+ string s = System.Environment.GetEnvironmentVariable("ICE_CONFIG");
+ if(s != null && s.Length != 0)
+ {
+ val = s;
+ }
+ }
+#endif
+
+ if(val.Length > 0)
+ {
+ char[] separator = { ',' };
+ string[] files = val.Split(separator);
+ for(int i = 0; i < files.Length; i++)
+ {
+ load(files[i].Trim());
+ }
+
+ _properties["Ice.Config"] = new PropertyValue(val, true);
+ }
+ }
+
+ private Dictionary<string, PropertyValue> _properties;
+ }
+}
diff --git a/csharp/src/Ice/Property.cs b/csharp/src/Ice/Property.cs
new file mode 100644
index 00000000000..0363bd2e446
--- /dev/null
+++ b/csharp/src/Ice/Property.cs
@@ -0,0 +1,43 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ public sealed class Property
+ {
+ public Property(string pattern, bool deprecated, string deprecatedBy)
+ {
+ _pattern = pattern;
+ _deprecated = deprecated;
+ _deprecatedBy = deprecatedBy;
+ }
+
+ public string
+ pattern()
+ {
+ return _pattern;
+ }
+
+ public bool
+ deprecated()
+ {
+ return _deprecated;
+ }
+
+ public string
+ deprecatedBy()
+ {
+ return _deprecatedBy;
+ }
+
+ private string _pattern;
+ private bool _deprecated;
+ private string _deprecatedBy;
+ }
+}
diff --git a/csharp/src/Ice/PropertyNames.cs b/csharp/src/Ice/PropertyNames.cs
new file mode 100644
index 00000000000..279d5cb0ff2
--- /dev/null
+++ b/csharp/src/Ice/PropertyNames.cs
@@ -0,0 +1,1249 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+// Generated by makeprops.py from file ../config/PropertyNames.xml, Tue Dec 9 12:08:30 2014
+
+// IMPORTANT: Do not edit this file -- any edits made here will be lost!
+
+namespace IceInternal
+{
+ public sealed class PropertyNames
+ {
+ public static Property[] IceProps =
+ {
+ new Property(@"^Ice\.ACM\.Client$", true, null),
+ new Property(@"^Ice\.ACM\.Server$", true, null),
+ new Property(@"^Ice\.ACM\.Timeout$", false, null),
+ new Property(@"^Ice\.ACM\.Heartbeat$", false, null),
+ new Property(@"^Ice\.ACM\.Close$", false, null),
+ new Property(@"^Ice\.ACM$", false, null),
+ new Property(@"^Ice\.ACM\.Client\.Timeout$", false, null),
+ new Property(@"^Ice\.ACM\.Client\.Heartbeat$", false, null),
+ new Property(@"^Ice\.ACM\.Client\.Close$", false, null),
+ new Property(@"^Ice\.ACM\.Client$", false, null),
+ new Property(@"^Ice\.ACM\.Server\.Timeout$", false, null),
+ new Property(@"^Ice\.ACM\.Server\.Heartbeat$", false, null),
+ new Property(@"^Ice\.ACM\.Server\.Close$", false, null),
+ new Property(@"^Ice\.ACM\.Server$", false, null),
+ new Property(@"^Ice\.Admin\.ACM\.Timeout$", false, null),
+ new Property(@"^Ice\.Admin\.ACM\.Heartbeat$", false, null),
+ new Property(@"^Ice\.Admin\.ACM\.Close$", false, null),
+ new Property(@"^Ice\.Admin\.ACM$", false, null),
+ new Property(@"^Ice\.Admin\.AdapterId$", false, null),
+ new Property(@"^Ice\.Admin\.Endpoints$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.PreferSecure$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.Locator$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.Router$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^Ice\.Admin\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^Ice\.Admin\.Locator$", false, null),
+ new Property(@"^Ice\.Admin\.PublishedEndpoints$", false, null),
+ new Property(@"^Ice\.Admin\.ReplicaGroupId$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.EndpointSelection$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.ConnectionCached$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.PreferSecure$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.Locator$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.Router$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^Ice\.Admin\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^Ice\.Admin\.Router$", false, null),
+ new Property(@"^Ice\.Admin\.ProxyOptions$", false, null),
+ new Property(@"^Ice\.Admin\.ThreadPool\.Size$", false, null),
+ new Property(@"^Ice\.Admin\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^Ice\.Admin\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^Ice\.Admin\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^Ice\.Admin\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^Ice\.Admin\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^Ice\.Admin\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^Ice\.Admin\.MessageSizeMax$", false, null),
+ new Property(@"^Ice\.Admin\.DelayCreation$", false, null),
+ new Property(@"^Ice\.Admin\.Enabled$", false, null),
+ new Property(@"^Ice\.Admin\.Facets$", false, null),
+ new Property(@"^Ice\.Admin\.InstanceName$", false, null),
+ new Property(@"^Ice\.Admin\.Logger\.KeepLogs$", false, null),
+ new Property(@"^Ice\.Admin\.Logger\.KeepTraces$", false, null),
+ new Property(@"^Ice\.Admin\.Logger\.Properties$", false, null),
+ new Property(@"^Ice\.Admin\.ServerId$", false, null),
+ new Property(@"^Ice\.BackgroundLocatorCacheUpdates$", false, null),
+ new Property(@"^Ice\.BatchAutoFlush$", true, null),
+ new Property(@"^Ice\.BatchAutoFlushSize$", false, null),
+ new Property(@"^Ice\.ChangeUser$", false, null),
+ new Property(@"^Ice\.ClientAccessPolicyProtocol$", false, null),
+ new Property(@"^Ice\.Compression\.Level$", false, null),
+ new Property(@"^Ice\.CollectObjects$", false, null),
+ new Property(@"^Ice\.Config$", false, null),
+ new Property(@"^Ice\.ConsoleListener$", false, null),
+ new Property(@"^Ice\.Default\.CollocationOptimized$", false, null),
+ new Property(@"^Ice\.Default\.EncodingVersion$", false, null),
+ new Property(@"^Ice\.Default\.EndpointSelection$", false, null),
+ new Property(@"^Ice\.Default\.Host$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.PreferSecure$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.Locator$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.Router$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^Ice\.Default\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^Ice\.Default\.Locator$", false, null),
+ new Property(@"^Ice\.Default\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Ice\.Default\.InvocationTimeout$", false, null),
+ new Property(@"^Ice\.Default\.Package$", false, null),
+ new Property(@"^Ice\.Default\.PreferSecure$", false, null),
+ new Property(@"^Ice\.Default\.Protocol$", false, null),
+ new Property(@"^Ice\.Default\.Router\.EndpointSelection$", false, null),
+ new Property(@"^Ice\.Default\.Router\.ConnectionCached$", false, null),
+ new Property(@"^Ice\.Default\.Router\.PreferSecure$", false, null),
+ new Property(@"^Ice\.Default\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Ice\.Default\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^Ice\.Default\.Router\.Locator$", false, null),
+ new Property(@"^Ice\.Default\.Router\.Router$", false, null),
+ new Property(@"^Ice\.Default\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^Ice\.Default\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^Ice\.Default\.Router$", false, null),
+ new Property(@"^Ice\.Default\.SlicedFormat$", false, null),
+ new Property(@"^Ice\.Default\.SourceAddress$", false, null),
+ new Property(@"^Ice\.Default\.Timeout$", false, null),
+ new Property(@"^Ice\.EventLog\.Source$", false, null),
+ new Property(@"^Ice\.FactoryAssemblies$", false, null),
+ new Property(@"^Ice\.HTTPProxyHost$", false, null),
+ new Property(@"^Ice\.HTTPProxyPort$", false, null),
+ new Property(@"^Ice\.ImplicitContext$", false, null),
+ new Property(@"^Ice\.InitPlugins$", false, null),
+ new Property(@"^Ice\.IPv4$", false, null),
+ new Property(@"^Ice\.IPv6$", false, null),
+ new Property(@"^Ice\.LogFile$", false, null),
+ new Property(@"^Ice\.LogStdErr\.Convert$", false, null),
+ new Property(@"^Ice\.MessageSizeMax$", false, null),
+ new Property(@"^Ice\.Nohup$", false, null),
+ new Property(@"^Ice\.NullHandleAbort$", false, null),
+ new Property(@"^Ice\.Override\.CloseTimeout$", false, null),
+ new Property(@"^Ice\.Override\.Compress$", false, null),
+ new Property(@"^Ice\.Override\.ConnectTimeout$", false, null),
+ new Property(@"^Ice\.Override\.Timeout$", false, null),
+ new Property(@"^Ice\.Override\.Secure$", false, null),
+ new Property(@"^Ice\.Package\.[^\s]+$", false, null),
+ new Property(@"^Ice\.Plugin\.[^\s]+$", false, null),
+ new Property(@"^Ice\.PluginLoadOrder$", false, null),
+ new Property(@"^Ice\.PreferIPv6Address$", false, null),
+ new Property(@"^Ice\.PrintAdapterReady$", false, null),
+ new Property(@"^Ice\.PrintProcessId$", false, null),
+ new Property(@"^Ice\.PrintStackTraces$", false, null),
+ new Property(@"^Ice\.ProgramName$", false, null),
+ new Property(@"^Ice\.RetryIntervals$", false, null),
+ new Property(@"^Ice\.ServerIdleTime$", false, null),
+ new Property(@"^Ice\.SOCKSProxyHost$", false, null),
+ new Property(@"^Ice\.SOCKSProxyPort$", false, null),
+ new Property(@"^Ice\.StdErr$", false, null),
+ new Property(@"^Ice\.StdOut$", false, null),
+ new Property(@"^Ice\.SyslogFacility$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Client\.Size$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Client\.SizeMax$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Client\.SizeWarn$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Client\.StackSize$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Client\.Serialize$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Client\.ThreadIdleTime$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Client\.ThreadPriority$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Server\.Size$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Server\.SizeMax$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Server\.SizeWarn$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Server\.StackSize$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Server\.Serialize$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Server\.ThreadIdleTime$", false, null),
+ new Property(@"^Ice\.ThreadPool\.Server\.ThreadPriority$", false, null),
+ new Property(@"^Ice\.ThreadPriority$", false, null),
+ new Property(@"^Ice\.Trace\.Admin\.Properties$", false, null),
+ new Property(@"^Ice\.Trace\.Admin\.Logger$", false, null),
+ new Property(@"^Ice\.Trace\.Locator$", false, null),
+ new Property(@"^Ice\.Trace\.Network$", false, null),
+ new Property(@"^Ice\.Trace\.Protocol$", false, null),
+ new Property(@"^Ice\.Trace\.Retry$", false, null),
+ new Property(@"^Ice\.Trace\.Slicing$", false, null),
+ new Property(@"^Ice\.Trace\.ThreadPool$", false, null),
+ new Property(@"^Ice\.UDP\.RcvSize$", false, null),
+ new Property(@"^Ice\.UDP\.SndSize$", false, null),
+ new Property(@"^Ice\.TCP\.Backlog$", false, null),
+ new Property(@"^Ice\.TCP\.RcvSize$", false, null),
+ new Property(@"^Ice\.TCP\.SndSize$", false, null),
+ new Property(@"^Ice\.UseApplicationClassLoader$", false, null),
+ new Property(@"^Ice\.UseSyslog$", false, null),
+ new Property(@"^Ice\.Warn\.AMICallback$", false, null),
+ new Property(@"^Ice\.Warn\.Connections$", false, null),
+ new Property(@"^Ice\.Warn\.Datagrams$", false, null),
+ new Property(@"^Ice\.Warn\.Dispatch$", false, null),
+ new Property(@"^Ice\.Warn\.Endpoints$", false, null),
+ new Property(@"^Ice\.Warn\.UnknownProperties$", false, null),
+ new Property(@"^Ice\.Warn\.UnusedProperties$", false, null),
+ new Property(@"^Ice\.CacheMessageBuffers$", false, null),
+ new Property(@"^Ice\.ThreadInterruptSafe$", false, null),
+ null
+ };
+
+ public static Property[] IceMXProps =
+ {
+ new Property(@"^IceMX\.Metrics\.[^\s]+\.GroupBy$", false, null),
+ new Property(@"^IceMX\.Metrics\.[^\s]+\.Map$", false, null),
+ new Property(@"^IceMX\.Metrics\.[^\s]+\.RetainDetached$", false, null),
+ new Property(@"^IceMX\.Metrics\.[^\s]+\.Accept$", false, null),
+ new Property(@"^IceMX\.Metrics\.[^\s]+\.Reject$", false, null),
+ new Property(@"^IceMX\.Metrics\.[^\s]+$", false, null),
+ null
+ };
+
+ public static Property[] IceDiscoveryProps =
+ {
+ new Property(@"^IceDiscovery\.Multicast\.ACM\.Timeout$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ACM\.Close$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ACM$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.AdapterId$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Endpoints$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.PublishedEndpoints$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ReplicaGroupId$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ProxyOptions$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceDiscovery\.Multicast\.MessageSizeMax$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ACM\.Timeout$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ACM\.Close$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ACM$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.AdapterId$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Endpoints$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.PublishedEndpoints$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ReplicaGroupId$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ProxyOptions$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceDiscovery\.Reply\.MessageSizeMax$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ACM\.Timeout$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ACM\.Close$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ACM$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.AdapterId$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Endpoints$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.PublishedEndpoints$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ReplicaGroupId$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.Locator$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.Router$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ProxyOptions$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceDiscovery\.Locator\.MessageSizeMax$", false, null),
+ new Property(@"^IceDiscovery\.Lookup$", false, null),
+ new Property(@"^IceDiscovery\.Timeout$", false, null),
+ new Property(@"^IceDiscovery\.RetryCount$", false, null),
+ new Property(@"^IceDiscovery\.LatencyMultiplier$", false, null),
+ new Property(@"^IceDiscovery\.Address$", false, null),
+ new Property(@"^IceDiscovery\.Port$", false, null),
+ new Property(@"^IceDiscovery\.Interface$", false, null),
+ new Property(@"^IceDiscovery\.DomainId$", false, null),
+ null
+ };
+
+ public static Property[] IceGridDiscoveryProps =
+ {
+ new Property(@"^IceGridDiscovery\.Reply\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ACM\.Close$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ACM$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.AdapterId$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Endpoints$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.Locator$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.Router$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Locator$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.Locator$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.Router$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.Router$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ProxyOptions$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGridDiscovery\.Reply\.MessageSizeMax$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ACM\.Close$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ACM$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.AdapterId$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Endpoints$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.Locator$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.Router$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Locator$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.Locator$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.Router$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.Router$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ProxyOptions$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGridDiscovery\.Locator\.MessageSizeMax$", false, null),
+ new Property(@"^IceGridDiscovery\.Lookup$", false, null),
+ new Property(@"^IceGridDiscovery\.Timeout$", false, null),
+ new Property(@"^IceGridDiscovery\.RetryCount$", false, null),
+ new Property(@"^IceGridDiscovery\.RetryDelay$", false, null),
+ new Property(@"^IceGridDiscovery\.Address$", false, null),
+ new Property(@"^IceGridDiscovery\.Port$", false, null),
+ new Property(@"^IceGridDiscovery\.Interface$", false, null),
+ new Property(@"^IceGridDiscovery\.InstanceName$", false, null),
+ null
+ };
+
+ public static Property[] IceBoxProps =
+ {
+ new Property(@"^IceBox\.InheritProperties$", false, null),
+ new Property(@"^IceBox\.InstanceName$", true, null),
+ new Property(@"^IceBox\.LoadOrder$", false, null),
+ new Property(@"^IceBox\.PrintServicesReady$", false, null),
+ new Property(@"^IceBox\.Service\.[^\s]+$", false, null),
+ new Property(@"^IceBox\.ServiceManager\.AdapterId$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.Endpoints$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.Locator$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.PublishedEndpoints$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.ReplicaGroupId$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.Router$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.ThreadPool\.Size$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.ThreadPool\.SizeMax$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.ThreadPool\.SizeWarn$", true, null),
+ new Property(@"^IceBox\.ServiceManager\.ThreadPool\.StackSize$", true, null),
+ new Property(@"^IceBox\.Trace\.ServiceObserver$", false, null),
+ new Property(@"^IceBox\.UseSharedCommunicator\.[^\s]+$", false, null),
+ null
+ };
+
+ public static Property[] IceBoxAdminProps =
+ {
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.EndpointSelection$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.ConnectionCached$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.PreferSecure$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.InvocationTimeout$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.Locator$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.Router$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.CollocationOptimized$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceBoxAdmin\.ServiceManager\.Proxy$", false, null),
+ null
+ };
+
+ public static Property[] IceGridAdminProps =
+ {
+ new Property(@"^IceGridAdmin\.AuthenticateUsingSSL$", false, null),
+ new Property(@"^IceGridAdmin\.MetricsConfig$", false, null),
+ new Property(@"^IceGridAdmin\.Username$", false, null),
+ new Property(@"^IceGridAdmin\.Password$", false, null),
+ new Property(@"^IceGridAdmin\.Replica$", false, null),
+ new Property(@"^IceGridAdmin\.Host$", false, null),
+ new Property(@"^IceGridAdmin\.Port$", false, null),
+ new Property(@"^IceGridAdmin\.InstanceName$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Address$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Interface$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Lookup$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ACM\.Close$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ACM$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.AdapterId$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Endpoints$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.Locator$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.Router$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Locator$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.Locator$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.Router$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.Router$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ProxyOptions$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGridAdmin\.Discovery\.Reply\.MessageSizeMax$", false, null),
+ new Property(@"^IceGridAdmin\.Trace\.Observers$", false, null),
+ new Property(@"^IceGridAdmin\.Trace\.SaveToRegistry$", false, null),
+ null
+ };
+
+ public static Property[] IceGridProps =
+ {
+ new Property(@"^IceGrid\.AdminRouter\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ACM$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Locator$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.Router$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.AdminRouter\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.InstanceName$", false, null),
+ new Property(@"^IceGrid\.Node\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.Node\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.Node\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.Node\.ACM$", false, null),
+ new Property(@"^IceGrid\.Node\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.Node\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Node\.Locator$", false, null),
+ new Property(@"^IceGrid\.Node\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.Node\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Node\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Node\.Router$", false, null),
+ new Property(@"^IceGrid\.Node\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.Node\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.Node\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.Node\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.Node\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.Node\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.Node\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.Node\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.Node\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.Node\.AllowRunningServersAsRoot$", false, null),
+ new Property(@"^IceGrid\.Node\.AllowEndpointsOverride$", false, null),
+ new Property(@"^IceGrid\.Node\.CollocateRegistry$", false, null),
+ new Property(@"^IceGrid\.Node\.Data$", false, null),
+ new Property(@"^IceGrid\.Node\.DisableOnFailure$", false, null),
+ new Property(@"^IceGrid\.Node\.Name$", false, null),
+ new Property(@"^IceGrid\.Node\.Output$", false, null),
+ new Property(@"^IceGrid\.Node\.ProcessorSocketCount$", false, null),
+ new Property(@"^IceGrid\.Node\.PrintServersReady$", false, null),
+ new Property(@"^IceGrid\.Node\.PropertiesOverride$", false, null),
+ new Property(@"^IceGrid\.Node\.RedirectErrToOut$", false, null),
+ new Property(@"^IceGrid\.Node\.Trace\.Activator$", false, null),
+ new Property(@"^IceGrid\.Node\.Trace\.Adapter$", false, null),
+ new Property(@"^IceGrid\.Node\.Trace\.Patch$", false, null),
+ new Property(@"^IceGrid\.Node\.Trace\.Replica$", false, null),
+ new Property(@"^IceGrid\.Node\.Trace\.Server$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccounts$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.Locator$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.Router$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Node\.UserAccountMapper$", false, null),
+ new Property(@"^IceGrid\.Node\.WaitTime$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminCryptPasswords$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminPermissionsVerifier$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionFilters$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ACM$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSessionManager\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.AdminSSLPermissionsVerifier$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ACM$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.Registry\.Client\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.CryptPasswords$", false, null),
+ new Property(@"^IceGrid\.Registry\.Data$", false, null),
+ new Property(@"^IceGrid\.Registry\.DefaultTemplates$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ACM$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Enabled$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Address$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Port$", false, null),
+ new Property(@"^IceGrid\.Registry\.Discovery\.Interface$", false, null),
+ new Property(@"^IceGrid\.Registry\.DynamicRegistration$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ACM$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.Registry\.Internal\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.NodeSessionTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.PermissionsVerifier$", false, null),
+ new Property(@"^IceGrid\.Registry\.ReplicaName$", false, null),
+ new Property(@"^IceGrid\.Registry\.ReplicaSessionTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.RequireNodeCertCN$", false, null),
+ new Property(@"^IceGrid\.Registry\.RequireReplicaCertCN$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ACM$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.Registry\.Server\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionFilters$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ACM\.Timeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ACM\.Close$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ACM$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.AdapterId$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Endpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.PublishedEndpoints$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ReplicaGroupId$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ProxyOptions$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ThreadPool\.Size$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionManager\.MessageSizeMax$", false, null),
+ new Property(@"^IceGrid\.Registry\.SessionTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.EndpointSelection$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.ConnectionCached$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.PreferSecure$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.InvocationTimeout$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.Router$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.CollocationOptimized$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier\.Context\.[^\s]+$", false, null),
+ new Property(@"^IceGrid\.Registry\.SSLPermissionsVerifier$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Application$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Adapter$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Locator$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Node$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Object$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Patch$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Replica$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Server$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Session$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Subscriber$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.Topic$", false, null),
+ new Property(@"^IceGrid\.Registry\.Trace\.TopicManager$", false, null),
+ new Property(@"^IceGrid\.Registry\.UserAccounts$", false, null),
+ new Property(@"^IceGrid\.SQL\.DatabaseType$", false, null),
+ new Property(@"^IceGrid\.SQL\.EncodingVersion$", false, null),
+ new Property(@"^IceGrid\.SQL\.HostName$", false, null),
+ new Property(@"^IceGrid\.SQL\.Port$", false, null),
+ new Property(@"^IceGrid\.SQL\.DatabaseName$", false, null),
+ new Property(@"^IceGrid\.SQL\.UserName$", false, null),
+ new Property(@"^IceGrid\.SQL\.Password$", false, null),
+ null
+ };
+
+ public static Property[] IcePatch2Props =
+ {
+ new Property(@"^IcePatch2\.ACM\.Timeout$", false, null),
+ new Property(@"^IcePatch2\.ACM\.Heartbeat$", false, null),
+ new Property(@"^IcePatch2\.ACM\.Close$", false, null),
+ new Property(@"^IcePatch2\.ACM$", false, null),
+ new Property(@"^IcePatch2\.AdapterId$", false, null),
+ new Property(@"^IcePatch2\.Endpoints$", false, null),
+ new Property(@"^IcePatch2\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^IcePatch2\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^IcePatch2\.Locator\.PreferSecure$", false, null),
+ new Property(@"^IcePatch2\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IcePatch2\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^IcePatch2\.Locator\.Locator$", false, null),
+ new Property(@"^IcePatch2\.Locator\.Router$", false, null),
+ new Property(@"^IcePatch2\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^IcePatch2\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^IcePatch2\.Locator$", false, null),
+ new Property(@"^IcePatch2\.PublishedEndpoints$", false, null),
+ new Property(@"^IcePatch2\.ReplicaGroupId$", false, null),
+ new Property(@"^IcePatch2\.Router\.EndpointSelection$", false, null),
+ new Property(@"^IcePatch2\.Router\.ConnectionCached$", false, null),
+ new Property(@"^IcePatch2\.Router\.PreferSecure$", false, null),
+ new Property(@"^IcePatch2\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^IcePatch2\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^IcePatch2\.Router\.Locator$", false, null),
+ new Property(@"^IcePatch2\.Router\.Router$", false, null),
+ new Property(@"^IcePatch2\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^IcePatch2\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^IcePatch2\.Router$", false, null),
+ new Property(@"^IcePatch2\.ProxyOptions$", false, null),
+ new Property(@"^IcePatch2\.ThreadPool\.Size$", false, null),
+ new Property(@"^IcePatch2\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^IcePatch2\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^IcePatch2\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^IcePatch2\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^IcePatch2\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^IcePatch2\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^IcePatch2\.MessageSizeMax$", false, null),
+ new Property(@"^IcePatch2\.Directory$", false, null),
+ new Property(@"^IcePatch2\.InstanceName$", false, null),
+ null
+ };
+
+ public static Property[] IcePatch2ClientProps =
+ {
+ new Property(@"^IcePatch2Client\.ChunkSize$", false, null),
+ new Property(@"^IcePatch2Client\.Directory$", false, null),
+ new Property(@"^IcePatch2Client\.Proxy$", false, null),
+ new Property(@"^IcePatch2Client\.Remove$", false, null),
+ new Property(@"^IcePatch2Client\.Thorough$", false, null),
+ null
+ };
+
+ public static Property[] IceSSLProps =
+ {
+ new Property(@"^IceSSL\.Alias$", false, null),
+ new Property(@"^IceSSL\.CertAuthDir$", false, null),
+ new Property(@"^IceSSL\.CertAuthFile$", false, null),
+ new Property(@"^IceSSL\.CertStore$", false, null),
+ new Property(@"^IceSSL\.CertFile$", false, null),
+ new Property(@"^IceSSL\.CertVerifier$", false, null),
+ new Property(@"^IceSSL\.CheckCertName$", false, null),
+ new Property(@"^IceSSL\.CheckCRL$", false, null),
+ new Property(@"^IceSSL\.Ciphers$", false, null),
+ new Property(@"^IceSSL\.DefaultDir$", false, null),
+ new Property(@"^IceSSL\.DH\.[^\s]+$", false, null),
+ new Property(@"^IceSSL\.DHParams$", false, null),
+ new Property(@"^IceSSL\.EntropyDaemon$", false, null),
+ new Property(@"^IceSSL\.FindCert$", false, null),
+ new Property(@"^IceSSL\.FindCert\.[^\s]+$", false, null),
+ new Property(@"^IceSSL\.ImportCert\.[^\s]+$", true, null),
+ new Property(@"^IceSSL\.InitOpenSSL$", false, null),
+ new Property(@"^IceSSL\.KeyFile$", false, null),
+ new Property(@"^IceSSL\.KeySet$", false, null),
+ new Property(@"^IceSSL\.Keychain$", false, null),
+ new Property(@"^IceSSL\.KeychainPassword$", false, null),
+ new Property(@"^IceSSL\.Keystore$", false, null),
+ new Property(@"^IceSSL\.KeystorePassword$", false, null),
+ new Property(@"^IceSSL\.KeystoreType$", false, null),
+ new Property(@"^IceSSL\.Password$", false, null),
+ new Property(@"^IceSSL\.PasswordCallback$", false, null),
+ new Property(@"^IceSSL\.PasswordRetryMax$", false, null),
+ new Property(@"^IceSSL\.PersistKeySet$", false, null),
+ new Property(@"^IceSSL\.Protocols$", false, null),
+ new Property(@"^IceSSL\.ProtocolVersionMax$", false, null),
+ new Property(@"^IceSSL\.ProtocolVersionMin$", false, null),
+ new Property(@"^IceSSL\.Random$", false, null),
+ new Property(@"^IceSSL\.Trace\.Security$", false, null),
+ new Property(@"^IceSSL\.TrustOnly$", false, null),
+ new Property(@"^IceSSL\.TrustOnly\.Client$", false, null),
+ new Property(@"^IceSSL\.TrustOnly\.Server$", false, null),
+ new Property(@"^IceSSL\.TrustOnly\.Server\.[^\s]+$", false, null),
+ new Property(@"^IceSSL\.Truststore$", false, null),
+ new Property(@"^IceSSL\.TruststorePassword$", false, null),
+ new Property(@"^IceSSL\.TruststoreType$", false, null),
+ new Property(@"^IceSSL\.VerifyDepthMax$", false, null),
+ new Property(@"^IceSSL\.VerifyPeer$", false, null),
+ null
+ };
+
+ public static Property[] IceStormAdminProps =
+ {
+ new Property(@"^IceStormAdmin\.TopicManager\.[^\s]+$", false, null),
+ new Property(@"^IceStormAdmin\.Host$", false, null),
+ new Property(@"^IceStormAdmin\.Port$", false, null),
+ null
+ };
+
+ public static Property[] Glacier2Props =
+ {
+ new Property(@"^Glacier2\.AddConnectionContext$", false, null),
+ new Property(@"^Glacier2\.Client\.ACM\.Timeout$", false, null),
+ new Property(@"^Glacier2\.Client\.ACM\.Heartbeat$", false, null),
+ new Property(@"^Glacier2\.Client\.ACM\.Close$", false, null),
+ new Property(@"^Glacier2\.Client\.ACM$", false, null),
+ new Property(@"^Glacier2\.Client\.AdapterId$", false, null),
+ new Property(@"^Glacier2\.Client\.Endpoints$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.Locator$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.Router$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.Client\.Locator$", false, null),
+ new Property(@"^Glacier2\.Client\.PublishedEndpoints$", false, null),
+ new Property(@"^Glacier2\.Client\.ReplicaGroupId$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.Locator$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.Router$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.Client\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.Client\.Router$", false, null),
+ new Property(@"^Glacier2\.Client\.ProxyOptions$", false, null),
+ new Property(@"^Glacier2\.Client\.ThreadPool\.Size$", false, null),
+ new Property(@"^Glacier2\.Client\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^Glacier2\.Client\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^Glacier2\.Client\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^Glacier2\.Client\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^Glacier2\.Client\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^Glacier2\.Client\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^Glacier2\.Client\.MessageSizeMax$", false, null),
+ new Property(@"^Glacier2\.Client\.AlwaysBatch$", false, null),
+ new Property(@"^Glacier2\.Client\.Buffered$", false, null),
+ new Property(@"^Glacier2\.Client\.ForwardContext$", false, null),
+ new Property(@"^Glacier2\.Client\.SleepTime$", false, null),
+ new Property(@"^Glacier2\.Client\.Trace\.Override$", false, null),
+ new Property(@"^Glacier2\.Client\.Trace\.Reject$", false, null),
+ new Property(@"^Glacier2\.Client\.Trace\.Request$", false, null),
+ new Property(@"^Glacier2\.CryptPasswords$", false, null),
+ new Property(@"^Glacier2\.Filter\.Address\.Reject$", false, null),
+ new Property(@"^Glacier2\.Filter\.Address\.Accept$", false, null),
+ new Property(@"^Glacier2\.Filter\.ProxySizeMax$", false, null),
+ new Property(@"^Glacier2\.Filter\.Category\.Accept$", false, null),
+ new Property(@"^Glacier2\.Filter\.Category\.AcceptUser$", false, null),
+ new Property(@"^Glacier2\.Filter\.AdapterId\.Accept$", false, null),
+ new Property(@"^Glacier2\.Filter\.Identity\.Accept$", false, null),
+ new Property(@"^Glacier2\.InstanceName$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.Locator$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.Router$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.PermissionsVerifier$", false, null),
+ new Property(@"^Glacier2\.ReturnClientProxy$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.Locator$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.Router$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.SSLPermissionsVerifier$", false, null),
+ new Property(@"^Glacier2\.RoutingTable\.MaxSize$", false, null),
+ new Property(@"^Glacier2\.Server\.ACM\.Timeout$", false, null),
+ new Property(@"^Glacier2\.Server\.ACM\.Heartbeat$", false, null),
+ new Property(@"^Glacier2\.Server\.ACM\.Close$", false, null),
+ new Property(@"^Glacier2\.Server\.ACM$", false, null),
+ new Property(@"^Glacier2\.Server\.AdapterId$", false, null),
+ new Property(@"^Glacier2\.Server\.Endpoints$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.Locator$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.Router$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.Server\.Locator$", false, null),
+ new Property(@"^Glacier2\.Server\.PublishedEndpoints$", false, null),
+ new Property(@"^Glacier2\.Server\.ReplicaGroupId$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.Locator$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.Router$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.Server\.Router\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.Server\.Router$", false, null),
+ new Property(@"^Glacier2\.Server\.ProxyOptions$", false, null),
+ new Property(@"^Glacier2\.Server\.ThreadPool\.Size$", false, null),
+ new Property(@"^Glacier2\.Server\.ThreadPool\.SizeMax$", false, null),
+ new Property(@"^Glacier2\.Server\.ThreadPool\.SizeWarn$", false, null),
+ new Property(@"^Glacier2\.Server\.ThreadPool\.StackSize$", false, null),
+ new Property(@"^Glacier2\.Server\.ThreadPool\.Serialize$", false, null),
+ new Property(@"^Glacier2\.Server\.ThreadPool\.ThreadIdleTime$", false, null),
+ new Property(@"^Glacier2\.Server\.ThreadPool\.ThreadPriority$", false, null),
+ new Property(@"^Glacier2\.Server\.MessageSizeMax$", false, null),
+ new Property(@"^Glacier2\.Server\.AlwaysBatch$", false, null),
+ new Property(@"^Glacier2\.Server\.Buffered$", false, null),
+ new Property(@"^Glacier2\.Server\.ForwardContext$", false, null),
+ new Property(@"^Glacier2\.Server\.SleepTime$", false, null),
+ new Property(@"^Glacier2\.Server\.Trace\.Override$", false, null),
+ new Property(@"^Glacier2\.Server\.Trace\.Request$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.Locator$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.Router$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.SessionManager\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.SessionManager$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.EndpointSelection$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.ConnectionCached$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.PreferSecure$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.LocatorCacheTimeout$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.InvocationTimeout$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.Locator$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.Router$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.CollocationOptimized$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager\.Context\.[^\s]+$", false, null),
+ new Property(@"^Glacier2\.SSLSessionManager$", false, null),
+ new Property(@"^Glacier2\.SessionTimeout$", false, null),
+ new Property(@"^Glacier2\.Trace\.RoutingTable$", false, null),
+ new Property(@"^Glacier2\.Trace\.Session$", false, null),
+ null
+ };
+
+ public static Property[] Glacier2CryptPermissionsVerifierProps =
+ {
+ new Property(@"^Glacier2CryptPermissionsVerifier\.[^\s]+\.PermissionsVerifier$", false, null),
+ new Property(@"^Glacier2CryptPermissionsVerifier\.[^\s]+\.AdminPermissionsVerifier$", false, null),
+ null
+ };
+
+ public static Property[] FreezeProps =
+ {
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.CheckpointPeriod$", false, null),
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.DbHome$", false, null),
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.DbPrivate$", false, null),
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.DbRecoverFatal$", false, null),
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.EncodingVersion$", false, null),
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.LockFile$", false, null),
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.OldLogsAutoDelete$", false, null),
+ new Property(@"^Freeze\.DbEnv\.[^\s]+\.PeriodicCheckpointMinSize$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.BtreeMinKey$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.Checksum$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.MaxTxSize$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.PageSize$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.PopulateEmptyIndices$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.RollbackOnUserException$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.SavePeriod$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.SaveSizeTrigger$", false, null),
+ new Property(@"^Freeze\.Evictor\.[^\s]+\.StreamTimeout$", false, null),
+ new Property(@"^Freeze\.Map\.[^\s]+\.BtreeMinKey$", false, null),
+ new Property(@"^Freeze\.Map\.[^\s]+\.Checksum$", false, null),
+ new Property(@"^Freeze\.Map\.[^\s]+\.PageSize$", false, null),
+ new Property(@"^Freeze\.Trace\.DbEnv$", false, null),
+ new Property(@"^Freeze\.Trace\.Evictor$", false, null),
+ new Property(@"^Freeze\.Trace\.Map$", false, null),
+ new Property(@"^Freeze\.Trace\.Transaction$", false, null),
+ new Property(@"^Freeze\.Warn\.Deadlocks$", false, null),
+ new Property(@"^Freeze\.Warn\.Rollback$", false, null),
+ null
+ };
+
+ public static Property[][] validProps =
+ {
+ IceProps,
+ IceMXProps,
+ IceDiscoveryProps,
+ IceGridDiscoveryProps,
+ IceBoxProps,
+ IceBoxAdminProps,
+ IceGridAdminProps,
+ IceGridProps,
+ IcePatch2Props,
+ IcePatch2ClientProps,
+ IceSSLProps,
+ IceStormAdminProps,
+ Glacier2Props,
+ Glacier2CryptPermissionsVerifierProps,
+ FreezeProps,
+ null
+ };
+
+ public static string[] clPropNames =
+ {
+ "Ice",
+ "IceMX",
+ "IceDiscovery",
+ "IceGridDiscovery",
+ "IceBox",
+ "IceBoxAdmin",
+ "IceGridAdmin",
+ "IceGrid",
+ "IcePatch2",
+ "IcePatch2Client",
+ "IceSSL",
+ "IceStormAdmin",
+ "Glacier2",
+ "Glacier2CryptPermissionsVerifier",
+ "Freeze",
+ null
+ };
+ }
+}
diff --git a/csharp/src/Ice/Protocol.cs b/csharp/src/Ice/Protocol.cs
new file mode 100644
index 00000000000..f4d8823369a
--- /dev/null
+++ b/csharp/src/Ice/Protocol.cs
@@ -0,0 +1,184 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ sealed class Protocol
+ {
+ //
+ // Size of the Ice protocol header
+ //
+ // Magic number (4 bytes)
+ // Protocol version major (Byte)
+ // Protocol version minor (Byte)
+ // Encoding version major (Byte)
+ // Encoding version minor (Byte)
+ // Message type (Byte)
+ // Compression status (Byte)
+ // Message size (Int)
+ //
+ internal const int headerSize = 14;
+
+ //
+ // The magic number at the front of each message
+ //
+ internal static readonly byte[] magic
+ = new byte[] { (byte)0x49, (byte)0x63, (byte)0x65, (byte)0x50 }; // 'I', 'c', 'e', 'P'
+
+ //
+ // The current Ice protocol and encoding version
+ //
+ internal const byte protocolMajor = 1;
+ internal const byte protocolMinor = 0;
+ internal const byte protocolEncodingMajor = 1;
+ internal const byte protocolEncodingMinor = 0;
+
+ internal const byte encodingMajor = 1;
+ internal const byte encodingMinor = 1;
+
+ //
+ // The Ice protocol message types
+ //
+ internal const byte requestMsg = 0;
+ internal const byte requestBatchMsg = 1;
+ internal const byte replyMsg = 2;
+ internal const byte validateConnectionMsg = 3;
+ internal const byte closeConnectionMsg = 4;
+
+ internal static readonly byte[] requestHdr = new byte[]
+ {
+ IceInternal.Protocol.magic[0], IceInternal.Protocol.magic[1], IceInternal.Protocol.magic[2],
+ IceInternal.Protocol.magic[3],
+ IceInternal.Protocol.protocolMajor, IceInternal.Protocol.protocolMinor,
+ IceInternal.Protocol.protocolEncodingMajor, IceInternal.Protocol.protocolEncodingMinor,
+ IceInternal.Protocol.requestMsg,
+ (byte)0, // Compression status.
+ (byte)0, (byte)0, (byte)0, (byte)0, // Message size (placeholder).
+ (byte)0, (byte)0, (byte)0, (byte)0 // Request ID (placeholder).
+ };
+
+ internal static readonly byte[] requestBatchHdr = new byte[]
+ {
+ IceInternal.Protocol.magic[0], IceInternal.Protocol.magic[1], IceInternal.Protocol.magic[2],
+ IceInternal.Protocol.magic[3],
+ IceInternal.Protocol.protocolMajor, IceInternal.Protocol.protocolMinor,
+ IceInternal.Protocol.protocolEncodingMajor, IceInternal.Protocol.protocolEncodingMinor,
+ IceInternal.Protocol.requestBatchMsg,
+ (byte)0, // Compression status.
+ (byte)0, (byte)0, (byte)0, (byte)0, // Message size (placeholder).
+ (byte)0, (byte)0, (byte)0, (byte)0 // Number of requests in batch (placeholder).
+ };
+
+ internal static readonly byte[] replyHdr = new byte[]
+ {
+ IceInternal.Protocol.magic[0], IceInternal.Protocol.magic[1], IceInternal.Protocol.magic[2],
+ IceInternal.Protocol.magic[3],
+ IceInternal.Protocol.protocolMajor, IceInternal.Protocol.protocolMinor,
+ IceInternal.Protocol.protocolEncodingMajor, IceInternal.Protocol.protocolEncodingMinor,
+ IceInternal.Protocol.replyMsg,
+ (byte)0, // Compression status.
+ (byte)0, (byte)0, (byte)0, (byte)0 // Message size (placeholder).
+ };
+
+ internal static void
+ checkSupportedProtocol(Ice.ProtocolVersion v)
+ {
+ if(v.major != protocolMajor || v.minor > protocolMinor)
+ {
+ throw new Ice.UnsupportedProtocolException("", v, Ice.Util.currentProtocol);
+ }
+ }
+
+ internal static void
+ checkSupportedProtocolEncoding(Ice.EncodingVersion v)
+ {
+ if(v.major != protocolEncodingMajor || v.minor > protocolEncodingMinor)
+ {
+ throw new Ice.UnsupportedEncodingException("", v, Ice.Util.currentProtocolEncoding);
+ }
+ }
+
+ internal static void
+ checkSupportedEncoding(Ice.EncodingVersion v)
+ {
+ if(v.major != encodingMajor || v.minor > encodingMinor)
+ {
+ throw new Ice.UnsupportedEncodingException("", v, Ice.Util.currentEncoding);
+ }
+ }
+
+ //
+ // Either return the given protocol if not compatible, or the greatest
+ // supported protocol otherwise.
+ //
+ internal static Ice.ProtocolVersion
+ getCompatibleProtocol(Ice.ProtocolVersion v)
+ {
+ if(v.major != Ice.Util.currentProtocol.major)
+ {
+ return v; // Unsupported protocol, return as is.
+ }
+ else if(v.minor < Ice.Util.currentProtocol.minor)
+ {
+ return v; // Supported protocol.
+ }
+ else
+ {
+ //
+ // Unsupported but compatible, use the currently supported
+ // protocol, that's the best we can do.
+ //
+ return Ice.Util.currentProtocol;
+ }
+ }
+
+ //
+ // Either return the given encoding if not compatible, or the greatest
+ // supported encoding otherwise.
+ //
+ internal static Ice.EncodingVersion
+ getCompatibleEncoding(Ice.EncodingVersion v)
+ {
+ if(v.major != Ice.Util.currentEncoding.major)
+ {
+ return v; // Unsupported encoding, return as is.
+ }
+ else if(v.minor < Ice.Util.currentEncoding.minor)
+ {
+ return v; // Supported encoding.
+ }
+ else
+ {
+ //
+ // Unsupported but compatible, use the currently supported
+ // encoding, that's the best we can do.
+ //
+ return Ice.Util.currentEncoding;
+ }
+ }
+
+ internal static bool
+ isSupported(Ice.ProtocolVersion version, Ice.ProtocolVersion supported)
+ {
+ return version.major == supported.major && version.minor <= supported.minor;
+ }
+
+ internal static bool
+ isSupported(Ice.EncodingVersion version, Ice.EncodingVersion supported)
+ {
+ return version.major == supported.major && version.minor <= supported.minor;
+ }
+
+ private Protocol()
+ {
+ }
+ }
+
+}
diff --git a/csharp/src/Ice/ProtocolInstance.cs b/csharp/src/Ice/ProtocolInstance.cs
new file mode 100644
index 00000000000..68c8d33e13f
--- /dev/null
+++ b/csharp/src/Ice/ProtocolInstance.cs
@@ -0,0 +1,149 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Net;
+ using System.Collections.Generic;
+
+ public class ProtocolInstance
+ {
+ public ProtocolInstance(Ice.Communicator communicator, short type, string protocol, bool secure)
+ {
+ instance_ = Util.getInstance(communicator);
+ traceLevel_ = instance_.traceLevels().network;
+ traceCategory_ = instance_.traceLevels().networkCat;
+ logger_ = instance_.initializationData().logger;
+ properties_ = instance_.initializationData().properties;
+ type_ = type;
+ protocol_ = protocol;
+ secure_ = secure;
+ }
+
+ public ProtocolInstance(Instance instance, short type, string protocol, bool secure)
+ {
+ instance_ = instance;
+ traceLevel_ = instance_.traceLevels().network;
+ traceCategory_ = instance_.traceLevels().networkCat;
+ logger_ = instance_.initializationData().logger;
+ properties_ = instance_.initializationData().properties;
+ type_ = type;
+ protocol_ = protocol;
+ secure_ = secure;
+ }
+
+ public int traceLevel()
+ {
+ return traceLevel_;
+ }
+
+ public string traceCategory()
+ {
+ return traceCategory_;
+ }
+
+ public Ice.Logger logger()
+ {
+ return logger_;
+ }
+
+ public string protocol()
+ {
+ return protocol_;
+ }
+
+ public short type()
+ {
+ return type_;
+ }
+
+ public bool secure()
+ {
+ return secure_;
+ }
+
+ public Ice.Properties properties()
+ {
+ return properties_;
+ }
+
+ public bool preferIPv6()
+ {
+ return instance_.preferIPv6();
+ }
+
+ public int protocolSupport()
+ {
+ return instance_.protocolSupport();
+ }
+
+ public string defaultHost()
+ {
+ return instance_.defaultsAndOverrides().defaultHost;
+ }
+
+ public EndPoint defaultSourceAddress()
+ {
+ return instance_.defaultsAndOverrides().defaultSourceAddress;
+ }
+
+ public Ice.EncodingVersion defaultEncoding()
+ {
+ return instance_.defaultsAndOverrides().defaultEncoding;
+ }
+
+ public int defaultTimeout()
+ {
+ return instance_.defaultsAndOverrides().defaultTimeout;
+ }
+
+ public NetworkProxy networkProxy()
+ {
+ return instance_.networkProxy();
+ }
+
+ public int messageSizeMax()
+ {
+ return instance_.messageSizeMax();
+ }
+
+#if !SILVERLIGHT
+ public void resolve(string host, int port, Ice.EndpointSelectionType type, IPEndpointI endpt,
+ EndpointI_connectors callback)
+ {
+ instance_.endpointHostResolver().resolve(host, port, type, endpt, callback);
+ }
+#endif
+
+ public BufSizeWarnInfo getBufSizeWarn(short type)
+ {
+ return instance_.getBufSizeWarn(type);
+ }
+
+ public void setSndBufSizeWarn(short type, int size)
+ {
+ instance_.setSndBufSizeWarn(type, size);
+ }
+
+ public void setRcvBufSizeWarn(short type, int size)
+ {
+ instance_.setRcvBufSizeWarn(type, size);
+ }
+
+ protected Instance instance_;
+ protected int traceLevel_;
+ protected string traceCategory_;
+ protected Ice.Logger logger_;
+ protected Ice.Properties properties_;
+ protected string protocol_;
+ protected short type_;
+ protected bool secure_;
+ }
+
+}
diff --git a/csharp/src/Ice/ProtocolPluginFacade.cs b/csharp/src/Ice/ProtocolPluginFacade.cs
new file mode 100644
index 00000000000..3d924e4c186
--- /dev/null
+++ b/csharp/src/Ice/ProtocolPluginFacade.cs
@@ -0,0 +1,80 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ public interface ProtocolPluginFacade
+ {
+ //
+ // Get the Communicator instance with which this facade is
+ // associated.
+ //
+ Ice.Communicator getCommunicator();
+
+ //
+ // Register an EndpointFactory.
+ //
+ void addEndpointFactory(EndpointFactory factory);
+
+ //
+ // Get an EndpointFactory.
+ //
+ EndpointFactory getEndpointFactory(short type);
+
+ //
+ // Obtain the type for a name.
+ //
+ System.Type findType(string name);
+ }
+
+ public sealed class ProtocolPluginFacadeI : ProtocolPluginFacade
+ {
+ public ProtocolPluginFacadeI(Ice.Communicator communicator)
+ {
+ _communicator = communicator;
+ _instance = IceInternal.Util.getInstance(communicator);
+ }
+
+ //
+ // Get the Communicator instance with which this facade is
+ // associated.
+ //
+ public Ice.Communicator getCommunicator()
+ {
+ return _communicator;
+ }
+
+ //
+ // Register an EndpointFactory.
+ //
+ public void addEndpointFactory(EndpointFactory factory)
+ {
+ _instance.endpointFactoryManager().add(factory);
+ }
+
+ //
+ // Get an EndpointFactory.
+ //
+ public EndpointFactory getEndpointFactory(short type)
+ {
+ return _instance.endpointFactoryManager().get(type);
+ }
+
+ //
+ // Obtain the type for a name.
+ //
+ public System.Type findType(string name)
+ {
+ return AssemblyUtil.findType(_instance, name);
+ }
+
+ private Instance _instance;
+ private Ice.Communicator _communicator;
+ }
+}
diff --git a/csharp/src/Ice/Proxy.cs b/csharp/src/Ice/Proxy.cs
new file mode 100644
index 00000000000..22ea3f51874
--- /dev/null
+++ b/csharp/src/Ice/Proxy.cs
@@ -0,0 +1,2611 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using IceUtilInternal;
+using Ice.Instrumentation;
+
+namespace Ice
+{
+ /// <summary>
+ /// Delegate for a successful <code>ice_isA</code> invocation.
+ /// <param name="ret__">True if the remote object supports the type, false otherwise.</param>
+ /// </summary>
+ public delegate void Callback_Object_ice_isA(bool ret__);
+
+ /// <summary>
+ /// Delegate for a successful <code>ice_ids</code> invocation.
+ /// <param name="ret__">The array of Slice type ids supported by the remote object.</param>
+ /// </summary>
+ public delegate void Callback_Object_ice_ids(string[] ret__);
+
+ /// <summary>
+ /// Delegate for a successful <code>ice_id</code> invocation.
+ /// <param name="ret__">The Slice type id of the most-derived interface supported by the remote object.</param>
+ /// </summary>
+ public delegate void Callback_Object_ice_id(string ret__);
+
+ /// <summary>
+ /// Delegate for a successful <code>ice_ping</code> invocation.
+ /// </summary>
+ public delegate void Callback_Object_ice_ping();
+
+ /// <summary>
+ /// Delegate for a successful <code>ice_invoke</code> invocation.
+ /// <param name="ret__">True if the invocation succeeded, or false if the invocation
+ /// raised a user exception.</param>
+ /// <param name="outEncaps">The encoded out-parameters or user exception.</param>
+ /// </summary>
+ public delegate void Callback_Object_ice_invoke(bool ret__, byte[] outEncaps);
+
+ /// <summary>
+ /// Delegate for a successful <code>ice_getConnection</code> invocation.
+ /// <param name="ret__">The connection used by the proxy.</param>
+ /// </summary>
+ public delegate void Callback_Object_ice_getConnection(Connection ret__);
+
+ /// <summary>
+ /// Base interface of all object proxies.
+ /// </summary>
+ public interface ObjectPrx
+ {
+ /// <summary>
+ /// Returns the communicator that created this proxy.
+ /// </summary>
+ /// <returns>The communicator that created this proxy.</returns>
+ Communicator ice_getCommunicator();
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id__">The type ID of the Slice interface to test against.</param>
+ /// <returns>True if the target object has the interface specified by id__ or derives
+ /// from the interface specified by id__.</returns>
+ bool ice_isA(string id__);
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id__">The type ID of the Slice interface to test against.</param>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>True if the target object has the interface specified by id__ or derives
+ /// from the interface specified by id__.</returns>
+ bool ice_isA(string id__, Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id">The type ID of the Slice interface to test against.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_isA> begin_ice_isA(string id);
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id">The type ID of the Slice interface to test against.</param>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_isA> begin_ice_isA(string id, Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id">The type ID of the Slice interface to test against.</param>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_isA(string id, AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id">The type ID of the Slice interface to test against.</param>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_isA(string id, Dictionary<string, string> context__, AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="r__">The asynchronous result object returned by <code>begin_ice_isA</code>.</param>
+ /// <returns>True if the object supports the Slice interface, false otherwise.</returns>
+ bool end_ice_isA(AsyncResult r__);
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ void ice_ping();
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ void ice_ping(Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_ping> begin_ice_ping();
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_ping> begin_ice_ping(Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_ping(AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_ping(Dictionary<string, string> context__, AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ /// <param name="r__">The asynchronous result object returned by <code>begin_ice_ping</code>.</param>
+ void end_ice_ping(AsyncResult r__);
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <returns>The Slice type IDs of the interfaces supported by the target object, in base-to-derived
+ /// order. The first element of the returned array is always ::Ice::Object.</returns>
+ string[] ice_ids();
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>The Slice type IDs of the interfaces supported by the target object, in base-to-derived
+ /// order. The first element of the returned array is always ::Ice::Object.</returns>
+ string[] ice_ids(Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_ids> begin_ice_ids();
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_ids> begin_ice_ids(Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_ids(AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_ids(Dictionary<string, string> context__, AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="r__">The asynchronous result object returned by <code>begin_ice_ids</code>.</param>
+ /// <returns>The Slice type IDs of the interfaces supported by the target object, in base-to-derived
+ /// order. The first element of the returned array is always ::Ice::Object.</returns>
+ string[] end_ice_ids(AsyncResult r__);
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <returns>The Slice type ID of the most-derived interface.</returns>
+ string ice_id();
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>The Slice type ID of the most-derived interface.</returns>
+ string ice_id(Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_id> begin_ice_id();
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_id> begin_ice_id(Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_id(AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_id(Dictionary<string, string> context__, AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="r__">The asynchronous result object returned by <code>begin_ice_id</code>.</param>
+ /// <returns>The Slice type ID of the most-derived interface.</returns>
+ string end_ice_id(AsyncResult r__);
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <param name="outEncaps">The encoded out-paramaters and return value
+ /// for the operation. The return value follows any out-parameters.</param>
+ /// <returns>If the operation completed successfully, the return value
+ /// is true. If the operation raises a user exception,
+ /// the return value is false; in this case, outEncaps
+ /// contains the encoded user exception. If the operation raises a run-time exception,
+ /// it throws it directly.</returns>
+ bool ice_invoke(string operation, OperationMode mode, byte[] inEncaps, out byte[] outEncaps);
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <param name="outEncaps">The encoded out-paramaters and return value
+ /// for the operation. The return value follows any out-parameters.</param>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>If the operation completed successfully, the return value
+ /// is true. If the operation raises a user exception,
+ /// the return value is false; in this case, outEncaps
+ /// contains the encoded user exception. If the operation raises a run-time exception,
+ /// it throws it directly.</returns>
+ bool ice_invoke(string operation, OperationMode mode, byte[] inEncaps, out byte[] outEncaps,
+ Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_invoke> begin_ice_invoke(string operation, OperationMode mode,
+ byte[] inEncaps);
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_invoke> begin_ice_invoke(string operation, OperationMode mode,
+ byte[] inEncaps,
+ Dictionary<string, string> context__);
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_invoke(string operation, OperationMode mode, byte[] inEncaps, AsyncCallback cb__,
+ object cookie__);
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_invoke(string operation, OperationMode mode, byte[] inEncaps,
+ Dictionary<string, string> context__, AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Completes a dynamic invocation.
+ /// </summary>
+ /// <param name="outEncaps">The encoded out parameters or user exception.</param>
+ /// <param name="r__">The asynchronous result object returned by <code>begin_ice_invoke</code>.</param>
+ /// <returns>If the operation completed successfully, the return value
+ /// is true. If the operation raises a user exception,
+ /// the return value is false; in this case, outEncaps
+ /// contains the encoded user exception. If the operation raises a run-time exception,
+ /// it throws it directly.</returns>
+ bool end_ice_invoke(out byte[] outEncaps, AsyncResult r__);
+
+ /// <summary>
+ /// Returns the identity embedded in this proxy.
+ /// <returns>The identity of the target object.</returns>
+ /// </summary>
+ Identity ice_getIdentity();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the per-proxy context.
+ /// <param name="newIdentity">The identity for the new proxy.</param>
+ /// <returns>The proxy with the new identity.</returns>
+ /// </summary>
+ ObjectPrx ice_identity(Identity newIdentity);
+
+ /// <summary>
+ /// Returns the per-proxy context for this proxy.
+ /// </summary>
+ /// <returns>The per-proxy context. If the proxy does not have a per-proxy (implicit) context, the return value
+ /// is null.</returns>
+ Dictionary<string, string> ice_getContext();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the per-proxy context.
+ /// </summary>
+ /// <param name="newContext">The context for the new proxy.</param>
+ /// <returns>The proxy with the new per-proxy context.</returns>
+ ObjectPrx ice_context(Dictionary<string, string> newContext);
+
+ /// <summary>
+ /// Returns the facet for this proxy.
+ /// </summary>
+ /// <returns>The facet for this proxy. If the proxy uses the default facet, the return value is the
+ /// empty string.</returns>
+ string ice_getFacet();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the facet.
+ /// </summary>
+ /// <param name="newFacet">The facet for the new proxy.</param>
+ /// <returns>The proxy with the new facet.</returns>
+ ObjectPrx ice_facet(string newFacet);
+
+ /// <summary>
+ /// Returns the adapter ID for this proxy.
+ /// </summary>
+ /// <returns>The adapter ID. If the proxy does not have an adapter ID, the return value is the
+ /// empty string.</returns>
+ string ice_getAdapterId();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the adapter ID.
+ /// </summary>
+ /// <param name="newAdapterId">The adapter ID for the new proxy.</param>
+ /// <returns>The proxy with the new adapter ID.</returns>
+ ObjectPrx ice_adapterId(string newAdapterId);
+
+ /// <summary>
+ /// Returns the endpoints used by this proxy.
+ /// </summary>
+ /// <returns>The endpoints used by this proxy.</returns>
+ Endpoint[] ice_getEndpoints();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the endpoints.
+ /// </summary>
+ /// <param name="newEndpoints">The endpoints for the new proxy.</param>
+ /// <returns>The proxy with the new endpoints.</returns>
+ ObjectPrx ice_endpoints(Endpoint[] newEndpoints);
+
+ /// <summary>
+ /// Returns the locator cache timeout of this proxy.
+ /// </summary>
+ /// <returns>The locator cache timeout value (in seconds).</returns>
+ int ice_getLocatorCacheTimeout();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the locator cache timeout.
+ /// </summary>
+ /// <param name="timeout">The new locator cache timeout (in seconds).</param>
+ ObjectPrx ice_locatorCacheTimeout(int timeout);
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the invocation timeout.
+ /// </summary>
+ /// <param name="timeout">The new invocation timeout (in seconds).</param>
+ ObjectPrx ice_invocationTimeout(int timeout);
+
+ /// <summary>
+ /// Returns the invocation timeout of this proxy.
+ /// </summary>
+ /// <returns>The invocation timeout value (in seconds).</returns>
+ int ice_getInvocationTimeout();
+
+ /// <summary>
+ /// Returns whether this proxy caches connections.
+ /// </summary>
+ /// <returns>True if this proxy caches connections; false, otherwise.</returns>
+ bool ice_isConnectionCached();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for connection caching.
+ /// </summary>
+ /// <param name="newCache">True if the new proxy should cache connections; false, otherwise.</param>
+ /// <returns>The new proxy with the specified caching policy.</returns>
+ ObjectPrx ice_connectionCached(bool newCache);
+
+ /// <summary>
+ /// Returns how this proxy selects endpoints (randomly or ordered).
+ /// </summary>
+ /// <returns>The endpoint selection policy.</returns>
+ EndpointSelectionType ice_getEndpointSelection();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the endpoint selection policy.
+ /// </summary>
+ /// <param name="newType">The new endpoint selection policy.</param>
+ /// <returns>The new proxy with the specified endpoint selection policy.</returns>
+ ObjectPrx ice_endpointSelection(EndpointSelectionType newType);
+
+ /// <summary>
+ /// Returns whether this proxy communicates only via secure endpoints.
+ /// </summary>
+ /// <returns>True if this proxy communicates only vi secure endpoints; false, otherwise.</returns>
+ bool ice_isSecure();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for how it selects endpoints.
+ /// </summary>
+ /// <param name="b"> If b is true, only endpoints that use a secure transport are
+ /// used by the new proxy. If b is false, the returned proxy uses both secure and insecure
+ /// endpoints.</param>
+ /// <returns>The new proxy with the specified selection policy.</returns>
+ ObjectPrx ice_secure(bool b);
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the encoding used to marshal
+ /// parameters.
+ /// </summary>
+ /// <param name="e">The encoding version to use to marshal requests parameters.</param>
+ /// <returns>The new proxy with the specified encoding version.</returns>
+ ObjectPrx ice_encodingVersion(Ice.EncodingVersion e);
+
+ /// <summary>Returns the encoding version used to marshal requests parameters.</summary>
+ /// <returns>The encoding version.</returns>
+ Ice.EncodingVersion ice_getEncodingVersion();
+
+ /// <summary>
+ /// Returns whether this proxy prefers secure endpoints.
+ /// </summary>
+ /// <returns>True if the proxy always attempts to invoke via secure endpoints before it
+ /// attempts to use insecure endpoints; false, otherwise.</returns>
+ bool ice_isPreferSecure();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for its endpoint selection policy.
+ /// </summary>
+ /// <param name="b">If b is true, the new proxy will use secure endpoints for invocations
+ /// and only use insecure endpoints if an invocation cannot be made via secure endpoints. If b is
+ /// false, the proxy prefers insecure endpoints to secure ones.</param>
+ /// <returns>The new proxy with the new endpoint selection policy.</returns>
+ ObjectPrx ice_preferSecure(bool b);
+
+ /// <summary>
+ /// Returns the router for this proxy.
+ /// </summary>
+ /// <returns>The router for the proxy. If no router is configured for the proxy, the return value
+ /// is null.</returns>
+ Ice.RouterPrx ice_getRouter();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the router.
+ /// </summary>
+ /// <param name="router">The router for the new proxy.</param>
+ /// <returns>The new proxy with the specified router.</returns>
+ ObjectPrx ice_router(Ice.RouterPrx router);
+
+ /// <summary>
+ /// Returns the locator for this proxy.
+ /// </summary>
+ /// <returns>The locator for this proxy. If no locator is configured, the return value is null.</returns>
+ Ice.LocatorPrx ice_getLocator();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the locator.
+ /// </summary>
+ /// <param name="locator">The locator for the new proxy.</param>
+ /// <returns>The new proxy with the specified locator.</returns>
+ ObjectPrx ice_locator(Ice.LocatorPrx locator);
+
+ /// <summary>
+ /// Returns whether this proxy uses collocation optimization.
+ /// </summary>
+ /// <returns>True if the proxy uses collocation optimization; false, otherwise.</returns>
+ bool ice_isCollocationOptimized();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for collocation optimization.
+ /// </summary>
+ /// <param name="b">True if the new proxy enables collocation optimization; false, otherwise.</param>
+ /// <returns>The new proxy the specified collocation optimization.</returns>
+ ObjectPrx ice_collocationOptimized(bool b);
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses twoway invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses twoway invocations.</returns>
+ ObjectPrx ice_twoway();
+
+ /// <summary>
+ /// Returns whether this proxy uses twoway invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses twoway invocations; false, otherwise.</returns>
+ bool ice_isTwoway();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses oneway invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses oneway invocations.</returns>
+ ObjectPrx ice_oneway();
+
+ /// <summary>
+ /// Returns whether this proxy uses oneway invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses oneway invocations; false, otherwise.</returns>
+ bool ice_isOneway();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses batch oneway invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses batch oneway invocations.</returns>
+ ObjectPrx ice_batchOneway();
+
+ /// <summary>
+ /// Returns whether this proxy uses batch oneway invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses batch oneway invocations; false, otherwise.</returns>
+ bool ice_isBatchOneway();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses datagram invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses datagram invocations.</returns>
+ ObjectPrx ice_datagram();
+
+ /// <summary>
+ /// Returns whether this proxy uses datagram invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses datagram invocations; false, otherwise.</returns>
+ bool ice_isDatagram();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses batch datagram invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses batch datagram invocations.</returns>
+ ObjectPrx ice_batchDatagram();
+
+ /// <summary>
+ /// Returns whether this proxy uses batch datagram invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses batch datagram invocations; false, otherwise.</returns>
+ bool ice_isBatchDatagram();
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for compression.
+ /// </summary>
+ /// <param name="co">True enables compression for the new proxy; false disables compression.</param>
+ /// <returns>A new proxy with the specified compression setting.</returns>
+ ObjectPrx ice_compress(bool co);
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for its timeout setting.
+ /// </summary>
+ /// <param name="t">The timeout for the new proxy in milliseconds.</param>
+ /// <returns>A new proxy with the specified timeout.</returns>
+ ObjectPrx ice_timeout(int t);
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for its connection ID.
+ /// </summary>
+ /// <param name="connectionId">The connection ID for the new proxy. An empty string removes the
+ /// connection ID.</param>
+ /// <returns>A new proxy with the specified connection ID.</returns>
+ ObjectPrx ice_connectionId(string connectionId);
+
+ /// <summary>
+ /// Returns the connection id of this proxy.
+ /// </summary>
+ /// <returns>The connection id.</returns>
+ string ice_getConnectionId();
+
+ /// <summary>
+ /// Returns the Connection for this proxy. If the proxy does not yet have an established connection,
+ /// it first attempts to create a connection.
+ /// </summary>
+ /// <returns>The Connection for this proxy.</returns>
+ /// <exception name="CollocationOptimizationException">If the proxy uses collocation optimization and denotes a
+ /// collocated object.</exception>
+ Connection ice_getConnection();
+
+ /// <summary>
+ /// Asynchronously gets the connection for this proxy.
+ /// </summary>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult<Callback_Object_ice_getConnection> begin_ice_getConnection();
+
+ /// <summary>
+ /// Asynchronously gets the connection for this proxy.
+ /// </summary>
+ /// <param name="cb__">A callback to be invoked when the invocation completes.</param>
+ /// <param name="cookie__">Application-specific data to be stored in the result.</param>
+ /// <returns>An asynchronous result object.</returns>
+ AsyncResult begin_ice_getConnection(AsyncCallback cb__, object cookie__);
+
+ /// <summary>
+ /// Asynchronously gets the connection for this proxy.
+ /// </summary>
+ /// <param name="r__">The asynchronous result object returned by <code>begin_ice_getConnection</code>.</param>
+ /// <returns>The connection.</returns>
+ Connection end_ice_getConnection(AsyncResult r__);
+
+ /// <summary>
+ /// Returns the cached Connection for this proxy. If the proxy does not yet have an established
+ /// connection, it does not attempt to create a connection.
+ /// </summary>
+ /// <returns>The cached Connection for this proxy (null if the proxy does not have
+ /// an established connection).</returns>
+ /// <exception name="CollocationOptimizationException">If the proxy uses collocation optimization and denotes a
+ /// collocated object.</exception>
+ Connection ice_getCachedConnection();
+
+ /// <summary>
+ /// Flushes any pending batched requests for this communicator. The call blocks until the flush is complete.
+ /// </summary>
+ void ice_flushBatchRequests();
+
+ AsyncResult begin_ice_flushBatchRequests();
+ AsyncResult begin_ice_flushBatchRequests(AsyncCallback cb__, object cookie__);
+
+ void end_ice_flushBatchRequests(AsyncResult r__);
+ }
+
+ /// <summary>
+ /// Base class of all object proxies.
+ /// </summary>
+ public class ObjectPrxHelperBase : ObjectPrx
+ {
+ /// <summary>
+ /// Returns a hash code for this proxy.
+ /// </summary>
+ /// <returns>The hash code.</returns>
+ public override int GetHashCode()
+ {
+ return _reference.GetHashCode();
+ }
+
+ /// <summary>
+ /// Returns the communicator that created this proxy.
+ /// </summary>
+ /// <returns>The communicator that created this proxy.</returns>
+ public Communicator ice_getCommunicator()
+ {
+ return _reference.getCommunicator();
+ }
+
+ /// <summary>
+ /// Returns the stringified form of this proxy.
+ /// </summary>
+ /// <returns>The stringified proxy.</returns>
+ public override string ToString()
+ {
+ return _reference.ToString();
+ }
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id__">The type ID of the Slice interface to test against.</param>
+ /// <returns>True if the target object has the interface specified by id__ or derives
+ /// from the interface specified by id__.</returns>
+ public bool ice_isA(string id__)
+ {
+ return ice_isA(id__, null, false);
+ }
+
+ /// <summary>
+ /// Tests whether this object supports a specific Slice interface.
+ /// </summary>
+ /// <param name="id__">The type ID of the Slice interface to test against.</param>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>True if the target object has the interface specified by id__ or derives
+ /// from the interface specified by id__.</returns>
+ public bool ice_isA(string id__, Dictionary<string, string> context__)
+ {
+ return ice_isA(id__, context__, true);
+ }
+
+ private bool ice_isA(string id__, Dictionary<string, string> context__, bool explicitCtx__)
+ {
+ checkTwowayOnly__(__ice_isA_name);
+ return end_ice_isA(begin_ice_isA(id__, context__, explicitCtx__, true, null, null));
+ }
+
+ public AsyncResult<Callback_Object_ice_isA> begin_ice_isA(string id)
+ {
+ return begin_ice_isA(id, null, false, false, null, null);
+ }
+
+ public AsyncResult<Callback_Object_ice_isA> begin_ice_isA(string id, Dictionary<string, string> context__)
+ {
+ return begin_ice_isA(id, context__, true, false, null, null);
+ }
+
+ public AsyncResult begin_ice_isA(string id, AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_isA(id, null, false, false, cb__, cookie__);
+ }
+
+ public AsyncResult begin_ice_isA(string id, Dictionary<string, string> context__, AsyncCallback cb__,
+ object cookie__)
+ {
+ return begin_ice_isA(id, context__, true, false, cb__, cookie__);
+ }
+
+ internal const string __ice_isA_name = "ice_isA";
+
+ public bool end_ice_isA(AsyncResult r__)
+ {
+ IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_isA_name);
+ try
+ {
+ if(!outAsync__.wait())
+ {
+ try
+ {
+ outAsync__.throwUserException();
+ }
+ catch(Ice.UserException ex__)
+ {
+ throw new Ice.UnknownUserException(ex__.ice_name(), ex__);
+ }
+ }
+ bool ret__;
+ IceInternal.BasicStream is__ = outAsync__.startReadParams();
+ ret__ = is__.readBool();
+ outAsync__.endReadParams();
+ return ret__;
+ }
+ finally
+ {
+ if(outAsync__ != null)
+ {
+ outAsync__.cacheMessageBuffers();
+ }
+ }
+ }
+
+ private AsyncResult<Callback_Object_ice_isA> begin_ice_isA(string id,
+ Dictionary<string, string> context__,
+ bool explicitCtx__,
+ bool synchronous__,
+ Ice.AsyncCallback cb__,
+ object cookie__)
+ {
+ checkAsyncTwowayOnly__(__ice_isA_name);
+
+ IceInternal.TwowayOutgoingAsync<Callback_Object_ice_isA> result__ =
+ getTwowayOutgoingAsync<Callback_Object_ice_isA>(__ice_isA_name, ice_isA_completed__, cookie__);
+ if(cb__ != null)
+ {
+ result__.whenCompletedWithAsyncCallback(cb__);
+ }
+
+ try
+ {
+ result__.prepare(__ice_isA_name, OperationMode.Nonmutating, context__, explicitCtx__, synchronous__);
+ IceInternal.BasicStream os__ = result__.startWriteParams(FormatType.DefaultFormat);
+ os__.writeString(id);
+ result__.endWriteParams();
+ result__.invoke();
+ }
+ catch(Ice.Exception ex__)
+ {
+ result__.abort(ex__);
+ }
+ return result__;
+ }
+
+ protected IceInternal.TwowayOutgoingAsync<T>
+ getTwowayOutgoingAsync<T>(string operation, IceInternal.ProxyTwowayCallback<T> cb,
+ object cookie) {
+ bool haveEntry = false;
+ IceInternal.BasicStream iss = null;
+ IceInternal.BasicStream os = null;
+
+ if(_reference.getInstance().cacheMessageBuffers() > 0)
+ {
+ lock(this)
+ {
+ if(_streamCache != null && _streamCache.Count > 0)
+ {
+ haveEntry = true;
+ iss = _streamCache.First.Value.iss;
+ os = _streamCache.First.Value.os;
+
+ _streamCache.RemoveFirst();
+ }
+ }
+ }
+ if(!haveEntry)
+ {
+ return new IceInternal.TwowayOutgoingAsync<T>(this, operation, cb, cookie);
+ }
+ else
+ {
+ return new IceInternal.TwowayOutgoingAsync<T>(this, operation, cb, cookie, iss, os);
+ }
+ }
+
+ protected IceInternal.OnewayOutgoingAsync<T>
+ getOnewayOutgoingAsync<T>(string operation, IceInternal.ProxyOnewayCallback<T> cb,
+ object cookie) {
+ bool haveEntry = false;
+ IceInternal.BasicStream iss = null;
+ IceInternal.BasicStream os = null;
+
+ if(_reference.getInstance().cacheMessageBuffers() > 0)
+ {
+ lock(this)
+ {
+ if(_streamCache != null && _streamCache.Count > 0)
+ {
+ haveEntry = true;
+ iss = _streamCache.First.Value.iss;
+ os = _streamCache.First.Value.os;
+ _streamCache.RemoveFirst();
+ }
+ }
+ }
+ if(!haveEntry)
+ {
+ return new IceInternal.OnewayOutgoingAsync<T>(this, operation, cb, cookie);
+ }
+ else
+ {
+ return new IceInternal.OnewayOutgoingAsync<T>(this, operation, cb, cookie, iss, os);
+ }
+ }
+
+ public void
+ cacheMessageBuffers(IceInternal.BasicStream iss, IceInternal.BasicStream os)
+ {
+ lock(this)
+ {
+ if(_streamCache == null)
+ {
+ _streamCache = new LinkedList<StreamCacheEntry>();
+ }
+ StreamCacheEntry cacheEntry;
+ cacheEntry.iss = iss;
+ cacheEntry.os = os;
+ _streamCache.AddLast(cacheEntry);
+ }
+ }
+
+ private void ice_isA_completed__(AsyncResult r__, Callback_Object_ice_isA cb__, Ice.ExceptionCallback excb__)
+ {
+ bool ret__;
+ try
+ {
+ ret__ = end_ice_isA(r__);
+ }
+ catch(Ice.Exception ex__)
+ {
+ if(excb__ != null)
+ {
+ excb__(ex__);
+ }
+ return;
+ }
+ if(cb__ != null)
+ {
+ cb__(ret__);
+ }
+ }
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ public void ice_ping()
+ {
+ ice_ping(null, false);
+ }
+
+ /// <summary>
+ /// Tests whether the target object of this proxy can be reached.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ public void ice_ping(Dictionary<string, string> context__)
+ {
+ ice_ping(context__, true);
+ }
+
+ private void ice_ping(Dictionary<string, string> context__, bool explicitCtx__)
+ {
+ end_ice_ping(begin_ice_ping(context__, explicitCtx__, true, null, null));
+ }
+
+ public AsyncResult<Callback_Object_ice_ping> begin_ice_ping()
+ {
+ return begin_ice_ping(null, false, false, null, null);
+ }
+
+ public AsyncResult<Callback_Object_ice_ping> begin_ice_ping(Dictionary<string, string> context__)
+ {
+ return begin_ice_ping(context__, true, false, null, null);
+ }
+
+ public AsyncResult begin_ice_ping(AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_ping(null, false, false, cb__, cookie__);
+ }
+
+ public AsyncResult begin_ice_ping(Dictionary<string, string> context__, AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_ping(null, false, false, cb__, cookie__);
+ }
+
+ internal const string __ice_ping_name = "ice_ping";
+
+ public void end_ice_ping(AsyncResult r__)
+ {
+ end__(r__, __ice_ping_name);
+ }
+
+ private AsyncResult<Callback_Object_ice_ping> begin_ice_ping(Dictionary<string, string> context__,
+ bool explicitCtx__,
+ bool synchronous__,
+ Ice.AsyncCallback cb__,
+ object cookie__)
+ {
+ IceInternal.OnewayOutgoingAsync<Callback_Object_ice_ping> result__ =
+ getOnewayOutgoingAsync<Callback_Object_ice_ping>(__ice_ping_name, ice_ping_completed__, cookie__);
+ if(cb__ != null)
+ {
+ result__.whenCompletedWithAsyncCallback(cb__);
+ }
+
+ try
+ {
+ result__.prepare(__ice_ping_name, OperationMode.Nonmutating, context__, explicitCtx__, synchronous__);
+ result__.writeEmptyParams();
+ result__.invoke();
+ }
+ catch(Ice.Exception ex__)
+ {
+ result__.abort(ex__);
+ }
+ return result__;
+ }
+
+ private void ice_ping_completed__(Callback_Object_ice_ping cb)
+ {
+ if(cb != null)
+ {
+ cb();
+ }
+ }
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <returns>The Slice type IDs of the interfaces supported by the target object, in base-to-derived
+ /// order. The first element of the returned array is always ::Ice::Object.</returns>
+ public string[] ice_ids()
+ {
+ return ice_ids(null, false);
+ }
+
+ /// <summary>
+ /// Returns the Slice type IDs of the interfaces supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>The Slice type IDs of the interfaces supported by the target object, in base-to-derived
+ /// order. The first element of the returned array is always ::Ice::Object.</returns>
+ public string[] ice_ids(Dictionary<string, string> context__)
+ {
+ return ice_ids(context__, true);
+ }
+
+ private string[] ice_ids(Dictionary<string, string> context__, bool explicitCtx__)
+ {
+
+ checkTwowayOnly__(__ice_ids_name);
+ return end_ice_ids(begin_ice_ids(context__, explicitCtx__, true, null, null));
+ }
+
+ public AsyncResult<Callback_Object_ice_ids> begin_ice_ids()
+ {
+ return begin_ice_ids(null, false, false, null, null);
+ }
+
+ public AsyncResult<Callback_Object_ice_ids> begin_ice_ids(Dictionary<string, string> context__)
+ {
+ return begin_ice_ids(context__, true, false, null, null);
+ }
+
+ public AsyncResult begin_ice_ids(AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_ids(null, false, false, cb__, cookie__);
+ }
+
+ public AsyncResult begin_ice_ids(Dictionary<string, string> context__, AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_ids(null, false, false, cb__, cookie__);
+ }
+
+ internal const string __ice_ids_name = "ice_ids";
+
+ public string[] end_ice_ids(AsyncResult r__)
+ {
+ IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_ids_name);
+ try
+ {
+ if(!outAsync__.wait())
+ {
+ try
+ {
+ outAsync__.throwUserException();
+ }
+ catch(Ice.UserException ex__)
+ {
+ throw new Ice.UnknownUserException(ex__.ice_name(), ex__);
+ }
+ }
+ string[] ret__;
+ IceInternal.BasicStream is__ = outAsync__.startReadParams();
+ ret__ = is__.readStringSeq();
+ outAsync__.endReadParams();
+ return ret__;
+ }
+ finally
+ {
+ if(outAsync__ != null)
+ {
+ outAsync__.cacheMessageBuffers();
+ }
+ }
+ }
+
+ private AsyncResult<Callback_Object_ice_ids> begin_ice_ids(Dictionary<string, string> context__,
+ bool explicitCtx__,
+ bool synchronous__,
+ Ice.AsyncCallback cb__,
+ object cookie__)
+ {
+ checkAsyncTwowayOnly__(__ice_ids_name);
+
+ IceInternal.TwowayOutgoingAsync<Callback_Object_ice_ids> result__ =
+ getTwowayOutgoingAsync<Callback_Object_ice_ids>(__ice_ids_name, ice_ids_completed__, cookie__);
+ if(cb__ != null)
+ {
+ result__.whenCompletedWithAsyncCallback(cb__);
+ }
+
+ try
+ {
+ result__.prepare(__ice_ids_name, OperationMode.Nonmutating, context__, explicitCtx__, synchronous__);
+ result__.writeEmptyParams();
+ result__.invoke();
+ }
+ catch(Ice.Exception ex__)
+ {
+ result__.abort(ex__);
+ }
+ return result__;
+ }
+
+ private void ice_ids_completed__(AsyncResult r__, Callback_Object_ice_ids cb__, Ice.ExceptionCallback excb__)
+ {
+ string[] ret__;
+ try
+ {
+ ret__ = end_ice_ids(r__);
+ }
+ catch(Ice.Exception ex__)
+ {
+ if(excb__ != null)
+ {
+ excb__(ex__);
+ }
+ return;
+ }
+ if(cb__ != null)
+ {
+ cb__(ret__);
+ }
+ }
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <returns>The Slice type ID of the most-derived interface.</returns>
+ public string ice_id()
+ {
+ return ice_id(null, false);
+ }
+
+ /// <summary>
+ /// Returns the Slice type ID of the most-derived interface supported by the target object of this proxy.
+ /// </summary>
+ /// <param name="context__">The context dictionary for the invocation.</param>
+ /// <returns>The Slice type ID of the most-derived interface.</returns>
+ public string ice_id(Dictionary<string, string> context__)
+ {
+ return ice_id(context__, true);
+ }
+
+ private string ice_id(Dictionary<string, string> context__, bool explicitCtx__)
+ {
+ checkTwowayOnly__(__ice_id_name);
+ return end_ice_id(begin_ice_id(context__, explicitCtx__, true, null, null));
+ }
+
+ public AsyncResult<Callback_Object_ice_id> begin_ice_id()
+ {
+ return begin_ice_id(null, false, false, null, null);
+ }
+
+ public AsyncResult<Callback_Object_ice_id> begin_ice_id(Dictionary<string, string> context__)
+ {
+ return begin_ice_id(context__, true, false, null, null);
+ }
+
+ public AsyncResult begin_ice_id(AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_id(null, false, false, cb__, cookie__);
+ }
+
+ public AsyncResult begin_ice_id(Dictionary<string, string> context__, AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_id(null, false, false, cb__, cookie__);
+ }
+
+ internal const string __ice_id_name = "ice_id";
+
+ public string end_ice_id(AsyncResult r__)
+ {
+ IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_id_name);
+ try
+ {
+ if(!outAsync__.wait())
+ {
+ try
+ {
+ outAsync__.throwUserException();
+ }
+ catch(Ice.UserException ex__)
+ {
+ throw new Ice.UnknownUserException(ex__.ice_name(), ex__);
+ }
+ }
+ string ret__;
+ IceInternal.BasicStream is__ = outAsync__.startReadParams();
+ ret__ = is__.readString();
+ outAsync__.endReadParams();
+ return ret__;
+ }
+ finally
+ {
+ if(outAsync__ != null)
+ {
+ outAsync__.cacheMessageBuffers();
+ }
+ }
+ }
+
+ private AsyncResult<Callback_Object_ice_id> begin_ice_id(Dictionary<string, string> context__,
+ bool explicitCtx__,
+ bool synchronous__,
+ Ice.AsyncCallback cb__,
+ object cookie__)
+ {
+ checkAsyncTwowayOnly__(__ice_id_name);
+
+ IceInternal.TwowayOutgoingAsync<Callback_Object_ice_id> result__ =
+ getTwowayOutgoingAsync<Callback_Object_ice_id>(__ice_id_name, ice_id_completed__, cookie__);
+ if(cb__ != null)
+ {
+ result__.whenCompletedWithAsyncCallback(cb__);
+ }
+
+ try
+ {
+ result__.prepare(__ice_id_name, OperationMode.Nonmutating, context__, explicitCtx__, synchronous__);
+ result__.writeEmptyParams();
+ result__.invoke();
+ }
+ catch(Ice.Exception ex__)
+ {
+ result__.abort(ex__);
+ }
+ return result__;
+ }
+
+ private void ice_id_completed__(AsyncResult r__, Callback_Object_ice_id cb__, Ice.ExceptionCallback excb__)
+ {
+ string ret__;
+ try
+ {
+ ret__ = end_ice_id(r__);
+ }
+ catch(Ice.Exception ex__)
+ {
+ if(excb__ != null)
+ {
+ excb__(ex__);
+ }
+ return;
+ }
+ if(cb__ != null)
+ {
+ cb__(ret__);
+ }
+ }
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <param name="outEncaps">The encoded out-paramaters and return value
+ /// for the operation. The return value follows any out-parameters.</param>
+ /// <returns>If the operation completed successfully, the return value
+ /// is true. If the operation raises a user exception,
+ /// the return value is false; in this case, outEncaps
+ /// contains the encoded user exception. If the operation raises a run-time exception,
+ /// it throws it directly.</returns>
+ public bool ice_invoke(string operation, OperationMode mode, byte[] inEncaps, out byte[] outEncaps)
+ {
+ return ice_invoke(operation, mode, inEncaps, out outEncaps, null, false);
+ }
+
+ /// <summary>
+ /// Invokes an operation dynamically.
+ /// </summary>
+ /// <param name="operation">The name of the operation to invoke.</param>
+ /// <param name="mode">The operation mode (normal or idempotent).</param>
+ /// <param name="inEncaps">The encoded in-parameters for the operation.</param>
+ /// <param name="outEncaps">The encoded out-paramaters and return value
+ /// for the operation. The return value follows any out-parameters.</param>
+ /// <param name="context">The context dictionary for the invocation.</param>
+ /// <returns>If the operation completed successfully, the return value
+ /// is true. If the operation raises a user exception,
+ /// the return value is false; in this case, outEncaps
+ /// contains the encoded user exception. If the operation raises a run-time exception,
+ /// it throws it directly.</returns>
+ public bool ice_invoke(string operation, OperationMode mode, byte[] inEncaps, out byte[] outEncaps,
+ Dictionary<string, string> context)
+ {
+ return ice_invoke(operation, mode, inEncaps, out outEncaps, context, true);
+ }
+
+ private bool ice_invoke(string operation, OperationMode mode, byte[] inEncaps, out byte[] outEncaps,
+ Dictionary<string, string> context, bool explicitCtx)
+ {
+ return end_ice_invoke(out outEncaps, begin_ice_invoke(operation, mode, inEncaps, context, explicitCtx, true, null, null));
+ }
+
+ public AsyncResult<Callback_Object_ice_invoke> begin_ice_invoke(string operation,
+ OperationMode mode,
+ byte[] inEncaps)
+ {
+ return begin_ice_invoke(operation, mode, inEncaps, null, false, false, null, null);
+ }
+
+ public AsyncResult<Callback_Object_ice_invoke> begin_ice_invoke(string operation,
+ OperationMode mode,
+ byte[] inEncaps,
+ Dictionary<string, string> context__)
+ {
+ return begin_ice_invoke(operation, mode, inEncaps, context__, true, false, null, null);
+ }
+
+ public AsyncResult begin_ice_invoke(string operation, OperationMode mode, byte[] inEncaps, AsyncCallback cb__,
+ object cookie__)
+ {
+ return begin_ice_invoke(operation, mode, inEncaps, null, false, false, cb__, cookie__);
+ }
+
+ public AsyncResult begin_ice_invoke(string operation, OperationMode mode, byte[] inEncaps,
+ Dictionary<string, string> context__, AsyncCallback cb__, object cookie__)
+ {
+ return begin_ice_invoke(operation, mode, inEncaps, null, false, false, cb__, cookie__);
+ }
+
+ internal const string __ice_invoke_name = "ice_invoke";
+
+ public bool end_ice_invoke(out byte[] outEncaps, AsyncResult r__)
+ {
+ IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_invoke_name);
+ try
+ {
+ bool ok = outAsync__.wait();
+ if(_reference.getMode() == IceInternal.Reference.Mode.ModeTwoway)
+ {
+ outEncaps = outAsync__.readParamEncaps();
+ }
+ else
+ {
+ outEncaps = null; // Satisfy compiler
+ }
+ return ok;
+ }
+ finally
+ {
+ if(outAsync__ != null)
+ {
+ outAsync__.cacheMessageBuffers();
+ }
+ }
+
+ }
+
+ private AsyncResult<Callback_Object_ice_invoke> begin_ice_invoke(string operation,
+ OperationMode mode,
+ byte[] inEncaps,
+ Dictionary<string, string> context__,
+ bool explicitCtx__,
+ bool synchronous__,
+ Ice.AsyncCallback cb__,
+ object cookie__)
+ {
+ IceInternal.TwowayOutgoingAsync<Callback_Object_ice_invoke> result__ =
+ getTwowayOutgoingAsync<Callback_Object_ice_invoke>(__ice_invoke_name, ice_invoke_completed__, cookie__);
+ if(cb__ != null)
+ {
+ result__.whenCompletedWithAsyncCallback(cb__);
+ }
+
+ try
+ {
+ result__.prepare(operation, mode, context__, explicitCtx__, synchronous__);
+ result__.writeParamEncaps(inEncaps);
+ result__.invoke();
+ }
+ catch(Ice.Exception ex__)
+ {
+ result__.abort(ex__);
+ }
+ return result__;
+ }
+
+ private void ice_invoke_completed__(AsyncResult r__,
+ Callback_Object_ice_invoke cb__,
+ Ice.ExceptionCallback excb__)
+ {
+ byte[] outEncaps;
+ bool ret__;
+ try
+ {
+ ret__ = end_ice_invoke(out outEncaps, r__);
+ }
+ catch(Ice.Exception ex__)
+ {
+ if(excb__ != null)
+ {
+ excb__(ex__);
+ }
+ return;
+ }
+ if(cb__ != null)
+ {
+ cb__(ret__, outEncaps);
+ }
+ }
+
+ /// <summary>
+ /// Returns the identity embedded in this proxy.
+ /// <returns>The identity of the target object.</returns>
+ /// </summary>
+ public Identity ice_getIdentity()
+ {
+ return (Identity)_reference.getIdentity().Clone();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the per-proxy context.
+ /// <param name="newIdentity">The identity for the new proxy.</param>
+ /// <returns>The proxy with the new identity.</returns>
+ /// </summary>
+ public ObjectPrx ice_identity(Identity newIdentity)
+ {
+ if(newIdentity.name.Length == 0)
+ {
+ throw new IllegalIdentityException();
+ }
+ if(newIdentity.Equals(_reference.getIdentity()))
+ {
+ return this;
+ }
+ else
+ {
+ ObjectPrxHelperBase proxy = new ObjectPrxHelperBase();
+ proxy.setup(_reference.changeIdentity(newIdentity));
+ return proxy;
+ }
+ }
+
+ /// <summary>
+ /// Returns the per-proxy context for this proxy.
+ /// </summary>
+ /// <returns>The per-proxy context. If the proxy does not have a per-proxy (implicit) context, the return value
+ /// is null.</returns>
+ public Dictionary<string, string> ice_getContext()
+ {
+ return new Dictionary<string, string>(_reference.getContext());
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the per-proxy context.
+ /// </summary>
+ /// <param name="newContext">The context for the new proxy.</param>
+ /// <returns>The proxy with the new per-proxy context.</returns>
+ public ObjectPrx ice_context(Dictionary<string, string> newContext)
+ {
+ return newInstance(_reference.changeContext(newContext));
+ }
+
+ /// <summary>
+ /// Returns the facet for this proxy.
+ /// </summary>
+ /// <returns>The facet for this proxy. If the proxy uses the default facet, the return value is the
+ /// empty string.</returns>
+ public string ice_getFacet()
+ {
+ return _reference.getFacet();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the facet.
+ /// </summary>
+ /// <param name="newFacet">The facet for the new proxy.</param>
+ /// <returns>The proxy with the new facet.</returns>
+ public ObjectPrx ice_facet(string newFacet)
+ {
+ if(newFacet == null)
+ {
+ newFacet = "";
+ }
+
+ if(newFacet.Equals(_reference.getFacet()))
+ {
+ return this;
+ }
+ else
+ {
+ ObjectPrxHelperBase proxy = new ObjectPrxHelperBase();
+ proxy.setup(_reference.changeFacet(newFacet));
+ return proxy;
+ }
+ }
+
+ /// <summary>
+ /// Returns the adapter ID for this proxy.
+ /// </summary>
+ /// <returns>The adapter ID. If the proxy does not have an adapter ID, the return value is the
+ /// empty string.</returns>
+ public string ice_getAdapterId()
+ {
+ return _reference.getAdapterId();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the adapter ID.
+ /// </summary>
+ /// <param name="newAdapterId">The adapter ID for the new proxy.</param>
+ /// <returns>The proxy with the new adapter ID.</returns>
+ public ObjectPrx ice_adapterId(string newAdapterId)
+ {
+ if(newAdapterId == null)
+ {
+ newAdapterId = "";
+ }
+
+ if(newAdapterId.Equals(_reference.getAdapterId()))
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeAdapterId(newAdapterId));
+ }
+ }
+
+ /// <summary>
+ /// Returns the endpoints used by this proxy.
+ /// </summary>
+ /// <returns>The endpoints used by this proxy.</returns>
+ public Endpoint[] ice_getEndpoints()
+ {
+ return (Endpoint[])_reference.getEndpoints().Clone();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the endpoints.
+ /// </summary>
+ /// <param name="newEndpoints">The endpoints for the new proxy.</param>
+ /// <returns>The proxy with the new endpoints.</returns>
+ public ObjectPrx ice_endpoints(Endpoint[] newEndpoints)
+ {
+ if(Arrays.Equals(newEndpoints, _reference.getEndpoints()))
+ {
+ return this;
+ }
+ else
+ {
+ IceInternal.EndpointI[] endpts = new IceInternal.EndpointI[newEndpoints.Length];
+ for(int i = 0; i < newEndpoints.Length; ++i)
+ {
+ endpts[i] = (IceInternal.EndpointI)newEndpoints[i];
+ }
+ return newInstance(_reference.changeEndpoints(endpts));
+ }
+ }
+
+ /// <summary>
+ /// Returns the locator cache timeout of this proxy.
+ /// </summary>
+ /// <returns>The locator cache timeout value (in seconds).</returns>
+ public int ice_getLocatorCacheTimeout()
+ {
+ return _reference.getLocatorCacheTimeout();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the locator cache timeout.
+ /// </summary>
+ /// <param name="newTimeout">The new locator cache timeout (in seconds).</param>
+ public ObjectPrx ice_locatorCacheTimeout(int newTimeout)
+ {
+ if(newTimeout < -1)
+ {
+ throw new System.ArgumentException("invalid value passed to ice_locatorCacheTimeout: " + newTimeout);
+ }
+ if(newTimeout == _reference.getLocatorCacheTimeout())
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeLocatorCacheTimeout(newTimeout));
+ }
+ }
+
+ /// <summary>
+ /// Returns the invocation timeout of this proxy.
+ /// </summary>
+ /// <returns>The invocation timeout value (in seconds).</returns>
+ public int ice_getInvocationTimeout()
+ {
+ return _reference.getInvocationTimeout();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the invocation timeout.
+ /// </summary>
+ /// <param name="newTimeout">The new invocation timeout (in seconds).</param>
+ public ObjectPrx ice_invocationTimeout(int newTimeout)
+ {
+ if(newTimeout < 1 && newTimeout != -1 && newTimeout != -2)
+ {
+ throw new System.ArgumentException("invalid value passed to ice_invocationTimeout: " + newTimeout);
+ }
+ if(newTimeout == _reference.getInvocationTimeout())
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeInvocationTimeout(newTimeout));
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy caches connections.
+ /// </summary>
+ /// <returns>True if this proxy caches connections; false, otherwise.</returns>
+ public bool ice_isConnectionCached()
+ {
+ return _reference.getCacheConnection();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for connection caching.
+ /// </summary>
+ /// <param name="newCache">True if the new proxy should cache connections; false, otherwise.</param>
+ /// <returns>The new proxy with the specified caching policy.</returns>
+ public ObjectPrx ice_connectionCached(bool newCache)
+ {
+ if(newCache == _reference.getCacheConnection())
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeCacheConnection(newCache));
+ }
+ }
+
+ /// <summary>
+ /// Returns how this proxy selects endpoints (randomly or ordered).
+ /// </summary>
+ /// <returns>The endpoint selection policy.</returns>
+ public EndpointSelectionType ice_getEndpointSelection()
+ {
+ return _reference.getEndpointSelection();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the endpoint selection policy.
+ /// </summary>
+ /// <param name="newType">The new endpoint selection policy.</param>
+ /// <returns>The new proxy with the specified endpoint selection policy.</returns>
+ public ObjectPrx ice_endpointSelection(EndpointSelectionType newType)
+ {
+ if(newType == _reference.getEndpointSelection())
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeEndpointSelection(newType));
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy communicates only via secure endpoints.
+ /// </summary>
+ /// <returns>True if this proxy communicates only vi secure endpoints; false, otherwise.</returns>
+ public bool ice_isSecure()
+ {
+ return _reference.getSecure();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for how it selects endpoints.
+ /// </summary>
+ /// <param name="b"> If b is true, only endpoints that use a secure transport are
+ /// used by the new proxy. If b is false, the returned proxy uses both secure and insecure
+ /// endpoints.</param>
+ /// <returns>The new proxy with the specified selection policy.</returns>
+ public ObjectPrx ice_secure(bool b)
+ {
+ if(b == _reference.getSecure())
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeSecure(b));
+ }
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the encoding used to marshal
+ /// parameters.
+ /// </summary>
+ /// <param name="e">The encoding version to use to marshal requests parameters.</param>
+ /// <returns>The new proxy with the specified encoding version.</returns>
+ public ObjectPrx ice_encodingVersion(Ice.EncodingVersion e)
+ {
+ if(e.Equals(_reference.getEncoding()))
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeEncoding(e));
+ }
+ }
+
+ /// <summary>Returns the encoding version used to marshal requests parameters.</summary>
+ /// <returns>The encoding version.</returns>
+ public Ice.EncodingVersion ice_getEncodingVersion()
+ {
+ return _reference.getEncoding();
+ }
+
+ /// <summary>
+ /// Returns whether this proxy prefers secure endpoints.
+ /// </summary>
+ /// <returns>True if the proxy always attempts to invoke via secure endpoints before it
+ /// attempts to use insecure endpoints; false, otherwise.</returns>
+ public bool ice_isPreferSecure()
+ {
+ return _reference.getPreferSecure();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for its endpoint selection policy.
+ /// </summary>
+ /// <param name="b">If b is true, the new proxy will use secure endpoints for invocations
+ /// and only use insecure endpoints if an invocation cannot be made via secure endpoints. If b is
+ /// false, the proxy prefers insecure endpoints to secure ones.</param>
+ /// <returns>The new proxy with the new endpoint selection policy.</returns>
+ public ObjectPrx ice_preferSecure(bool b)
+ {
+ if(b == _reference.getPreferSecure())
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changePreferSecure(b));
+ }
+ }
+
+ /// <summary>
+ /// Returns the router for this proxy.
+ /// </summary>
+ /// <returns>The router for the proxy. If no router is configured for the proxy, the return value
+ /// is null.</returns>
+ public Ice.RouterPrx ice_getRouter()
+ {
+ IceInternal.RouterInfo ri = _reference.getRouterInfo();
+ return ri != null ? ri.getRouter() : null;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the router.
+ /// </summary>
+ /// <param name="router">The router for the new proxy.</param>
+ /// <returns>The new proxy with the specified router.</returns>
+ public ObjectPrx ice_router(RouterPrx router)
+ {
+ IceInternal.Reference @ref = _reference.changeRouter(router);
+ if(@ref.Equals(_reference))
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(@ref);
+ }
+ }
+
+ /// <summary>
+ /// Returns the locator for this proxy.
+ /// </summary>
+ /// <returns>The locator for this proxy. If no locator is configured, the return value is null.</returns>
+ public Ice.LocatorPrx ice_getLocator()
+ {
+ IceInternal.LocatorInfo li = _reference.getLocatorInfo();
+ return li != null ? li.getLocator() : null;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for the locator.
+ /// </summary>
+ /// <param name="locator">The locator for the new proxy.</param>
+ /// <returns>The new proxy with the specified locator.</returns>
+ public ObjectPrx ice_locator(LocatorPrx locator)
+ {
+ IceInternal.Reference @ref = _reference.changeLocator(locator);
+ if(@ref.Equals(_reference))
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(@ref);
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy uses collocation optimization.
+ /// </summary>
+ /// <returns>True if the proxy uses collocation optimization; false, otherwise.</returns>
+ public bool ice_isCollocationOptimized()
+ {
+ return _reference.getCollocationOptimized();
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for collocation optimization.
+ /// </summary>
+ /// <param name="b">True if the new proxy enables collocation optimization; false, otherwise.</param>
+ /// <returns>The new proxy the specified collocation optimization.</returns>
+ public ObjectPrx ice_collocationOptimized(bool b)
+ {
+ if(b == _reference.getCollocationOptimized())
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeCollocationOptimized(b));
+ }
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses twoway invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses twoway invocations.</returns>
+ public ObjectPrx ice_twoway()
+ {
+ if(_reference.getMode() == IceInternal.Reference.Mode.ModeTwoway)
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeMode(IceInternal.Reference.Mode.ModeTwoway));
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy uses twoway invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses twoway invocations; false, otherwise.</returns>
+ public bool ice_isTwoway()
+ {
+ return _reference.getMode() == IceInternal.Reference.Mode.ModeTwoway;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses oneway invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses oneway invocations.</returns>
+ public ObjectPrx ice_oneway()
+ {
+ if(_reference.getMode() == IceInternal.Reference.Mode.ModeOneway)
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeMode(IceInternal.Reference.Mode.ModeOneway));
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy uses oneway invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses oneway invocations; false, otherwise.</returns>
+ public bool ice_isOneway()
+ {
+ return _reference.getMode() == IceInternal.Reference.Mode.ModeOneway;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses batch oneway invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses batch oneway invocations.</returns>
+ public ObjectPrx ice_batchOneway()
+ {
+ if(_reference.getMode() == IceInternal.Reference.Mode.ModeBatchOneway)
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeMode(IceInternal.Reference.Mode.ModeBatchOneway));
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy uses batch oneway invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses batch oneway invocations; false, otherwise.</returns>
+ public bool ice_isBatchOneway()
+ {
+ return _reference.getMode() == IceInternal.Reference.Mode.ModeBatchOneway;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses datagram invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses datagram invocations.</returns>
+ public ObjectPrx ice_datagram()
+ {
+ if(_reference.getMode() == IceInternal.Reference.Mode.ModeDatagram)
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeMode(IceInternal.Reference.Mode.ModeDatagram));
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy uses datagram invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses datagram invocations; false, otherwise.</returns>
+ public bool ice_isDatagram()
+ {
+ return _reference.getMode() == IceInternal.Reference.Mode.ModeDatagram;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, but uses batch datagram invocations.
+ /// </summary>
+ /// <returns>A new proxy that uses batch datagram invocations.</returns>
+ public ObjectPrx ice_batchDatagram()
+ {
+ if(_reference.getMode() == IceInternal.Reference.Mode.ModeBatchDatagram)
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(_reference.changeMode(IceInternal.Reference.Mode.ModeBatchDatagram));
+ }
+ }
+
+ /// <summary>
+ /// Returns whether this proxy uses batch datagram invocations.
+ /// </summary>
+ /// <returns>True if this proxy uses batch datagram invocations; false, otherwise.</returns>
+ public bool ice_isBatchDatagram()
+ {
+ return _reference.getMode() == IceInternal.Reference.Mode.ModeBatchDatagram;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for compression.
+ /// </summary>
+ /// <param name="co">True enables compression for the new proxy; false disables compression.</param>
+ /// <returns>A new proxy with the specified compression setting.</returns>
+ public ObjectPrx ice_compress(bool co)
+ {
+ IceInternal.Reference @ref = _reference.changeCompress(co);
+ if(@ref.Equals(_reference))
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(@ref);
+ }
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for its timeout setting.
+ /// </summary>
+ /// <param name="t">The timeout for the new proxy in milliseconds.</param>
+ /// <returns>A new proxy with the specified timeout.</returns>
+ public ObjectPrx ice_timeout(int t)
+ {
+ if(t < 1 && t != -1)
+ {
+ throw new System.ArgumentException("invalid value passed to ice_timeout: " + t);
+ }
+ IceInternal.Reference @ref = _reference.changeTimeout(t);
+ if(@ref.Equals(_reference))
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(@ref);
+ }
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to this proxy, except for its connection ID.
+ /// </summary>
+ /// <param name="connectionId">The connection ID for the new proxy. An empty string removes the
+ /// connection ID.</param>
+ /// <returns>A new proxy with the specified connection ID.</returns>
+ public ObjectPrx ice_connectionId(string connectionId)
+ {
+ IceInternal.Reference @ref = _reference.changeConnectionId(connectionId);
+ if(@ref.Equals(_reference))
+ {
+ return this;
+ }
+ else
+ {
+ return newInstance(@ref);
+ }
+ }
+
+ /// <summary>
+ /// Returns the connection id of this proxy.
+ /// </summary>
+ /// <returns>The connection id.</returns>
+ public string ice_getConnectionId()
+ {
+ return _reference.getConnectionId();
+ }
+
+ /// <summary>
+ /// Returns the Connection for this proxy. If the proxy does not yet have an established connection,
+ /// it first attempts to create a connection.
+ /// </summary>
+ /// <returns>The Connection for this proxy.</returns>
+ /// <exception name="CollocationOptimizationException">If the proxy uses collocation optimization and denotes a
+ /// collocated object.</exception>
+ public Connection ice_getConnection()
+ {
+ return end_ice_getConnection(begin_ice_getConnection());
+ }
+
+ public AsyncResult<Callback_Object_ice_getConnection> begin_ice_getConnection()
+ {
+ return begin_ice_getConnectionInternal(null, null);
+ }
+
+ internal const string __ice_getConnection_name = "ice_getConnection";
+
+ public AsyncResult begin_ice_getConnection(Ice.AsyncCallback cb, object cookie)
+ {
+ return begin_ice_getConnectionInternal(cb, cookie);
+ }
+
+ public Connection end_ice_getConnection(Ice.AsyncResult r)
+ {
+ IceInternal.ProxyGetConnection outAsync =
+ IceInternal.ProxyGetConnection.check(r, this, __ice_getConnection_name);
+ outAsync.wait();
+ return ice_getCachedConnection();
+ }
+
+ private AsyncResult<Callback_Object_ice_getConnection> begin_ice_getConnectionInternal(Ice.AsyncCallback cb,
+ object cookie)
+ {
+ IceInternal.ProxyGetConnection result = new IceInternal.ProxyGetConnection(this,
+ __ice_getConnection_name,
+ ice_getConnection_completed__,
+ cookie);
+ if(cb != null)
+ {
+ result.whenCompletedWithAsyncCallback(cb);
+ }
+ try
+ {
+ result.invoke();
+ }
+ catch(Ice.Exception ex)
+ {
+ result.abort(ex);
+ }
+ return result;
+ }
+
+
+
+ private void ice_getConnection_completed__(AsyncResult r,
+ Callback_Object_ice_getConnection cb,
+ Ice.ExceptionCallback excb)
+ {
+ Connection ret;
+ try
+ {
+ ret = end_ice_getConnection(r);
+ }
+ catch(Ice.Exception ex)
+ {
+ if(excb != null)
+ {
+ excb(ex);
+ }
+ return;
+ }
+ if(cb != null)
+ {
+ cb(ret);
+ }
+ }
+
+ /// <summary>
+ /// Returns the cached Connection for this proxy. If the proxy does not yet have an established
+ /// connection, it does not attempt to create a connection.
+ /// </summary>
+ /// <returns>The cached Connection for this proxy (null if the proxy does not have
+ /// an established connection).</returns>
+ /// <exception name="CollocationOptimizationException">If the proxy uses collocation optimization and denotes a
+ /// collocated object.</exception>
+ public Connection ice_getCachedConnection()
+ {
+ IceInternal.RequestHandler handler;
+ lock(this)
+ {
+ handler = _requestHandler;
+ }
+
+ if(handler != null)
+ {
+ try
+ {
+ return handler.getConnection();
+ }
+ catch(LocalException)
+ {
+ }
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Flushes any pending batched requests for this communicator. The call blocks until the flush is complete.
+ /// </summary>
+ public void ice_flushBatchRequests()
+ {
+ end_ice_flushBatchRequests(begin_ice_flushBatchRequests());
+ }
+
+ internal const string __ice_flushBatchRequests_name = "ice_flushBatchRequests";
+
+ public AsyncResult begin_ice_flushBatchRequests()
+ {
+ return begin_ice_flushBatchRequests(null, null);
+ }
+
+ public AsyncResult begin_ice_flushBatchRequests(Ice.AsyncCallback cb, object cookie)
+ {
+ IceInternal.ProxyFlushBatch result = new IceInternal.ProxyFlushBatch(this,
+ __ice_flushBatchRequests_name,
+ cookie);
+ if(cb != null)
+ {
+ result.whenCompletedWithAsyncCallback(cb);
+ }
+ try
+ {
+ result.invoke();
+ }
+ catch(Ice.Exception ex)
+ {
+ result.abort(ex);
+ }
+ return result;
+ }
+
+ public void end_ice_flushBatchRequests(Ice.AsyncResult r)
+ {
+ IceInternal.ProxyFlushBatch outAsync =
+ IceInternal.ProxyFlushBatch.check(r, this, __ice_flushBatchRequests_name);
+ outAsync.wait();
+ }
+
+ /// <summary>
+ /// Returns whether this proxy equals the passed object. Two proxies are equal if they are equal in all
+ /// respects, that is, if their object identity, endpoints timeout settings, and so on are all equal.
+ /// </summary>
+ /// <param name="r">The object to compare this proxy with.</param>
+ /// <returns>True if this proxy is equal to r; false, otherwise.</returns>
+ public override bool Equals(object r)
+ {
+ ObjectPrxHelperBase rhs = r as ObjectPrxHelperBase;
+ return object.ReferenceEquals(rhs, null) ? false : _reference.Equals(rhs._reference);
+ }
+
+ /// <summary>
+ /// Returns whether two proxies are equal. Two proxies are equal if they are equal in all
+ /// respects, that is, if their object identity, endpoints timeout settings, and so on are all equal.
+ /// </summary>
+ /// <param name="lhs">A proxy to compare with the proxy rhs.</param>
+ /// <param name="rhs">A proxy to compare with the proxy lhs.</param>
+ /// <returns>True if the proxies are equal; false, otherwise.</returns>
+ public static bool Equals(ObjectPrxHelperBase lhs, ObjectPrxHelperBase rhs)
+ {
+ return object.ReferenceEquals(lhs, null) ? object.ReferenceEquals(rhs, null) : lhs.Equals(rhs);
+ }
+
+ /// <summary>
+ /// Returns whether two proxies are equal. Two proxies are equal if they are equal in all
+ /// respects, that is, if their object identity, endpoints timeout settings, and so on are all equal.
+ /// </summary>
+ /// <param name="lhs">A proxy to compare with the proxy rhs.</param>
+ /// <param name="rhs">A proxy to compare with the proxy lhs.</param>
+ /// <returns>True if the proxies are equal; false, otherwise.</returns>
+ public static bool operator==(ObjectPrxHelperBase lhs, ObjectPrxHelperBase rhs)
+ {
+ return Equals(lhs, rhs);
+ }
+
+ /// <summary>
+ /// Returns whether two proxies are not equal. Two proxies are equal if they are equal in all
+ /// respects, that is, if their object identity, endpoints timeout settings, and so on are all equal.
+ /// </summary>
+ /// <param name="lhs">A proxy to compare with the proxy rhs.</param>
+ /// <param name="rhs">A proxy to compare with the proxy lhs.</param>
+ /// <returns>True if the proxies are not equal; false, otherwise.</returns>
+ public static bool operator!=(ObjectPrxHelperBase lhs, ObjectPrxHelperBase rhs)
+ {
+ return !Equals(lhs, rhs);
+ }
+
+ public IceInternal.Reference reference__()
+ {
+ return _reference;
+ }
+
+ public void copyFrom__(ObjectPrx from)
+ {
+ lock(from)
+ {
+ ObjectPrxHelperBase h = (ObjectPrxHelperBase)from;
+ _reference = h._reference;
+ _requestHandler = h._requestHandler;
+ }
+ }
+
+ public int handleException__(Exception ex, IceInternal.RequestHandler handler, OperationMode mode, bool sent,
+ ref int cnt)
+ {
+ updateRequestHandler__(handler, null); // Clear the request handler
+
+ //
+ // We only retry local exception, system exceptions aren't retried.
+ //
+ // A CloseConnectionException indicates graceful server shutdown, and is therefore
+ // always repeatable without violating "at-most-once". That's because by sending a
+ // close connection message, the server guarantees that all outstanding requests
+ // can safely be repeated.
+ //
+ // An ObjectNotExistException can always be retried as well without violating
+ // "at-most-once" (see the implementation of the checkRetryAfterException method
+ // of the ProxyFactory class for the reasons why it can be useful).
+ //
+ // If the request didn't get sent or if it's non-mutating or idempotent it can
+ // also always be retried if the retry count isn't reached.
+ //
+ if(ex is LocalException && (!sent ||
+ mode == OperationMode.Nonmutating || mode == OperationMode.Idempotent ||
+ ex is CloseConnectionException ||
+ ex is ObjectNotExistException))
+ {
+ try
+ {
+ return _reference.getInstance().proxyFactory().checkRetryAfterException((LocalException)ex,
+ _reference,
+ ref cnt);
+ }
+ catch(CommunicatorDestroyedException)
+ {
+ //
+ // The communicator is already destroyed, so we cannot retry.
+ //
+ throw ex;
+ }
+ }
+ else
+ {
+ throw ex; // Retry could break at-most-once semantics, don't retry.
+ }
+ }
+
+ public void checkTwowayOnly__(string name)
+ {
+ //
+ // No mutex lock necessary, there is nothing mutable in this
+ // operation.
+ //
+
+ if(!ice_isTwoway())
+ {
+ TwowayOnlyException ex = new TwowayOnlyException();
+ ex.operation = name;
+ throw ex;
+ }
+ }
+
+ public void checkAsyncTwowayOnly__(string name)
+ {
+ //
+ // No mutex lock necessary, there is nothing mutable in this
+ // operation.
+ //
+
+ if(!ice_isTwoway())
+ {
+ throw new System.ArgumentException("`" + name + "' can only be called with a twoway proxy");
+ }
+ }
+
+ public void end__(AsyncResult r, string operation)
+ {
+ IceInternal.ProxyOutgoingAsyncBase result = IceInternal.ProxyOutgoingAsyncBase.check(r, this, operation);
+ try
+ {
+ bool ok = result.wait();
+ if(_reference.getMode() == IceInternal.Reference.Mode.ModeTwoway)
+ {
+ IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)result;
+ if(!ok)
+ {
+ try
+ {
+ outAsync.throwUserException();
+ }
+ catch(Ice.UserException ex)
+ {
+ throw new Ice.UnknownUserException(ex.ice_name(), ex);
+ }
+ }
+ outAsync.readEmptyParams();
+ }
+ }
+ finally
+ {
+ if(result != null)
+ {
+ result.cacheMessageBuffers();
+ }
+ }
+ }
+
+ public IceInternal.RequestHandler getRequestHandler__()
+ {
+ if(_reference.getCacheConnection())
+ {
+ lock(this)
+ {
+ if(_requestHandler != null)
+ {
+ return _requestHandler;
+ }
+ }
+ }
+ return _reference.getRequestHandler(this);
+ }
+
+ public IceInternal.BatchRequestQueue
+ getBatchRequestQueue__()
+ {
+ lock(this)
+ {
+ if(_batchRequestQueue == null)
+ {
+ _batchRequestQueue = _reference.getBatchRequestQueue();
+ }
+ return _batchRequestQueue;
+ }
+ }
+
+ public IceInternal.RequestHandler
+ setRequestHandler__(IceInternal.RequestHandler handler)
+ {
+ if(_reference.getCacheConnection())
+ {
+ lock(this)
+ {
+ if(_requestHandler == null)
+ {
+ _requestHandler = handler;
+ }
+ return _requestHandler;
+ }
+ }
+ return handler;
+ }
+
+ public void updateRequestHandler__(IceInternal.RequestHandler previous, IceInternal.RequestHandler handler)
+ {
+ if(_reference.getCacheConnection() && previous != null)
+ {
+ lock(this)
+ {
+ if(_requestHandler != null && _requestHandler != handler)
+ {
+ //
+ // Update the request handler only if "previous" is the same
+ // as the current request handler. This is called after
+ // connection binding by the connect request handler. We only
+ // replace the request handler if the current handler is the
+ // connect request handler.
+ //
+ _requestHandler = _requestHandler.update(previous, handler);
+ }
+ }
+ }
+ }
+
+ //
+ // Only for use by IceInternal.ProxyFactory
+ //
+ public void setup(IceInternal.Reference @ref)
+ {
+ //
+ // No need to synchronize, as this operation is only called
+ // upon initial initialization.
+ //
+
+ Debug.Assert(_reference == null);
+ Debug.Assert(_requestHandler == null);
+
+ _reference = @ref;
+ }
+
+ private ObjectPrxHelperBase newInstance(IceInternal.Reference @ref)
+ {
+ ObjectPrxHelperBase proxy = (ObjectPrxHelperBase)Activator.CreateInstance(GetType());
+ proxy.setup(@ref);
+ return proxy;
+ }
+
+ private IceInternal.Reference _reference;
+ private IceInternal.RequestHandler _requestHandler;
+ private IceInternal.BatchRequestQueue _batchRequestQueue;
+ private struct StreamCacheEntry
+ {
+ public IceInternal.BasicStream iss;
+ public IceInternal.BasicStream os;
+ }
+
+ private LinkedList<StreamCacheEntry> _streamCache;
+ }
+
+ /// <summary>
+ /// Base class for all proxy helpers.
+ /// </summary>
+ public class ObjectPrxHelper : ObjectPrxHelperBase
+ {
+ /// <summary>
+ /// Casts a proxy to {@link ObjectPrx}. This call contacts
+ /// the server and will throw an Ice run-time exception if the target
+ /// object does not exist or the server cannot be reached.
+ /// </summary>
+ /// <param name="b">The proxy to cast to ObjectPrx.</param>
+ /// <returns>b.</returns>
+ public static ObjectPrx checkedCast(ObjectPrx b)
+ {
+ return b;
+ }
+
+ /// <summary>
+ /// Casts a proxy to {@link ObjectPrx}. This call contacts
+ /// the server and throws an Ice run-time exception if the target
+ /// object does not exist or the server cannot be reached.
+ /// </summary>
+ /// <param name="b">The proxy to cast to ObjectPrx.</param>
+ /// <param name="ctx">The Context map for the invocation.</param>
+ /// <returns>b.</returns>
+ public static ObjectPrx checkedCast(ObjectPrx b, Dictionary<string, string> ctx)
+ {
+ return b;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to the passed proxy, except
+ /// for its facet. This call contacts
+ /// the server and throws an Ice run-time exception if the target
+ /// object does not exist, the specified facet does not exist, or the server cannot be reached.
+ /// </summary>
+ /// <param name="b">The proxy to cast to ObjectPrx.</param>
+ /// <param name="f">The facet for the new proxy.</param>
+ /// <returns>The new proxy with the specified facet.</returns>
+ public static ObjectPrx checkedCast(ObjectPrx b, string f)
+ {
+ ObjectPrx d = null;
+ if(b != null)
+ {
+ try
+ {
+ ObjectPrx bb = b.ice_facet(f);
+ bool ok = bb.ice_isA("::Ice::Object");
+ Debug.Assert(ok);
+ ObjectPrxHelper h = new ObjectPrxHelper();
+ h.copyFrom__(bb);
+ d = h;
+ }
+ catch(Ice.FacetNotExistException)
+ {
+ }
+ }
+ return d;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to the passed proxy, except
+ /// for its facet. This call contacts
+ /// the server and throws an Ice run-time exception if the target
+ /// object does not exist, the specified facet does not exist, or the server cannot be reached.
+ /// </summary>
+ /// <param name="b">The proxy to cast to ObjectPrx.</param>
+ /// <param name="f">The facet for the new proxy.</param>
+ /// <param name="ctx">The Context map for the invocation.</param>
+ /// <returns>The new proxy with the specified facet.</returns>
+ public static ObjectPrx checkedCast(ObjectPrx b, string f, Dictionary<string, string> ctx)
+ {
+ ObjectPrx d = null;
+ if(b != null)
+ {
+ try
+ {
+ ObjectPrx bb = b.ice_facet(f);
+ bool ok = bb.ice_isA("::Ice::Object", ctx);
+ Debug.Assert(ok);
+ ObjectPrxHelper h = new ObjectPrxHelper();
+ h.copyFrom__(bb);
+ d = h;
+ }
+ catch(Ice.FacetNotExistException)
+ {
+ }
+ }
+ return d;
+ }
+
+ /// <summary>
+ /// Casts a proxy to {@link ObjectPrx}. This call does
+ /// not contact the server and always succeeds.
+ /// </summary>
+ /// <param name="b">The proxy to cast to ObjectPrx.</param>
+ /// <returns>b.</returns>
+ public static ObjectPrx uncheckedCast(ObjectPrx b)
+ {
+ return b;
+ }
+
+ /// <summary>
+ /// Creates a new proxy that is identical to the passed proxy, except
+ /// for its facet. This call does not contact the server and always succeeds.
+ /// </summary>
+ /// <param name="b">The proxy to cast to ObjectPrx.</param>
+ /// <param name="f">The facet for the new proxy.</param>
+ /// <returns>The new proxy with the specified facet.</returns>
+ public static ObjectPrx uncheckedCast(ObjectPrx b, string f)
+ {
+ ObjectPrx d = null;
+ if(b != null)
+ {
+ ObjectPrx bb = b.ice_facet(f);
+ ObjectPrxHelper h = new ObjectPrxHelper();
+ h.copyFrom__(bb);
+ d = h;
+ }
+ return d;
+ }
+
+
+ /// <summary>
+ /// Returns the Slice type id of the interface or class associated
+ /// with this proxy class.
+ /// </summary>
+ /// <returns>The type id, "::Ice::Object".</returns>
+ public static string ice_staticId()
+ {
+ return Ice.ObjectImpl.ice_staticId();
+ }
+ }
+}
diff --git a/csharp/src/Ice/ProxyFactory.cs b/csharp/src/Ice/ProxyFactory.cs
new file mode 100644
index 00000000000..b9d964ad03f
--- /dev/null
+++ b/csharp/src/Ice/ProxyFactory.cs
@@ -0,0 +1,299 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace IceInternal
+{
+ public sealed class ProxyFactory
+ {
+ public Ice.ObjectPrx stringToProxy(string str)
+ {
+ Reference r = instance_.referenceFactory().create(str, null);
+ return referenceToProxy(r);
+ }
+
+ public string proxyToString(Ice.ObjectPrx proxy)
+ {
+ if(proxy != null)
+ {
+ Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase) proxy;
+ return h.reference__().ToString();
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ public Ice.ObjectPrx propertyToProxy(string prefix)
+ {
+ string proxy = instance_.initializationData().properties.getProperty(prefix);
+ Reference r = instance_.referenceFactory().create(proxy, prefix);
+ return referenceToProxy(r);
+ }
+
+ public Dictionary<string, string>
+ proxyToProperty(Ice.ObjectPrx proxy, string prefix)
+ {
+ if(proxy != null)
+ {
+ Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase) proxy;
+ return h.reference__().toProperty(prefix);
+ }
+ else
+ {
+ return new Dictionary<string, string>();
+ }
+ }
+
+ public Ice.ObjectPrx streamToProxy(BasicStream s)
+ {
+ Ice.Identity ident = new Ice.Identity();
+ ident.read__(s);
+
+ Reference r = instance_.referenceFactory().create(ident, s);
+ return referenceToProxy(r);
+ }
+
+ public Ice.ObjectPrx referenceToProxy(Reference r)
+ {
+ if(r != null)
+ {
+ Ice.ObjectPrxHelperBase proxy = new Ice.ObjectPrxHelperBase();
+ proxy.setup(r);
+ return proxy;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void proxyToStream(Ice.ObjectPrx proxy, BasicStream s)
+ {
+ if(proxy != null)
+ {
+ Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase)proxy;
+ Reference r = h.reference__();
+ r.getIdentity().write__(s);
+ r.streamWrite(s);
+ }
+ else
+ {
+ Ice.Identity ident = new Ice.Identity();
+ ident.name = "";
+ ident.category = "";
+ ident.write__(s);
+ }
+ }
+
+ public int checkRetryAfterException(Ice.LocalException ex, Reference @ref, ref int cnt)
+ {
+ TraceLevels traceLevels = instance_.traceLevels();
+ Ice.Logger logger = instance_.initializationData().logger;
+
+ //
+ // We don't retry batch requests because the exception might have caused
+ // the all the requests batched with the connection to be aborted and we
+ // want the application to be notified.
+ //
+ if(@ref.getMode() == Reference.Mode.ModeBatchOneway || @ref.getMode() == Reference.Mode.ModeBatchDatagram)
+ {
+ throw ex;
+ }
+
+ Ice.ObjectNotExistException one = ex as Ice.ObjectNotExistException;
+ if(one != null)
+ {
+ if(@ref.getRouterInfo() != null && one.operation.Equals("ice_add_proxy"))
+ {
+ //
+ // If we have a router, an ObjectNotExistException with an
+ // operation name "ice_add_proxy" indicates to the client
+ // that the router isn't aware of the proxy (for example,
+ // because it was evicted by the router). In this case, we
+ // must *always* retry, so that the missing proxy is added
+ // to the router.
+ //
+
+ @ref.getRouterInfo().clearCache(@ref);
+
+ if(traceLevels.retry >= 1)
+ {
+ string s = "retrying operation call to add proxy to router\n" + ex;
+ logger.trace(traceLevels.retryCat, s);
+ }
+ return 0; // We must always retry, so we don't look at the retry count.
+ }
+ else if(@ref.isIndirect())
+ {
+ //
+ // We retry ObjectNotExistException if the reference is
+ // indirect.
+ //
+
+ if(@ref.isWellKnown())
+ {
+ LocatorInfo li = @ref.getLocatorInfo();
+ if(li != null)
+ {
+ li.clearCache(@ref);
+ }
+ }
+ }
+ else
+ {
+ //
+ // For all other cases, we don't retry ObjectNotExistException.
+ //
+ throw ex;
+ }
+ }
+ else if(ex is Ice.RequestFailedException)
+ {
+ throw ex;
+ }
+
+ //
+ // There is no point in retrying an operation that resulted in a
+ // MarshalException. This must have been raised locally (because if
+ // it happened in a server it would result in an UnknownLocalException
+ // instead), which means there was a problem in this process that will
+ // not change if we try again.
+ //
+ // The most likely cause for a MarshalException is exceeding the
+ // maximum message size, which is represented by the subclass
+ // MemoryLimitException. For example, a client can attempt to send a
+ // message that exceeds the maximum memory size, or accumulate enough
+ // batch requests without flushing that the maximum size is reached.
+ //
+ // This latter case is especially problematic, because if we were to
+ // retry a batch request after a MarshalException, we would in fact
+ // silently discard the accumulated requests and allow new batch
+ // requests to accumulate. If the subsequent batched requests do not
+ // exceed the maximum message size, it appears to the client that all
+ // of the batched requests were accepted, when in reality only the
+ // last few are actually sent.
+ //
+ if(ex is Ice.MarshalException)
+ {
+ throw ex;
+ }
+
+
+ //
+ // Don't retry if the communicator is destroyed or object adapter
+ // deactivated.
+ //
+ if(ex is Ice.CommunicatorDestroyedException || ex is Ice.ObjectAdapterDeactivatedException)
+ {
+ throw ex;
+ }
+
+ //
+ // Don't retry invocation timeouts.
+ //
+ if(ex is Ice.InvocationTimeoutException || ex is Ice.InvocationCanceledException)
+ {
+ throw ex;
+ }
+
+ ++cnt;
+ Debug.Assert(cnt > 0);
+
+ int interval;
+ if(cnt == (_retryIntervals.Length + 1) && ex is Ice.CloseConnectionException)
+ {
+ //
+ // A close connection exception is always retried at least once, even if the retry
+ // limit is reached.
+ //
+ interval = 0;
+ }
+ else if(cnt > _retryIntervals.Length)
+ {
+ if(traceLevels.retry >= 1)
+ {
+ string s = "cannot retry operation call because retry limit has been exceeded\n" + ex;
+ logger.trace(traceLevels.retryCat, s);
+ }
+ throw ex;
+ }
+ else
+ {
+ interval = _retryIntervals[cnt - 1];
+ }
+
+ if(traceLevels.retry >= 1)
+ {
+ string s = "retrying operation call";
+ if(interval > 0)
+ {
+ s += " in " + interval + "ms";
+ }
+ s += " because of exception\n" + ex;
+ logger.trace(traceLevels.retryCat, s);
+ }
+
+ return interval;
+ }
+
+ //
+ // Only for use by Instance
+ //
+ internal ProxyFactory(Instance instance)
+ {
+ instance_ = instance;
+
+ string[] arr = instance_.initializationData().properties.getPropertyAsList("Ice.RetryIntervals");
+
+ if(arr.Length > 0)
+ {
+ _retryIntervals = new int[arr.Length];
+
+ for (int i = 0; i < arr.Length; i++)
+ {
+ int v;
+
+ try
+ {
+ v = System.Int32.Parse(arr[i], CultureInfo.InvariantCulture);
+ }
+ catch(System.FormatException)
+ {
+ v = 0;
+ }
+
+ //
+ // If -1 is the first value, no retry and wait intervals.
+ //
+ if(i == 0 && v == -1)
+ {
+ _retryIntervals = new int[0];
+ break;
+ }
+
+ _retryIntervals[i] = v > 0?v:0;
+ }
+ }
+ else
+ {
+ _retryIntervals = new int[1];
+ _retryIntervals[0] = 0;
+ }
+ }
+
+ private Instance instance_;
+ private int[] _retryIntervals;
+ }
+
+}
diff --git a/csharp/src/Ice/ProxyIdentityKey.cs b/csharp/src/Ice/ProxyIdentityKey.cs
new file mode 100644
index 00000000000..3fbf481b439
--- /dev/null
+++ b/csharp/src/Ice/ProxyIdentityKey.cs
@@ -0,0 +1,135 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Globalization;
+
+namespace Ice
+{
+ /// <summary>
+ /// This class allows a proxy to be used as the key for a hashed collection.
+ /// The GetHashCode, Equals, and Compare methods are based on the object identity
+ /// of the proxy.
+ /// </summary>
+ public class ProxyIdentityKey : System.Collections.IEqualityComparer, System.Collections.IComparer
+ {
+ /// <summary>
+ /// Computes a hash value based on the object identity of the proxy.
+ /// </summary>
+ /// <param name="obj">The proxy whose hash value to compute.</param>
+ /// <returns>The hash value for the proxy based on the identity.</returns>
+ public int GetHashCode(object obj)
+ {
+ int h = 5381;
+ IceInternal.HashUtil.hashAdd(ref h, ((Ice.ObjectPrx)obj).ice_getIdentity());
+ return h;
+ }
+
+ /// Compares two proxies for equality.
+ /// <param name="obj1">A proxy to compare.</param>
+ /// <param name="obj2">A proxy to compare.</param>
+ /// <returns>True if the passed proxies have the same object
+ /// identity; false, otherwise.</returns>
+ public new bool Equals(object obj1, object obj2)
+ {
+ try
+ {
+ return Compare(obj1, obj2) == 0;
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+ }
+
+ /// Compares two proxies using the object identity for comparison.
+ /// <param name="obj1">A proxy to compare.</param>
+ /// <param name="obj2">A proxy to compare.</param>
+ /// <returns>&lt; 0 if obj1 is less than obj2; &gt; 0 if obj1 is greater than obj2;
+ /// 0, otherwise.</returns>
+ public int Compare(object obj1, object obj2)
+ {
+ Ice.ObjectPrx proxy1 = obj1 as Ice.ObjectPrx;
+ if(obj1 != null && proxy1 == null)
+ {
+ throw new System.ArgumentException("Argument must be derived from Ice.ObjectPrx", "obj1");
+ }
+
+ Ice.ObjectPrx proxy2 = obj2 as Ice.ObjectPrx;
+ if(obj2 != null && proxy2 == null)
+ {
+ throw new System.ArgumentException("Argument must be derived from Ice.ObjectPrx", "obj2");
+ }
+ return Ice.Util.proxyIdentityCompare(proxy1, proxy2);
+ }
+ }
+
+ /// <summary>
+ /// This class allows a proxy to be used as the key for a hashed collection.
+ /// The GetHashCode, Equals, and Compare methods are based on the object identity and
+ /// the facet of the proxy.
+ /// </summary>
+ public class ProxyIdentityFacetKey : System.Collections.IEqualityComparer, System.Collections.IComparer
+ {
+ /// <summary>
+ /// Computes a hash value based on the object identity and facet of the proxy.
+ /// </summary>
+ /// <param name="obj">The proxy whose hash value to compute.</param>
+ /// <returns>The hash value for the proxy based on the identity and facet.</returns>
+ public int GetHashCode(object obj)
+ {
+ Ice.ObjectPrx o = (Ice.ObjectPrx)obj;
+ Ice.Identity identity = o.ice_getIdentity();
+ string facet = o.ice_getFacet();
+ int h = 5381;
+ IceInternal.HashUtil.hashAdd(ref h, identity);
+ IceInternal.HashUtil.hashAdd(ref h, facet);
+ return h;
+ }
+
+ /// Compares two proxies for equality.
+ /// <param name="obj1">A proxy to compare.</param>
+ /// <param name="obj2">A proxy to compare.</param>
+ /// <returns>True if the passed proxies have the same object
+ /// identity and facet; false, otherwise.</returns>
+ public new bool Equals(object obj1, object obj2)
+ {
+ try
+ {
+ return Compare(obj1, obj2) == 0;
+ }
+ catch(System.Exception)
+ {
+ return false;
+ }
+ }
+
+ /// Compares two proxies using the object identity and facet for comparison.
+ /// <param name="obj1">A proxy to compare.</param>
+ /// <param name="obj2">A proxy to compare.</param>
+ /// <returns>&lt; 0 if obj1 is less than obj2; &gt; 0 if obj1 is greater than obj2;
+ /// 0, otherwise.</returns>
+ public int Compare(object obj1, object obj2)
+ {
+ Ice.ObjectPrx proxy1 = obj1 as Ice.ObjectPrx;
+ if(obj1 != null && proxy1 == null)
+ {
+ throw new System.ArgumentException("Argument must be derived from Ice.ObjectPrx", "obj1");
+ }
+
+ Ice.ObjectPrx proxy2 = obj2 as Ice.ObjectPrx;
+ if(obj2 != null && proxy2 == null)
+ {
+ throw new System.ArgumentException("Argument must be derived from Ice.ObjectPrx", "obj2");
+ }
+ return Ice.Util.proxyIdentityAndFacetCompare(proxy1, proxy2);
+ }
+ }
+
+}
diff --git a/csharp/src/Ice/Reference.cs b/csharp/src/Ice/Reference.cs
new file mode 100644
index 00000000000..80e48608a5d
--- /dev/null
+++ b/csharp/src/Ice/Reference.cs
@@ -0,0 +1,1685 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using System.Globalization;
+
+namespace IceInternal
+{
+ public abstract class Reference : ICloneable
+ {
+ public enum Mode {
+ ModeTwoway,
+ ModeOneway,
+ ModeBatchOneway,
+ ModeDatagram,
+ ModeBatchDatagram,
+ ModeLast=ModeBatchDatagram
+ };
+
+ public interface GetConnectionCallback
+ {
+ void setConnection(Ice.ConnectionI connection, bool compress);
+ void setException(Ice.LocalException ex);
+ }
+
+ public Mode getMode()
+ {
+ return mode_;
+ }
+
+ public bool getSecure()
+ {
+ return secure_;
+ }
+
+ public Ice.ProtocolVersion getProtocol()
+ {
+ return protocol_;
+ }
+
+ public Ice.EncodingVersion getEncoding()
+ {
+ return encoding_;
+ }
+
+ public Ice.Identity getIdentity()
+ {
+ return identity_;
+ }
+
+ public string getFacet()
+ {
+ return facet_;
+ }
+
+ public Instance getInstance()
+ {
+ return instance_;
+ }
+
+ public Dictionary<string, string> getContext()
+ {
+ return context_;
+ }
+
+ public int
+ getInvocationTimeout()
+ {
+ return invocationTimeout_;
+ }
+
+ public Ice.Communicator getCommunicator()
+ {
+ return communicator_;
+ }
+
+ public abstract EndpointI[] getEndpoints();
+ public abstract string getAdapterId();
+ public abstract LocatorInfo getLocatorInfo();
+ public abstract RouterInfo getRouterInfo();
+ public abstract bool getCollocationOptimized();
+ public abstract bool getCacheConnection();
+ public abstract bool getPreferSecure();
+ public abstract Ice.EndpointSelectionType getEndpointSelection();
+ public abstract int getLocatorCacheTimeout();
+ public abstract String getConnectionId();
+
+ //
+ // The change* methods (here and in derived classes) create
+ // a new reference based on the existing one, with the
+ // corresponding value changed.
+ //
+ public Reference changeContext(Dictionary<string, string> newContext)
+ {
+ if(newContext == null)
+ {
+ newContext = _emptyContext;
+ }
+ Reference r = instance_.referenceFactory().copy(this);
+ if(newContext.Count == 0)
+ {
+ r.context_ = _emptyContext;
+ }
+ else
+ {
+ r.context_ = new Dictionary<string, string>(newContext);
+ }
+ return r;
+ }
+
+ public Reference changeMode(Mode newMode)
+ {
+ if(newMode == mode_)
+ {
+ return this;
+ }
+ Reference r = instance_.referenceFactory().copy(this);
+ r.mode_ = newMode;
+ return r;
+ }
+
+ public Reference changeSecure(bool newSecure)
+ {
+ if(newSecure == secure_)
+ {
+ return this;
+ }
+ Reference r = instance_.referenceFactory().copy(this);
+ r.secure_ = newSecure;
+ return r;
+ }
+
+ public Reference changeIdentity(Ice.Identity newIdentity)
+ {
+ if(newIdentity.Equals(identity_))
+ {
+ return this;
+ }
+ Reference r = instance_.referenceFactory().copy(this);
+ r.identity_ = newIdentity; // Identity is a value type, therefore a copy of newIdentity is made.
+ return r;
+ }
+
+ public Reference changeFacet(string newFacet)
+ {
+ if(newFacet.Equals(facet_))
+ {
+ return this;
+ }
+ Reference r = instance_.referenceFactory().copy(this);
+ r.facet_ = newFacet;
+ return r;
+ }
+
+ public Reference changeInvocationTimeout(int newTimeout)
+ {
+ if(newTimeout == invocationTimeout_)
+ {
+ return this;
+ }
+ Reference r = instance_.referenceFactory().copy(this);
+ r.invocationTimeout_ = newTimeout;
+ return r;
+ }
+
+ public virtual Reference changeEncoding(Ice.EncodingVersion newEncoding)
+ {
+ if(newEncoding.Equals(encoding_))
+ {
+ return this;
+ }
+ Reference r = instance_.referenceFactory().copy(this);
+ r.encoding_ = newEncoding;
+ return r;
+ }
+
+ public virtual Reference changeCompress(bool newCompress)
+ {
+ if(overrideCompress_ && compress_ == newCompress)
+ {
+ return this;
+ }
+
+ Reference r = instance_.referenceFactory().copy(this);
+ r.compress_ = newCompress;
+ r.overrideCompress_ = true;
+ return r;
+ }
+
+ public abstract Reference changeEndpoints(EndpointI[] newEndpoints);
+ public abstract Reference changeAdapterId(string newAdapterId);
+ public abstract Reference changeLocator(Ice.LocatorPrx newLocator);
+ public abstract Reference changeRouter(Ice.RouterPrx newRouter);
+ public abstract Reference changeCollocationOptimized(bool newCollocationOptimized);
+ public abstract Reference changeCacheConnection(bool newCache);
+ public abstract Reference changePreferSecure(bool newPreferSecure);
+ public abstract Reference changeEndpointSelection(Ice.EndpointSelectionType newType);
+ public abstract Reference changeLocatorCacheTimeout(int newTimeout);
+
+ public abstract Reference changeTimeout(int newTimeout);
+ public abstract Reference changeConnectionId(string connectionId);
+
+ public override int GetHashCode()
+ {
+ lock(this)
+ {
+ if(hashInitialized_)
+ {
+ return hashValue_;
+ }
+ int h = 5381;
+ IceInternal.HashUtil.hashAdd(ref h, mode_);
+ IceInternal.HashUtil.hashAdd(ref h, secure_);
+ IceInternal.HashUtil.hashAdd(ref h, identity_);
+ IceInternal.HashUtil.hashAdd(ref h, context_);
+ IceInternal.HashUtil.hashAdd(ref h, facet_);
+ IceInternal.HashUtil.hashAdd(ref h, overrideCompress_);
+ if(overrideCompress_)
+ {
+ IceInternal.HashUtil.hashAdd(ref h, compress_);
+ }
+ IceInternal.HashUtil.hashAdd(ref h, protocol_);
+ IceInternal.HashUtil.hashAdd(ref h, encoding_);
+ IceInternal.HashUtil.hashAdd(ref h, invocationTimeout_);
+ hashValue_ = h;
+ hashInitialized_ = true;
+ return hashValue_;
+ }
+ }
+
+ public abstract bool isIndirect();
+ public abstract bool isWellKnown();
+
+ //
+ // Marshal the reference.
+ //
+ public virtual void streamWrite(BasicStream s)
+ {
+ //
+ // Don't write the identity here. Operations calling streamWrite
+ // write the identity.
+ //
+
+ //
+ // For compatibility with the old FacetPath.
+ //
+ if(facet_.Length == 0)
+ {
+ s.writeStringSeq(null);
+ }
+ else
+ {
+ string[] facetPath = { facet_ };
+ s.writeStringSeq(facetPath);
+ }
+
+ s.writeByte((byte)mode_);
+
+ s.writeBool(secure_);
+
+ if(!s.getWriteEncoding().Equals(Ice.Util.Encoding_1_0))
+ {
+ protocol_.write__(s);
+ encoding_.write__(s);
+ }
+
+ // Derived class writes the remainder of the reference.
+ }
+
+ //
+ // Convert the reference to its string form.
+ //
+ public override string ToString()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ StringBuilder s = new StringBuilder();
+
+ //
+ // If the encoded identity string contains characters which
+ // the reference parser uses as separators, then we enclose
+ // the identity string in quotes.
+ //
+ string id = instance_.identityToString(identity_);
+ if(IceUtilInternal.StringUtil.findFirstOf(id, " :@") != -1)
+ {
+ s.Append('"');
+ s.Append(id);
+ s.Append('"');
+ }
+ else
+ {
+ s.Append(id);
+ }
+
+ if(facet_.Length > 0)
+ {
+ //
+ // If the encoded facet string contains characters which
+ // the reference parser uses as separators, then we enclose
+ // the facet string in quotes.
+ //
+ s.Append(" -f ");
+ string fs = IceUtilInternal.StringUtil.escapeString(facet_, "");
+ if(IceUtilInternal.StringUtil.findFirstOf(fs, " :@") != -1)
+ {
+ s.Append('"');
+ s.Append(fs);
+ s.Append('"');
+ }
+ else
+ {
+ s.Append(fs);
+ }
+ }
+
+ switch(mode_)
+ {
+ case Mode.ModeTwoway:
+ {
+ s.Append(" -t");
+ break;
+ }
+
+ case Mode.ModeOneway:
+ {
+ s.Append(" -o");
+ break;
+ }
+
+ case Mode.ModeBatchOneway:
+ {
+ s.Append(" -O");
+ break;
+ }
+
+ case Mode.ModeDatagram:
+ {
+ s.Append(" -d");
+ break;
+ }
+
+ case Mode.ModeBatchDatagram:
+ {
+ s.Append(" -D");
+ break;
+ }
+ }
+
+ if(secure_)
+ {
+ s.Append(" -s");
+ }
+
+ if(!protocol_.Equals(Ice.Util.Protocol_1_0))
+ {
+ //
+ // We only print the protocol if it's not 1.0. It's fine as
+ // long as we don't add Ice.Default.ProtocolVersion, a
+ // stringified proxy will convert back to the same proxy with
+ // stringToProxy.
+ //
+ s.Append(" -p ");
+ s.Append(Ice.Util.protocolVersionToString(protocol_));
+ }
+
+ //
+ // Always print the encoding version to ensure a stringified proxy
+ // will convert back to a proxy with the same encoding with
+ // stringToProxy (and won't use Ice.Default.EncodingVersion).
+ //
+ s.Append(" -e ");
+ s.Append(Ice.Util.encodingVersionToString(encoding_));
+
+ return s.ToString();
+
+ // Derived class writes the remainder of the string.
+ }
+
+ public abstract Dictionary<string, string> toProperty(string prefix);
+
+ public abstract RequestHandler getRequestHandler(Ice.ObjectPrxHelperBase proxy);
+
+ public abstract BatchRequestQueue getBatchRequestQueue();
+
+ public override bool Equals(object obj)
+ {
+ //
+ // Note: if(this == obj) and type test are performed by each non-abstract derived class.
+ //
+
+ Reference r = (Reference)obj; // Guaranteed to succeed.
+
+ if(mode_ != r.mode_)
+ {
+ return false;
+ }
+
+ if(secure_ != r.secure_)
+ {
+ return false;
+ }
+
+ if(!identity_.Equals(r.identity_))
+ {
+ return false;
+ }
+
+ if(!Ice.CollectionComparer.Equals(context_, r.context_))
+ {
+ return false;
+ }
+
+ if(!facet_.Equals(r.facet_))
+ {
+ return false;
+ }
+
+ if(overrideCompress_ != r.overrideCompress_)
+ {
+ return false;
+ }
+ if(overrideCompress_ && compress_ != r.compress_)
+ {
+ return false;
+ }
+
+ if(!protocol_.Equals(r.protocol_))
+ {
+ return false;
+ }
+
+ if(!encoding_.Equals(r.encoding_))
+ {
+ return false;
+ }
+
+ if(invocationTimeout_ != r.invocationTimeout_)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public Object Clone()
+ {
+ //
+ // A member-wise copy is safe because the members are immutable.
+ //
+ return MemberwiseClone();
+ }
+
+ protected int hashValue_;
+ protected bool hashInitialized_;
+ private static Dictionary<string, string> _emptyContext = new Dictionary<string, string>();
+
+ private Instance instance_;
+ private Ice.Communicator communicator_;
+
+ private Mode mode_;
+ private Ice.Identity identity_;
+ private Dictionary<string, string> context_;
+ private string facet_;
+ protected bool secure_;
+ private Ice.ProtocolVersion protocol_;
+ private Ice.EncodingVersion encoding_;
+ private int invocationTimeout_;
+
+ protected bool overrideCompress_;
+ protected bool compress_; // Only used if _overrideCompress == true
+
+ protected Reference(Instance instance,
+ Ice.Communicator communicator,
+ Ice.Identity identity,
+ string facet,
+ Mode mode,
+ bool secure,
+ Ice.ProtocolVersion protocol,
+ Ice.EncodingVersion encoding,
+ int invocationTimeout,
+ Dictionary<string, string> context)
+ {
+ //
+ // Validate string arguments.
+ //
+ Debug.Assert(identity.name != null);
+ Debug.Assert(identity.category != null);
+ Debug.Assert(facet != null);
+
+ instance_ = instance;
+ communicator_ = communicator;
+ mode_ = mode;
+ identity_ = identity;
+ context_ = context != null ? new Dictionary<string, string>(context) : _emptyContext;
+ facet_ = facet;
+ protocol_ = protocol;
+ encoding_ = encoding;
+ invocationTimeout_ = invocationTimeout;
+ secure_ = secure;
+ hashInitialized_ = false;
+ overrideCompress_ = false;
+ compress_ = false;
+ }
+
+ protected static System.Random rand_ = new System.Random(unchecked((int)System.DateTime.Now.Ticks));
+ }
+
+ public class FixedReference : Reference
+ {
+ public FixedReference(Instance instance,
+ Ice.Communicator communicator,
+ Ice.Identity identity,
+ string facet,
+ Reference.Mode mode,
+ bool secure,
+ Ice.EncodingVersion encoding,
+ Ice.ConnectionI connection)
+ : base(instance, communicator, identity, facet, mode, secure, Ice.Util.Protocol_1_0, encoding, -1, null)
+ {
+ _fixedConnection = connection;
+ }
+
+ public override EndpointI[] getEndpoints()
+ {
+ return _emptyEndpoints;
+ }
+
+ public override string getAdapterId()
+ {
+ return "";
+ }
+
+ public override LocatorInfo getLocatorInfo()
+ {
+ return null;
+ }
+
+ public override RouterInfo getRouterInfo()
+ {
+ return null;
+ }
+
+ public override bool getCollocationOptimized()
+ {
+ return false;
+ }
+
+ public override bool getCacheConnection()
+ {
+ return true;
+ }
+
+ public override bool getPreferSecure()
+ {
+ return false;
+ }
+
+ public override Ice.EndpointSelectionType getEndpointSelection()
+ {
+ return Ice.EndpointSelectionType.Random;
+ }
+
+ public override int getLocatorCacheTimeout()
+ {
+ return 0;
+ }
+
+ public override string getConnectionId()
+ {
+ return "";
+ }
+
+ public override Reference changeEndpoints(EndpointI[] newEndpoints)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeAdapterId(string newAdapterId)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeLocator(Ice.LocatorPrx newLocator)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeRouter(Ice.RouterPrx newRouter)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeCollocationOptimized(bool newCollocationOptimized)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeCacheConnection(bool newCache)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changePreferSecure(bool prefSec)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeEndpointSelection(Ice.EndpointSelectionType newType)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeLocatorCacheTimeout(int newTimeout)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeTimeout(int newTimeout)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Reference changeConnectionId(string connectionId)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override bool isIndirect()
+ {
+ return false;
+ }
+
+ public override bool isWellKnown()
+ {
+ return false;
+ }
+
+ public override void streamWrite(BasicStream s)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override string ToString()
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override Dictionary<string, string> toProperty(string prefix)
+ {
+ throw new Ice.FixedProxyException();
+ }
+
+ public override RequestHandler getRequestHandler(Ice.ObjectPrxHelperBase proxy)
+ {
+ switch(getMode())
+ {
+ case Reference.Mode.ModeTwoway:
+ case Reference.Mode.ModeOneway:
+ case Reference.Mode.ModeBatchOneway:
+ {
+ if(_fixedConnection.endpoint().datagram())
+ {
+ throw new Ice.NoEndpointException("");
+ }
+ break;
+ }
+
+ case Reference.Mode.ModeDatagram:
+ case Reference.Mode.ModeBatchDatagram:
+ {
+ if(!_fixedConnection.endpoint().datagram())
+ {
+ throw new Ice.NoEndpointException("");
+ }
+ break;
+ }
+ }
+
+ //
+ // If a secure connection is requested or secure overrides is set,
+ // check if the connection is secure.
+ //
+ bool secure;
+ DefaultsAndOverrides defaultsAndOverrides = getInstance().defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideSecure)
+ {
+ secure = defaultsAndOverrides.overrideSecureValue;
+ }
+ else
+ {
+ secure = getSecure();
+ }
+ if(secure && !_fixedConnection.endpoint().secure())
+ {
+ throw new Ice.NoEndpointException("");
+ }
+
+ _fixedConnection.throwException(); // Throw in case our connection is already destroyed.
+
+ bool compress;
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ compress = defaultsAndOverrides.overrideCompressValue;
+ }
+ else if(overrideCompress_)
+ {
+ compress = compress_;
+ }
+ else
+ {
+ compress = _fixedConnection.endpoint().compress();
+ }
+
+ return ((Ice.ObjectPrxHelperBase)proxy).setRequestHandler__(new ConnectionRequestHandler(this,
+ _fixedConnection,
+ compress));
+ }
+
+ public override BatchRequestQueue getBatchRequestQueue()
+ {
+ return _fixedConnection.getBatchRequestQueue();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(object.ReferenceEquals(this, obj))
+ {
+ return true;
+ }
+ FixedReference rhs = obj as FixedReference;
+ if(rhs == null)
+ {
+ return false;
+ }
+ if(!base.Equals(rhs))
+ {
+ return false;
+ }
+ return _fixedConnection.Equals(_fixedConnection);
+ }
+
+ //
+ // If we override Equals, we must also override GetHashCode.
+ //
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ private Ice.ConnectionI _fixedConnection;
+ private static EndpointI[] _emptyEndpoints = new EndpointI[0];
+ }
+
+ public class RoutableReference : Reference
+ {
+ public override EndpointI[] getEndpoints()
+ {
+ return _endpoints;
+ }
+
+ public override string getAdapterId()
+ {
+ return _adapterId;
+ }
+
+ public override LocatorInfo getLocatorInfo()
+ {
+ return _locatorInfo;
+ }
+
+ public override RouterInfo getRouterInfo()
+ {
+ return _routerInfo;
+ }
+
+ public override bool getCollocationOptimized()
+ {
+ return _collocationOptimized;
+ }
+
+ public override bool getCacheConnection()
+ {
+ return _cacheConnection;
+ }
+
+ public override bool getPreferSecure()
+ {
+ return _preferSecure;
+ }
+
+ public override Ice.EndpointSelectionType getEndpointSelection()
+ {
+ return _endpointSelection;
+ }
+
+ public override int getLocatorCacheTimeout()
+ {
+ return _locatorCacheTimeout;
+ }
+
+ public override string getConnectionId()
+ {
+ return _connectionId;
+ }
+
+ public override Reference changeEncoding(Ice.EncodingVersion newEncoding)
+ {
+ RoutableReference r = (RoutableReference)base.changeEncoding(newEncoding);
+ if(r != this)
+ {
+ LocatorInfo locInfo = r._locatorInfo;
+ if(locInfo != null && !locInfo.getLocator().ice_getEncodingVersion().Equals(newEncoding))
+ {
+ r._locatorInfo = getInstance().locatorManager().get(
+ (Ice.LocatorPrx)locInfo.getLocator().ice_encodingVersion(newEncoding));
+ }
+ }
+ return r;
+ }
+
+ public override Reference changeCompress(bool newCompress)
+ {
+ RoutableReference r = (RoutableReference)base.changeCompress(newCompress);
+ if(r != this && _endpoints.Length > 0) // Also override the compress flag on the endpoints if it was updated
+ {
+ EndpointI[] newEndpoints = new EndpointI[_endpoints.Length];
+ for(int i = 0; i < _endpoints.Length; i++)
+ {
+ newEndpoints[i] = _endpoints[i].compress(newCompress);
+ }
+ r._endpoints = newEndpoints;
+ }
+ return r;
+ }
+
+ public override Reference changeEndpoints(EndpointI[] newEndpoints)
+ {
+ if(Array.Equals(newEndpoints, _endpoints))
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._endpoints = newEndpoints;
+ r._adapterId = "";
+ r.applyOverrides(ref r._endpoints);
+ return r;
+ }
+
+ public override Reference changeAdapterId(string newAdapterId)
+ {
+ if(_adapterId.Equals(newAdapterId))
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._adapterId = newAdapterId;
+ r._endpoints = _emptyEndpoints;
+ return r;
+ }
+
+ public override Reference changeLocator(Ice.LocatorPrx newLocator)
+ {
+ LocatorInfo newLocatorInfo = getInstance().locatorManager().get(newLocator);
+ if(newLocatorInfo != null && _locatorInfo != null && newLocatorInfo.Equals(_locatorInfo))
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._locatorInfo = newLocatorInfo;
+ return r;
+ }
+
+ public override Reference changeRouter(Ice.RouterPrx newRouter)
+ {
+ RouterInfo newRouterInfo = getInstance().routerManager().get(newRouter);
+ if(newRouterInfo != null && _routerInfo != null && newRouterInfo.Equals(_routerInfo))
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._routerInfo = newRouterInfo;
+ return r;
+ }
+
+ public override Reference changeCollocationOptimized(bool newCollocationOptimized)
+ {
+ if(newCollocationOptimized == _collocationOptimized)
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._collocationOptimized = newCollocationOptimized;
+ return r;
+ }
+
+ public override Reference changeCacheConnection(bool newCache)
+ {
+ if(newCache == _cacheConnection)
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._cacheConnection = newCache;
+ return r;
+ }
+
+ public override Reference changePreferSecure(bool newPreferSecure)
+ {
+ if(newPreferSecure == _preferSecure)
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._preferSecure = newPreferSecure;
+ return r;
+ }
+
+ public override Reference changeEndpointSelection(Ice.EndpointSelectionType newType)
+ {
+ if(newType == _endpointSelection)
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._endpointSelection = newType;
+ return r;
+ }
+
+ public override Reference changeLocatorCacheTimeout(int newTimeout)
+ {
+ if(newTimeout == _locatorCacheTimeout)
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._locatorCacheTimeout = newTimeout;
+ return r;
+ }
+
+ public override Reference changeTimeout(int newTimeout)
+ {
+ if(_overrideTimeout && _timeout == newTimeout)
+ {
+ return this;
+ }
+
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._timeout = newTimeout;
+ r._overrideTimeout = true;
+ if(_endpoints.Length > 0)
+ {
+ EndpointI[] newEndpoints = new EndpointI[_endpoints.Length];
+ for(int i = 0; i < _endpoints.Length; i++)
+ {
+ newEndpoints[i] = _endpoints[i].timeout(newTimeout);
+ }
+ r._endpoints = newEndpoints;
+ }
+ return r;
+ }
+
+ public override Reference changeConnectionId(string id)
+ {
+ if(_connectionId.Equals(id))
+ {
+ return this;
+ }
+ RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this);
+ r._connectionId = id;
+ if(_endpoints.Length > 0)
+ {
+ EndpointI[] newEndpoints = new EndpointI[_endpoints.Length];
+ for(int i = 0; i < _endpoints.Length; i++)
+ {
+ newEndpoints[i] = _endpoints[i].connectionId(id);
+ }
+ r._endpoints = newEndpoints;
+ }
+ return r;
+ }
+
+ public override bool isIndirect()
+ {
+ return _endpoints.Length == 0;
+ }
+
+ public override bool isWellKnown()
+ {
+ return _endpoints.Length == 0 && _adapterId.Length == 0;
+ }
+
+ public override void streamWrite(BasicStream s)
+ {
+ base.streamWrite(s);
+
+ s.writeSize(_endpoints.Length);
+ if(_endpoints.Length > 0)
+ {
+ Debug.Assert(_adapterId.Length == 0);
+ foreach(EndpointI endpoint in _endpoints)
+ {
+ s.writeShort(endpoint.type());
+ endpoint.streamWrite(s);
+ }
+ }
+ else
+ {
+ s.writeString(_adapterId); // Adapter id.
+ }
+ }
+
+ public override string ToString()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ StringBuilder s = new StringBuilder();
+ s.Append(base.ToString());
+
+ if(_endpoints.Length > 0)
+ {
+ for(int i = 0; i < _endpoints.Length; i++)
+ {
+ string endp = _endpoints[i].ToString();
+ if(endp != null && endp.Length > 0)
+ {
+ s.Append(':');
+ s.Append(endp);
+ }
+ }
+ }
+ else if(_adapterId.Length > 0)
+ {
+ s.Append(" @ ");
+
+ //
+ // If the encoded adapter id string contains characters which
+ // the reference parser uses as separators, then we enclose
+ // the adapter id string in quotes.
+ //
+ string a = IceUtilInternal.StringUtil.escapeString(_adapterId, null);
+ if(IceUtilInternal.StringUtil.findFirstOf(a, " :@") != -1)
+ {
+ s.Append('"');
+ s.Append(a);
+ s.Append('"');
+ }
+ else
+ {
+ s.Append(a);
+ }
+ }
+ return s.ToString();
+ }
+
+ public override Dictionary<string, string> toProperty(string prefix)
+ {
+ Dictionary<string, string> properties = new Dictionary<string, string>();
+
+ properties[prefix] = ToString();
+ properties[prefix + ".CollocationOptimized"] = _collocationOptimized ? "1" : "0";
+ properties[prefix + ".ConnectionCached"] = _cacheConnection ? "1" : "0";
+ properties[prefix + ".PreferSecure"] = _preferSecure ? "1" : "0";
+ properties[prefix + ".EndpointSelection"] =
+ _endpointSelection == Ice.EndpointSelectionType.Random ? "Random" : "Ordered";
+ properties[prefix + ".LocatorCacheTimeout"] = _locatorCacheTimeout.ToString(CultureInfo.InvariantCulture);
+ properties[prefix + ".InvocationTimeout"] = getInvocationTimeout().ToString(CultureInfo.InvariantCulture);
+
+ if(_routerInfo != null)
+ {
+ Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase)_routerInfo.getRouter();
+ Dictionary<String, String> routerProperties = h.reference__().toProperty(prefix + ".Router");
+ foreach(KeyValuePair<string, string> entry in routerProperties)
+ {
+ properties[entry.Key] = entry.Value;
+ }
+ }
+
+ if(_locatorInfo != null)
+ {
+ Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase)_locatorInfo.getLocator();
+ Dictionary<String, String> locatorProperties = h.reference__().toProperty(prefix + ".Locator");
+ foreach(KeyValuePair<string, string> entry in locatorProperties)
+ {
+ properties[entry.Key] = entry.Value;
+ }
+ }
+
+ return properties;
+ }
+
+ //
+ // If we override Equals, we must also override GetHashCode.
+ //
+ public override int GetHashCode()
+ {
+ lock(this)
+ {
+ if(!hashInitialized_)
+ {
+ int h = base.GetHashCode(); // Initializes hashValue_.
+ IceInternal.HashUtil.hashAdd(ref h, _adapterId);
+ hashValue_ = h;
+ }
+ return hashValue_;
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(Object.ReferenceEquals(this, obj))
+ {
+ return true;
+ }
+
+ RoutableReference rhs = obj as RoutableReference;
+ if(rhs == null)
+ {
+ return false;
+ }
+
+ if(!base.Equals(obj))
+ {
+ return false;
+ }
+
+ if(_locatorInfo == null ? rhs._locatorInfo != null : !_locatorInfo.Equals(rhs._locatorInfo))
+ {
+ return false;
+ }
+ if(_routerInfo == null ? rhs._routerInfo != null : !_routerInfo.Equals(rhs._routerInfo))
+ {
+ return false;
+ }
+ if(_collocationOptimized != rhs._collocationOptimized)
+ {
+ return false;
+ }
+ if(_cacheConnection != rhs._cacheConnection)
+ {
+ return false;
+ }
+ if(_preferSecure != rhs._preferSecure)
+ {
+ return false;
+ }
+ if(_endpointSelection != rhs._endpointSelection)
+ {
+ return false;
+ }
+ if(_locatorCacheTimeout != rhs._locatorCacheTimeout)
+ {
+ return false;
+ }
+ if(_overrideTimeout != rhs._overrideTimeout)
+ {
+ return false;
+ }
+ if(_overrideTimeout && _timeout != rhs._timeout)
+ {
+ return false;
+ }
+ if(!_connectionId.Equals(rhs._connectionId))
+ {
+ return false;
+ }
+ if(!_adapterId.Equals(rhs._adapterId))
+ {
+ return false;
+ }
+ if(!IceUtilInternal.Arrays.Equals(_endpoints, rhs._endpoints))
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+ private sealed class RouterEndpointsCallback : RouterInfo.GetClientEndpointsCallback
+ {
+ internal RouterEndpointsCallback(RoutableReference ir, GetConnectionCallback cb)
+ {
+ _ir = ir;
+ _cb = cb;
+ }
+
+ public void setEndpoints(EndpointI[] endpts)
+ {
+ if(endpts.Length > 0)
+ {
+ _ir.applyOverrides(ref endpts);
+ _ir.createConnection(endpts, _cb);
+ }
+ else
+ {
+ _ir.getConnectionNoRouterInfo(_cb);
+ }
+ }
+
+ public void setException(Ice.LocalException ex)
+ {
+ _cb.setException(ex);
+ }
+
+ private RoutableReference _ir;
+ private GetConnectionCallback _cb;
+ }
+
+ public override RequestHandler getRequestHandler(Ice.ObjectPrxHelperBase proxy)
+ {
+ return getInstance().requestHandlerFactory().getRequestHandler(this, proxy);
+ }
+
+ public override BatchRequestQueue getBatchRequestQueue()
+ {
+ return new BatchRequestQueue(getInstance(), getMode() == Reference.Mode.ModeBatchDatagram);
+ }
+
+ public void getConnection(GetConnectionCallback callback)
+ {
+ if(_routerInfo != null)
+ {
+ //
+ // If we route, we send everything to the router's client
+ // proxy endpoints.
+ //
+ _routerInfo.getClientEndpoints(new RouterEndpointsCallback(this, callback));
+ }
+ else
+ {
+ getConnectionNoRouterInfo(callback);
+ }
+ }
+
+ private sealed class LocatorEndpointsCallback : LocatorInfo.GetEndpointsCallback
+ {
+ internal LocatorEndpointsCallback(RoutableReference ir, GetConnectionCallback cb)
+ {
+ _ir = ir;
+ _cb = cb;
+ }
+
+ public void setEndpoints(EndpointI[] endpoints, bool cached)
+ {
+ if(endpoints.Length == 0)
+ {
+ _cb.setException(new Ice.NoEndpointException(_ir.ToString()));
+ return;
+ }
+
+ _ir.applyOverrides(ref endpoints);
+ _ir.createConnection(endpoints, new ConnectionCallback(_ir, _cb, cached));
+ }
+
+ public void setException(Ice.LocalException ex)
+ {
+ _cb.setException(ex);
+ }
+
+ private RoutableReference _ir;
+ private GetConnectionCallback _cb;
+ }
+
+ private sealed class ConnectionCallback : GetConnectionCallback
+ {
+ internal ConnectionCallback(RoutableReference ir, GetConnectionCallback cb, bool cached)
+ {
+ _ir = ir;
+ _cb = cb;
+ _cached = cached;
+ }
+
+ public void setConnection(Ice.ConnectionI connection, bool compress)
+ {
+ _cb.setConnection(connection, compress);
+ }
+
+ public void setException(Ice.LocalException exc)
+ {
+ try
+ {
+ throw exc;
+ }
+ catch(Ice.NoEndpointException ex)
+ {
+ _cb.setException(ex); // No need to retry if there's no endpoints.
+ }
+ catch(Ice.LocalException ex)
+ {
+ Debug.Assert(_ir._locatorInfo != null);
+ _ir._locatorInfo.clearCache(_ir);
+ if(_cached)
+ {
+ TraceLevels traceLevels = _ir.getInstance().traceLevels();
+ if(traceLevels.retry >= 2)
+ {
+ String s = "connection to cached endpoints failed\n" +
+ "removing endpoints from cache and trying one more time\n" + ex;
+ _ir.getInstance().initializationData().logger.trace(traceLevels.retryCat, s);
+ }
+ _ir.getConnectionNoRouterInfo(_cb); // Retry.
+ return;
+ }
+ _cb.setException(ex);
+ }
+ }
+
+ private RoutableReference _ir;
+ private GetConnectionCallback _cb;
+ private bool _cached;
+ }
+
+ private void getConnectionNoRouterInfo(GetConnectionCallback callback)
+ {
+ if(_endpoints.Length > 0)
+ {
+ createConnection(_endpoints, callback);
+ return;
+ }
+
+ if(_locatorInfo != null)
+ {
+ _locatorInfo.getEndpoints(this, _locatorCacheTimeout, new LocatorEndpointsCallback(this, callback));
+ }
+ else
+ {
+ callback.setException(new Ice.NoEndpointException(ToString()));
+ }
+ }
+
+ public RoutableReference(Instance instance,
+ Ice.Communicator communicator,
+ Ice.Identity identity,
+ string facet,
+ Reference.Mode mode,
+ bool secure,
+ Ice.ProtocolVersion protocol,
+ Ice.EncodingVersion encoding,
+ EndpointI[] endpoints,
+ string adapterId,
+ LocatorInfo locatorInfo,
+ RouterInfo routerInfo,
+ bool collocationOptimized,
+ bool cacheConnection,
+ bool preferSecure,
+ Ice.EndpointSelectionType endpointSelection,
+ int locatorCacheTimeout,
+ int invocationTimeout,
+ Dictionary<string, string> context)
+ : base(instance, communicator, identity, facet, mode, secure, protocol, encoding, invocationTimeout, context)
+ {
+ _endpoints = endpoints;
+ _adapterId = adapterId;
+ _locatorInfo = locatorInfo;
+ _routerInfo = routerInfo;
+ _collocationOptimized = collocationOptimized;
+ _cacheConnection = cacheConnection;
+ _preferSecure = preferSecure;
+ _endpointSelection = endpointSelection;
+ _locatorCacheTimeout = locatorCacheTimeout;
+ _overrideTimeout = false;
+ _timeout = -1;
+
+ if(_endpoints == null)
+ {
+ _endpoints = _emptyEndpoints;
+ }
+
+ if(_adapterId == null)
+ {
+ _adapterId = "";
+ }
+
+ Debug.Assert(_adapterId.Length == 0 || _endpoints.Length == 0);
+ }
+
+ protected void applyOverrides(ref EndpointI[] endpts)
+ {
+ for(int i = 0; i < endpts.Length; ++i)
+ {
+ endpts[i] = endpts[i].connectionId(_connectionId);
+ if(overrideCompress_)
+ {
+ endpts[i] = endpts[i].compress(compress_);
+ }
+ if(_overrideTimeout)
+ {
+ endpts[i] = endpts[i].timeout(_timeout);
+ }
+ }
+ }
+
+ private EndpointI[] filterEndpoints(EndpointI[] allEndpoints)
+ {
+ List<EndpointI> endpoints = new List<EndpointI>();
+
+ //
+ // Filter out unknown endpoints.
+ //
+ for(int i = 0; i < allEndpoints.Length; i++)
+ {
+ if(!(allEndpoints[i] is IceInternal.OpaqueEndpointI))
+ {
+ endpoints.Add(allEndpoints[i]);
+ }
+ }
+
+ //
+ // Filter out endpoints according to the mode of the reference.
+ //
+ switch(getMode())
+ {
+ case Reference.Mode.ModeTwoway:
+ case Reference.Mode.ModeOneway:
+ case Reference.Mode.ModeBatchOneway:
+ {
+ //
+ // Filter out datagram endpoints.
+ //
+ List<EndpointI> tmp = new List<EndpointI>();
+ foreach(EndpointI endpoint in endpoints)
+ {
+ if(!endpoint.datagram())
+ {
+ tmp.Add(endpoint);
+ }
+ }
+ endpoints = tmp;
+ break;
+ }
+
+ case Reference.Mode.ModeDatagram:
+ case Reference.Mode.ModeBatchDatagram:
+ {
+ //
+ // Filter out non-datagram endpoints.
+ //
+ List<EndpointI> tmp = new List<EndpointI>();
+ foreach(EndpointI endpoint in endpoints)
+ {
+ if(endpoint.datagram())
+ {
+ tmp.Add(endpoint);
+ }
+ }
+ endpoints = tmp;
+ break;
+ }
+ }
+
+ //
+ // Sort the endpoints according to the endpoint selection type.
+ //
+ switch(getEndpointSelection())
+ {
+ case Ice.EndpointSelectionType.Random:
+ {
+ lock(rand_)
+ {
+ for(int i = 0; i < endpoints.Count - 1; ++i)
+ {
+ int r = rand_.Next(endpoints.Count - i) + i;
+ Debug.Assert(r >= i && r < endpoints.Count);
+ if(r != i)
+ {
+ EndpointI tmp = endpoints[i];
+ endpoints[i] = endpoints[r];
+ endpoints[r] = tmp;
+ }
+ }
+ }
+ break;
+ }
+ case Ice.EndpointSelectionType.Ordered:
+ {
+ // Nothing to do.
+ break;
+ }
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+
+ //
+ // If a secure connection is requested or secure overrides
+ // is set, remove all non-secure endpoints. Otherwise make
+ // non-secure endpoints preferred over secure endpoints by
+ // partitioning the endpoint vector, so that non-secure
+ // endpoints come first.
+ //
+ DefaultsAndOverrides overrides = getInstance().defaultsAndOverrides();
+ if(overrides.overrideSecure ? overrides.overrideSecureValue : getSecure())
+ {
+ List<EndpointI> tmp = new List<EndpointI>();
+ foreach(EndpointI endpoint in endpoints)
+ {
+ if(endpoint.secure())
+ {
+ tmp.Add(endpoint);
+ }
+ }
+ endpoints = tmp;
+ }
+ else if(getPreferSecure())
+ {
+ IceUtilInternal.Collections.Sort(ref endpoints, _preferSecureEndpointComparator);
+ }
+ else
+ {
+ IceUtilInternal.Collections.Sort(ref endpoints, _preferNonSecureEndpointComparator);
+ }
+
+ EndpointI[] arr = new EndpointI[endpoints.Count];
+ endpoints.CopyTo(arr);
+ return arr;
+ }
+
+ private sealed class CreateConnectionCallback : OutgoingConnectionFactory.CreateConnectionCallback
+ {
+ internal CreateConnectionCallback(RoutableReference rr, EndpointI[] endpoints, GetConnectionCallback cb)
+ {
+ _rr = rr;
+ _endpoints = endpoints;
+ _callback = cb;
+ }
+
+ public void setConnection(Ice.ConnectionI connection, bool compress)
+ {
+ //
+ // If we have a router, set the object adapter for this router
+ // (if any) to the new connection, so that callbacks from the
+ // router can be received over this new connection.
+ //
+ if(_rr._routerInfo != null && _rr._routerInfo.getAdapter() != null)
+ {
+ connection.setAdapter(_rr._routerInfo.getAdapter());
+ }
+ _callback.setConnection(connection, compress);
+ }
+
+ public void setException(Ice.LocalException ex)
+ {
+ if(_exception == null)
+ {
+ _exception = ex;
+ }
+
+ if(_endpoints == null || ++_i == _endpoints.Length)
+ {
+ _callback.setException(_exception);
+ return;
+ }
+
+ bool more = _i != _endpoints.Length - 1;
+ EndpointI[] endpoint = new EndpointI[]{ _endpoints[_i] };
+ _rr.getInstance().outgoingConnectionFactory().create(endpoint, more, _rr.getEndpointSelection(), this);
+ }
+
+ private RoutableReference _rr;
+ private EndpointI[] _endpoints;
+ private GetConnectionCallback _callback;
+ private int _i = 0;
+ private Ice.LocalException _exception = null;
+ }
+
+ protected void createConnection(EndpointI[] allEndpoints, GetConnectionCallback callback)
+ {
+ EndpointI[] endpoints = filterEndpoints(allEndpoints);
+ if(endpoints.Length == 0)
+ {
+ callback.setException(new Ice.NoEndpointException(ToString()));
+ return;
+ }
+
+ //
+ // Finally, create the connection.
+ //
+ OutgoingConnectionFactory factory = getInstance().outgoingConnectionFactory();
+ if(getCacheConnection() || endpoints.Length == 1)
+ {
+ //
+ // Get an existing connection or create one if there's no
+ // existing connection to one of the given endpoints.
+ //
+ factory.create(endpoints, false, getEndpointSelection(),
+ new CreateConnectionCallback(this, null, callback));
+ }
+ else
+ {
+ //
+ // Go through the list of endpoints and try to create the
+ // connection until it succeeds. This is different from just
+ // calling create() with the given endpoints since this might
+ // create a new connection even if there's an existing
+ // connection for one of the endpoints.
+ //
+
+ factory.create(new EndpointI[]{ endpoints[0] }, true, getEndpointSelection(),
+ new CreateConnectionCallback(this, endpoints, callback));
+ }
+ }
+
+ private class EndpointComparator : IComparer<IceInternal.EndpointI>
+ {
+ public EndpointComparator(bool preferSecure)
+ {
+ _preferSecure = preferSecure;
+ }
+
+ public int Compare(IceInternal.EndpointI le, IceInternal.EndpointI re)
+ {
+ bool ls = le.secure();
+ bool rs = re.secure();
+ if((ls && rs) || (!ls && !rs))
+ {
+ return 0;
+ }
+ else if(!ls && rs)
+ {
+ if(_preferSecure)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ if(_preferSecure)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+
+ private bool _preferSecure;
+ }
+
+ private static EndpointComparator _preferNonSecureEndpointComparator = new EndpointComparator(false);
+ private static EndpointComparator _preferSecureEndpointComparator = new EndpointComparator(true);
+ private static EndpointI[] _emptyEndpoints = new EndpointI[0];
+
+ private EndpointI[] _endpoints;
+ private string _adapterId;
+ private LocatorInfo _locatorInfo; // Null if no locator is used.
+ private RouterInfo _routerInfo; // Null if no router is used.
+ private bool _collocationOptimized;
+ private bool _cacheConnection;
+ private bool _preferSecure;
+ private Ice.EndpointSelectionType _endpointSelection;
+ private int _locatorCacheTimeout;
+
+ private bool _overrideTimeout;
+ private int _timeout; // Only used if _overrideTimeout == true
+ private string _connectionId = "";
+ }
+}
diff --git a/csharp/src/Ice/ReferenceFactory.cs b/csharp/src/Ice/ReferenceFactory.cs
new file mode 100644
index 00000000000..3d8e23287a4
--- /dev/null
+++ b/csharp/src/Ice/ReferenceFactory.cs
@@ -0,0 +1,926 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace IceInternal
+{
+
+ public class ReferenceFactory
+ {
+ public Reference
+ create(Ice.Identity ident, string facet, Reference tmpl, EndpointI[] endpoints)
+ {
+ if(ident.name.Length == 0 && ident.category.Length == 0)
+ {
+ return null;
+ }
+
+ return create(ident, facet, tmpl.getMode(), tmpl.getSecure(), tmpl.getProtocol(), tmpl.getEncoding(),
+ endpoints, null, null);
+ }
+
+ public Reference
+ create(Ice.Identity ident, string facet, Reference tmpl, string adapterId)
+ {
+ if(ident.name.Length == 0 && ident.category.Length == 0)
+ {
+ return null;
+ }
+
+ //
+ // Create new reference
+ //
+ return create(ident, facet, tmpl.getMode(), tmpl.getSecure(), tmpl.getProtocol(), tmpl.getEncoding(),
+ null, adapterId, null);
+ }
+
+ public Reference create(Ice.Identity ident, Ice.ConnectionI connection)
+ {
+ if(ident.name.Length == 0 && ident.category.Length == 0)
+ {
+ return null;
+ }
+
+ //
+ // Create new reference
+ //
+ return new FixedReference(
+ instance_,
+ _communicator,
+ ident,
+ "", // Facet
+ connection.endpoint().datagram() ? Reference.Mode.ModeDatagram : Reference.Mode.ModeTwoway,
+ connection.endpoint().secure(),
+ instance_.defaultsAndOverrides().defaultEncoding,
+ connection);
+ }
+
+ public Reference copy(Reference r)
+ {
+ Ice.Identity ident = r.getIdentity();
+ if(ident.name.Length == 0 && ident.category.Length == 0)
+ {
+ return null;
+ }
+ return (Reference)r.Clone();
+ }
+
+ public Reference create(string s, string propertyPrefix)
+ {
+ if(s.Length == 0)
+ {
+ return null;
+ }
+
+ const string delim = " \t\n\r";
+
+ int beg;
+ int end = 0;
+
+ beg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end);
+ if(beg == -1)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "no non-whitespace characters found in `" + s + "'";
+ throw e;
+ }
+
+ //
+ // Extract the identity, which may be enclosed in single
+ // or double quotation marks.
+ //
+ string idstr = null;
+ end = IceUtilInternal.StringUtil.checkQuote(s, beg);
+ if(end == -1)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "mismatched quotes around identity in `" + s + "'";
+ throw e;
+ }
+ else if(end == 0)
+ {
+ end = IceUtilInternal.StringUtil.findFirstOf(s, delim + ":@", beg);
+ if(end == -1)
+ {
+ end = s.Length;
+ }
+ idstr = s.Substring(beg, end - beg);
+ }
+ else
+ {
+ beg++; // Skip leading quote
+ idstr = s.Substring(beg, end - beg);
+ end++; // Skip trailing quote
+ }
+
+ if(beg == end)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "no identity in `" + s + "'";
+ throw e;
+ }
+
+ //
+ // Parsing the identity may raise IdentityParseException.
+ //
+ Ice.Identity ident = instance_.stringToIdentity(idstr);
+
+ if(ident.name.Length == 0)
+ {
+ //
+ // An identity with an empty name and a non-empty
+ // category is illegal.
+ //
+ if(ident.category.Length > 0)
+ {
+ Ice.IllegalIdentityException e = new Ice.IllegalIdentityException();
+ e.id = ident;
+ throw e;
+ }
+ //
+ // Treat a stringified proxy containing two double
+ // quotes ("") the same as an empty string, i.e.,
+ // a null proxy, but only if nothing follows the
+ // quotes.
+ //
+ else if(IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end) != -1)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "invalid characters after identity in `" + s + "'";
+ throw e;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ string facet = "";
+ Reference.Mode mode = Reference.Mode.ModeTwoway;
+ bool secure = false;
+ Ice.EncodingVersion encoding = instance_.defaultsAndOverrides().defaultEncoding;
+ Ice.ProtocolVersion protocol = Ice.Util.Protocol_1_0;
+ string adapter = "";
+
+ while(true)
+ {
+ beg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end);
+ if(beg == -1)
+ {
+ break;
+ }
+
+ if(s[beg] == ':' || s[beg] == '@')
+ {
+ break;
+ }
+
+ end = IceUtilInternal.StringUtil.findFirstOf(s, delim + ":@", beg);
+ if(end == -1)
+ {
+ end = s.Length;
+ }
+
+ if(beg == end)
+ {
+ break;
+ }
+
+ string option = s.Substring(beg, end - beg);
+ if(option.Length != 2 || option[0] != '-')
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "expected a proxy option but found `" + option + "' in `" + s + "'";
+ throw e;
+ }
+
+ //
+ // Check for the presence of an option argument. The
+ // argument may be enclosed in single or double
+ // quotation marks.
+ //
+ string argument = null;
+ int argumentBeg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end);
+ if(argumentBeg != -1)
+ {
+ char ch = s[argumentBeg];
+ if(ch != '@' && ch != ':' && ch != '-')
+ {
+ beg = argumentBeg;
+ end = IceUtilInternal.StringUtil.checkQuote(s, beg);
+ if(end == -1)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "mismatched quotes around value for " + option + " option in `" + s + "'";
+ throw e;
+ }
+ else if(end == 0)
+ {
+ end = IceUtilInternal.StringUtil.findFirstOf(s, delim + ":@", beg);
+ if(end == -1)
+ {
+ end = s.Length;
+ }
+ argument = s.Substring(beg, end - beg);
+ }
+ else
+ {
+ beg++; // Skip leading quote
+ argument = s.Substring(beg, end - beg);
+ end++; // Skip trailing quote
+ }
+ }
+ }
+
+ //
+ // If any new options are added here,
+ // IceInternal::Reference::toString() and its derived classes must be updated as well.
+ //
+ switch(option[1])
+ {
+ case 'f':
+ {
+ if(argument == null)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "no argument provided for -f option in `" + s + "'";
+ throw e;
+ }
+
+ try
+ {
+ facet = IceUtilInternal.StringUtil.unescapeString(argument, 0, argument.Length);
+ }
+ catch(System.ArgumentException argEx)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "invalid facet in `" + s + "': " + argEx.Message;
+ throw e;
+ }
+ break;
+ }
+
+ case 't':
+ {
+ if(argument != null)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -t option in `" + s + "'";
+ throw e;
+ }
+ mode = Reference.Mode.ModeTwoway;
+ break;
+ }
+
+ case 'o':
+ {
+ if(argument != null)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -o option in `" + s + "'";
+ throw e;
+ }
+ mode = Reference.Mode.ModeOneway;
+ break;
+ }
+
+ case 'O':
+ {
+ if(argument != null)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -O option in `" + s + "'";
+ throw e;
+ }
+ mode = Reference.Mode.ModeBatchOneway;
+ break;
+ }
+
+ case 'd':
+ {
+ if(argument != null)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -d option in `" + s + "'";
+ throw e;
+ }
+ mode = Reference.Mode.ModeDatagram;
+ break;
+ }
+
+ case 'D':
+ {
+ if(argument != null)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -D option in `" + s + "'";
+ throw e;
+ }
+ mode = Reference.Mode.ModeBatchDatagram;
+ break;
+ }
+
+ case 's':
+ {
+ if(argument != null)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -s option in `" + s + "'";
+ throw e;
+ }
+ secure = true;
+ break;
+ }
+
+ case 'e':
+ {
+ if(argument == null)
+ {
+ throw new Ice.ProxyParseException("no argument provided for -e option `" + s + "'");
+ }
+
+ try
+ {
+ encoding = Ice.Util.stringToEncodingVersion(argument);
+ }
+ catch(Ice.VersionParseException e)
+ {
+ throw new Ice.ProxyParseException("invalid encoding version `" + argument + "' in `" + s +
+ "':\n" + e.str);
+ }
+ break;
+ }
+
+ case 'p':
+ {
+ if(argument == null)
+ {
+ throw new Ice.ProxyParseException("no argument provided for -p option `" + s + "'");
+ }
+
+ try
+ {
+ protocol = Ice.Util.stringToProtocolVersion(argument);
+ }
+ catch(Ice.VersionParseException e)
+ {
+ throw new Ice.ProxyParseException("invalid protocol version `" + argument + "' in `" + s +
+ "':\n" + e.str);
+ }
+ break;
+ }
+
+ default:
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "unknown option `" + option + "' in `" + s + "'";
+ throw e;
+ }
+ }
+ }
+
+ if(beg == -1)
+ {
+ return create(ident, facet, mode, secure, protocol, encoding, null, null, propertyPrefix);
+ }
+
+ List<EndpointI> endpoints = new List<EndpointI>();
+
+ if(s[beg] == ':')
+ {
+ List<string> unknownEndpoints = new List<string>();
+ end = beg;
+
+ while(end < s.Length && s[end] == ':')
+ {
+ beg = end + 1;
+
+ end = beg;
+ while(true)
+ {
+ end = s.IndexOf(':', end);
+ if(end == -1)
+ {
+ end = s.Length;
+ break;
+ }
+ else
+ {
+ bool quoted = false;
+ int quote = beg;
+ while(true)
+ {
+ quote = s.IndexOf((System.Char) '\"', quote);
+ if(quote == -1 || end < quote)
+ {
+ break;
+ }
+ else
+ {
+ quote = s.IndexOf((System.Char) '\"', ++quote);
+ if(quote == -1)
+ {
+ break;
+ }
+ else if(end < quote)
+ {
+ quoted = true;
+ break;
+ }
+ ++quote;
+ }
+ }
+ if(!quoted)
+ {
+ break;
+ }
+ ++end;
+ }
+ }
+
+ string es = s.Substring(beg, end - beg);
+ EndpointI endp = instance_.endpointFactoryManager().create(es, false);
+ if(endp != null)
+ {
+ endpoints.Add(endp);
+ }
+ else
+ {
+ unknownEndpoints.Add(es);
+ }
+ }
+ if(endpoints.Count == 0)
+ {
+ Debug.Assert(unknownEndpoints.Count > 0);
+ Ice.EndpointParseException e2 = new Ice.EndpointParseException();
+ e2.str = "invalid endpoint `" + unknownEndpoints[0] + "' in `" + s + "'";
+ throw e2;
+ }
+ else if(unknownEndpoints.Count != 0 &&
+ instance_.initializationData().properties.getPropertyAsIntWithDefault(
+ "Ice.Warn.Endpoints", 1) > 0)
+ {
+ StringBuilder msg = new StringBuilder("Proxy contains unknown endpoints:");
+ int sz = unknownEndpoints.Count;
+ for(int idx = 0; idx < sz; ++idx)
+ {
+ msg.Append(" `");
+ msg.Append((string)unknownEndpoints[idx]);
+ msg.Append("'");
+ }
+ instance_.initializationData().logger.warning(msg.ToString());
+ }
+
+ EndpointI[] ep = endpoints.ToArray();
+ return create(ident, facet, mode, secure, protocol, encoding, ep, null, propertyPrefix);
+ }
+ else if(s[beg] == '@')
+ {
+ beg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, beg + 1);
+ if(beg == -1)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "missing adapter id in `" + s + "'";
+ throw e;
+ }
+
+ string adapterstr = null;
+ end = IceUtilInternal.StringUtil.checkQuote(s, beg);
+ if(end == -1)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "mismatched quotes around adapter id in `" + s + "'";
+ throw e;
+ }
+ else if(end == 0)
+ {
+ end = IceUtilInternal.StringUtil.findFirstOf(s, delim, beg);
+ if(end == -1)
+ {
+ end = s.Length;
+ }
+ adapterstr = s.Substring(beg, end - beg);
+ }
+ else
+ {
+ beg++; // Skip leading quote
+ adapterstr = s.Substring(beg, end - beg);
+ end++; // Skip trailing quote
+ }
+
+ if(end != s.Length && IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end) != -1)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "invalid trailing characters after `" + s.Substring(0, end + 1) + "' in `" + s + "'";
+ throw e;
+ }
+
+ try
+ {
+ adapter = IceUtilInternal.StringUtil.unescapeString(adapterstr, 0, adapterstr.Length);
+ }
+ catch(System.ArgumentException argEx)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "invalid adapter id in `" + s + "': " + argEx.Message;
+ throw e;
+ }
+ if(adapter.Length == 0)
+ {
+ Ice.ProxyParseException e = new Ice.ProxyParseException();
+ e.str = "empty adapter id in `" + s + "'";
+ throw e;
+ }
+ return create(ident, facet, mode, secure, protocol, encoding, null, adapter, propertyPrefix);
+ }
+
+ Ice.ProxyParseException ex = new Ice.ProxyParseException();
+ ex.str = "malformed proxy `" + s + "'";
+ throw ex;
+ }
+
+ public Reference create(Ice.Identity ident, BasicStream s)
+ {
+ //
+ // Don't read the identity here. Operations calling this
+ // constructor read the identity, and pass it as a parameter.
+ //
+
+ if(ident.name.Length == 0 && ident.category.Length == 0)
+ {
+ return null;
+ }
+
+ //
+ // For compatibility with the old FacetPath.
+ //
+ string[] facetPath = s.readStringSeq();
+ string facet;
+ if(facetPath.Length > 0)
+ {
+ if(facetPath.Length > 1)
+ {
+ throw new Ice.ProxyUnmarshalException();
+ }
+ facet = facetPath[0];
+ }
+ else
+ {
+ facet = "";
+ }
+
+ int mode = (int)s.readByte();
+ if(mode < 0 || mode > (int)Reference.Mode.ModeLast)
+ {
+ throw new Ice.ProxyUnmarshalException();
+ }
+
+ bool secure = s.readBool();
+
+ Ice.ProtocolVersion protocol;
+ Ice.EncodingVersion encoding;
+ if(!s.getReadEncoding().Equals(Ice.Util.Encoding_1_0))
+ {
+ protocol = new Ice.ProtocolVersion();
+ protocol.read__(s);
+ encoding = new Ice.EncodingVersion();
+ encoding.read__(s);
+ }
+ else
+ {
+ protocol = Ice.Util.Protocol_1_0;
+ encoding = Ice.Util.Encoding_1_0;
+ }
+
+ EndpointI[] endpoints = null;
+ string adapterId = "";
+
+ int sz = s.readSize();
+ if(sz > 0)
+ {
+ endpoints = new EndpointI[sz];
+ for(int i = 0; i < sz; i++)
+ {
+ endpoints[i] = instance_.endpointFactoryManager().read(s);
+ }
+ }
+ else
+ {
+ adapterId = s.readString();
+ }
+
+ return create(ident, facet, (Reference.Mode)mode, secure, protocol, encoding, endpoints, adapterId, null);
+ }
+
+ public ReferenceFactory setDefaultRouter(Ice.RouterPrx defaultRouter)
+ {
+ if(_defaultRouter == null ? defaultRouter == null : _defaultRouter.Equals(defaultRouter))
+ {
+ return this;
+ }
+
+ ReferenceFactory factory = new ReferenceFactory(instance_, _communicator);
+ factory._defaultLocator = _defaultLocator;
+ factory._defaultRouter = defaultRouter;
+ return factory;
+ }
+
+ public Ice.RouterPrx getDefaultRouter()
+ {
+ return _defaultRouter;
+ }
+
+ public ReferenceFactory setDefaultLocator(Ice.LocatorPrx defaultLocator)
+ {
+ if(_defaultLocator == null ? defaultLocator == null : _defaultLocator.Equals(defaultLocator))
+ {
+ return this;
+ }
+
+ ReferenceFactory factory = new ReferenceFactory(instance_, _communicator);
+ factory._defaultLocator = defaultLocator;
+ factory._defaultRouter = _defaultRouter;
+ return factory;
+ }
+
+ public Ice.LocatorPrx getDefaultLocator()
+ {
+ return _defaultLocator;
+ }
+
+ //
+ // Only for use by Instance
+ //
+ internal ReferenceFactory(Instance instance, Ice.Communicator communicator)
+ {
+ instance_ = instance;
+ _communicator = communicator;
+ }
+
+ static private readonly string[] _suffixes =
+ {
+ "EndpointSelection",
+ "ConnectionCached",
+ "PreferSecure",
+ "LocatorCacheTimeout",
+ "InvocationTimeout",
+ "Locator",
+ "Router",
+ "CollocationOptimized",
+ "Context\\..*"
+ };
+
+ private void
+ checkForUnknownProperties(String prefix)
+ {
+ //
+ // Do not warn about unknown properties if Ice prefix, ie Ice, Glacier2, etc
+ //
+ for(int i = 0; IceInternal.PropertyNames.clPropNames[i] != null; ++i)
+ {
+ if(prefix.StartsWith(IceInternal.PropertyNames.clPropNames[i] + ".", StringComparison.Ordinal))
+ {
+ return;
+ }
+ }
+
+ List<string> unknownProps = new List<string>();
+ Dictionary<string, string> props
+ = instance_.initializationData().properties.getPropertiesForPrefix(prefix + ".");
+ foreach(String prop in props.Keys)
+ {
+ bool valid = false;
+ for(int i = 0; i < _suffixes.Length; ++i)
+ {
+ string pattern = "^" + Regex.Escape(prefix + ".") + _suffixes[i] + "$";
+ if(new Regex(pattern).Match(prop).Success)
+ {
+ valid = true;
+ break;
+ }
+ }
+
+ if(!valid)
+ {
+ unknownProps.Add(prop);
+ }
+ }
+
+ if(unknownProps.Count != 0)
+ {
+ StringBuilder message = new StringBuilder("found unknown properties for proxy '");
+ message.Append(prefix);
+ message.Append("':");
+ foreach(string s in unknownProps)
+ {
+ message.Append("\n ");
+ message.Append(s);
+ }
+ instance_.initializationData().logger.warning(message.ToString());
+ }
+ }
+
+ private Reference create(Ice.Identity ident,
+ string facet,
+ Reference.Mode mode,
+ bool secure,
+ Ice.ProtocolVersion protocol,
+ Ice.EncodingVersion encoding,
+ EndpointI[] endpoints,
+ string adapterId,
+ string propertyPrefix)
+ {
+ DefaultsAndOverrides defaultsAndOverrides = instance_.defaultsAndOverrides();
+
+ //
+ // Default local proxy options.
+ //
+ LocatorInfo locatorInfo = null;
+ if(_defaultLocator != null)
+ {
+ if(!((Ice.ObjectPrxHelperBase)_defaultLocator).reference__().getEncoding().Equals(encoding))
+ {
+ locatorInfo = instance_.locatorManager().get(
+ (Ice.LocatorPrx)_defaultLocator.ice_encodingVersion(encoding));
+ }
+ else
+ {
+ locatorInfo = instance_.locatorManager().get(_defaultLocator);
+ }
+ }
+ RouterInfo routerInfo = instance_.routerManager().get(_defaultRouter);
+ bool collocOptimized = defaultsAndOverrides.defaultCollocationOptimization;
+ bool cacheConnection = true;
+ bool preferSecure = defaultsAndOverrides.defaultPreferSecure;
+ Ice.EndpointSelectionType endpointSelection = defaultsAndOverrides.defaultEndpointSelection;
+ int locatorCacheTimeout = defaultsAndOverrides.defaultLocatorCacheTimeout;
+ int invocationTimeout = defaultsAndOverrides.defaultInvocationTimeout;
+ Dictionary<string, string> context = null;
+
+ //
+ // Override the defaults with the proxy properties if a property prefix is defined.
+ //
+ if(propertyPrefix != null && propertyPrefix.Length > 0)
+ {
+ Ice.Properties properties = instance_.initializationData().properties;
+
+ //
+ // Warn about unknown properties.
+ //
+ if(properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0)
+ {
+ checkForUnknownProperties(propertyPrefix);
+ }
+
+ string property;
+
+ property = propertyPrefix + ".Locator";
+ Ice.LocatorPrx locator = Ice.LocatorPrxHelper.uncheckedCast(_communicator.propertyToProxy(property));
+ if(locator != null)
+ {
+ if(!((Ice.ObjectPrxHelperBase)locator).reference__().getEncoding().Equals(encoding))
+ {
+ locatorInfo = instance_.locatorManager().get(
+ (Ice.LocatorPrx)locator.ice_encodingVersion(encoding));
+ }
+ else
+ {
+ locatorInfo = instance_.locatorManager().get(locator);
+ }
+ }
+
+ property = propertyPrefix + ".Router";
+ Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(_communicator.propertyToProxy(property));
+ if(router != null)
+ {
+ if(propertyPrefix.EndsWith(".Router", StringComparison.Ordinal))
+ {
+ string s = "`" + property + "=" + properties.getProperty(property) +
+ "': cannot set a router on a router; setting ignored";
+ instance_.initializationData().logger.warning(s);
+ }
+ else
+ {
+ routerInfo = instance_.routerManager().get(router);
+ }
+ }
+
+ property = propertyPrefix + ".CollocationOptimized";
+ collocOptimized = properties.getPropertyAsIntWithDefault(property, collocOptimized ? 1 : 0) > 0;
+
+ property = propertyPrefix + ".ConnectionCached";
+ cacheConnection = properties.getPropertyAsIntWithDefault(property, cacheConnection ? 1 : 0) > 0;
+
+ property = propertyPrefix + ".PreferSecure";
+ preferSecure = properties.getPropertyAsIntWithDefault(property, preferSecure ? 1 : 0) > 0;
+
+ property = propertyPrefix + ".EndpointSelection";
+ if(properties.getProperty(property).Length > 0)
+ {
+ string type = properties.getProperty(property);
+ if(type.Equals("Random"))
+ {
+ endpointSelection = Ice.EndpointSelectionType.Random;
+ }
+ else if(type.Equals("Ordered"))
+ {
+ endpointSelection = Ice.EndpointSelectionType.Ordered;
+ }
+ else
+ {
+ throw new Ice.EndpointSelectionTypeParseException("illegal value `" + type +
+ "'; expected `Random' or `Ordered'");
+ }
+ }
+
+ property = propertyPrefix + ".LocatorCacheTimeout";
+ string val = properties.getProperty(property);
+ if(val.Length > 0)
+ {
+ locatorCacheTimeout = properties.getPropertyAsIntWithDefault(property, locatorCacheTimeout);
+ if(locatorCacheTimeout < -1)
+ {
+ locatorCacheTimeout = -1;
+
+ StringBuilder msg = new StringBuilder("invalid value for ");
+ msg.Append(property);
+ msg.Append(" `");
+ msg.Append(properties.getProperty(property));
+ msg.Append("': defaulting to -1");
+ instance_.initializationData().logger.warning(msg.ToString());
+ }
+ }
+
+ property = propertyPrefix + ".InvocationTimeout";
+ val = properties.getProperty(property);
+ if(val.Length > 0)
+ {
+ invocationTimeout = properties.getPropertyAsIntWithDefault(property, invocationTimeout);
+ if(invocationTimeout < 1 && invocationTimeout != -1)
+ {
+ invocationTimeout = -1;
+
+ StringBuilder msg = new StringBuilder("invalid value for ");
+ msg.Append(property);
+ msg.Append(" `");
+ msg.Append(properties.getProperty(property));
+ msg.Append("': defaulting to -1");
+ instance_.initializationData().logger.warning(msg.ToString());
+ }
+ }
+
+ property = propertyPrefix + ".Context.";
+ Dictionary<string, string> contexts = properties.getPropertiesForPrefix(property);
+ if(contexts.Count != 0)
+ {
+ context = new Dictionary<string, string>();
+ foreach(KeyValuePair<string, string> e in contexts)
+ {
+ context.Add(e.Key.Substring(property.Length), e.Value);
+ }
+ }
+ }
+
+ //
+ // Create new reference
+ //
+ return new RoutableReference(instance_,
+ _communicator,
+ ident,
+ facet,
+ mode,
+ secure,
+ protocol,
+ encoding,
+ endpoints,
+ adapterId,
+ locatorInfo,
+ routerInfo,
+ collocOptimized,
+ cacheConnection,
+ preferSecure,
+ endpointSelection,
+ locatorCacheTimeout,
+ invocationTimeout,
+ context);
+ }
+
+ private Instance instance_;
+ private Ice.Communicator _communicator;
+ private Ice.RouterPrx _defaultRouter;
+ private Ice.LocatorPrx _defaultLocator;
+ }
+
+}
diff --git a/csharp/src/Ice/ReplyStatus.cs b/csharp/src/Ice/ReplyStatus.cs
new file mode 100644
index 00000000000..5ad5c6cb7fe
--- /dev/null
+++ b/csharp/src/Ice/ReplyStatus.cs
@@ -0,0 +1,27 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ sealed class ReplyStatus
+ {
+ public const byte replyOK = 0;
+ public const byte replyUserException = 1;
+ public const byte replyObjectNotExist = 2;
+ public const byte replyFacetNotExist = 3;
+ public const byte replyOperationNotExist = 4;
+ public const byte replyUnknownLocalException = 5;
+ public const byte replyUnknownUserException = 6;
+ public const byte replyUnknownException = 7;
+
+ private ReplyStatus()
+ {
+ }
+ }
+}
diff --git a/csharp/src/Ice/RequestHandler.cs b/csharp/src/Ice/RequestHandler.cs
new file mode 100644
index 00000000000..4593fd35fe3
--- /dev/null
+++ b/csharp/src/Ice/RequestHandler.cs
@@ -0,0 +1,30 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections.Generic;
+using Ice.Instrumentation;
+
+namespace IceInternal
+{
+ public interface CancellationHandler
+ {
+ void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex);
+ }
+
+ public interface RequestHandler : CancellationHandler
+ {
+ RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler);
+
+ bool sendAsyncRequest(ProxyOutgoingAsyncBase @out, out Ice.AsyncCallback cb);
+
+ Reference getReference();
+
+ Ice.ConnectionI getConnection();
+ }
+}
diff --git a/csharp/src/Ice/RequestHandlerFactory.cs b/csharp/src/Ice/RequestHandlerFactory.cs
new file mode 100644
index 00000000000..cc611ccba47
--- /dev/null
+++ b/csharp/src/Ice/RequestHandlerFactory.cs
@@ -0,0 +1,81 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace IceInternal
+{
+ public class RequestHandlerFactory
+ {
+ internal RequestHandlerFactory(Instance instance)
+ {
+ _instance = instance;
+ }
+
+ public RequestHandler
+ getRequestHandler(RoutableReference rf, Ice.ObjectPrxHelperBase proxy)
+ {
+ if(rf.getCollocationOptimized())
+ {
+ Ice.ObjectAdapter adapter = _instance.objectAdapterFactory().findObjectAdapter(proxy);
+ if(adapter != null)
+ {
+ return proxy.setRequestHandler__(new CollocatedRequestHandler(rf, adapter));
+ }
+ }
+
+ bool connect = false;
+ ConnectRequestHandler handler;
+ if(rf.getCacheConnection())
+ {
+ lock(this)
+ {
+ if(!_handlers.TryGetValue(rf, out handler))
+ {
+ handler = new ConnectRequestHandler(rf, proxy);
+ _handlers.Add(rf, handler);
+ connect = true;
+ }
+ }
+ }
+ else
+ {
+ handler = new ConnectRequestHandler(rf, proxy);
+ connect = true;
+ }
+
+ if(connect)
+ {
+ rf.getConnection(handler);
+ }
+ return proxy.setRequestHandler__(handler.connect(proxy));
+ }
+
+ internal void
+ removeRequestHandler(Reference rf, RequestHandler handler)
+ {
+ if(rf.getCacheConnection())
+ {
+ lock(this)
+ {
+ ConnectRequestHandler h;
+ if(_handlers.TryGetValue(rf, out h) && h == handler)
+ {
+ _handlers.Remove(rf);
+ }
+ }
+ }
+ }
+
+ readonly Instance _instance;
+ readonly Dictionary<Reference, ConnectRequestHandler> _handlers =
+ new Dictionary<Reference, ConnectRequestHandler>();
+ }
+}
diff --git a/csharp/src/Ice/ResponseHandler.cs b/csharp/src/Ice/ResponseHandler.cs
new file mode 100644
index 00000000000..e39fbfe5d64
--- /dev/null
+++ b/csharp/src/Ice/ResponseHandler.cs
@@ -0,0 +1,22 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Collections.Generic;
+using Ice.Instrumentation;
+
+namespace IceInternal
+{
+ public interface ResponseHandler
+ {
+ void sendResponse(int requestId, BasicStream os, byte status, bool amd);
+ void sendNoResponse();
+ bool systemException(int requestId, Ice.SystemException ex, bool amd);
+ void invokeException(int requestId, Ice.LocalException ex, int invokeNum, bool amd);
+ };
+}
diff --git a/csharp/src/Ice/RetryQueue.cs b/csharp/src/Ice/RetryQueue.cs
new file mode 100644
index 00000000000..427bceb5f9e
--- /dev/null
+++ b/csharp/src/Ice/RetryQueue.cs
@@ -0,0 +1,154 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Collections.Generic;
+ using System.Diagnostics;
+
+ public class RetryTask : TimerTask, CancellationHandler
+ {
+ public RetryTask(Instance instance, RetryQueue retryQueue, ProxyOutgoingAsyncBase outAsync)
+ {
+ _instance = instance;
+ _retryQueue = retryQueue;
+ _outAsync = outAsync;
+ }
+
+ public void runTimerTask()
+ {
+ _outAsync.retry();
+
+ //
+ // NOTE: this must be called last, destroy() blocks until all task
+ // are removed to prevent the client thread pool to be destroyed
+ // (we still need the client thread pool at this point to call
+ // exception callbacks with CommunicatorDestroyedException).
+ //
+ _retryQueue.remove(this);
+ }
+
+ public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
+ {
+ Debug.Assert(_outAsync == outAsync);
+ if(_retryQueue.cancel(this))
+ {
+ if(_instance.traceLevels().retry >= 1)
+ {
+ string s = "operation retry canceled\n" + ex;
+ _instance.initializationData().logger.trace(_instance.traceLevels().retryCat, s);
+ }
+ Ice.AsyncCallback cb = _outAsync.completed(ex);
+ if(cb != null)
+ {
+ _outAsync.invokeCompletedAsync(cb);
+ }
+ }
+ }
+
+ public void destroy()
+ {
+ try
+ {
+ _outAsync.abort(new Ice.CommunicatorDestroyedException());
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ // Abort can throw if there's no callback, just ignore in this case
+ }
+ }
+
+ private Instance _instance;
+ private RetryQueue _retryQueue;
+ private ProxyOutgoingAsyncBase _outAsync;
+ }
+
+ public class RetryQueue
+ {
+ public RetryQueue(Instance instance)
+ {
+ _instance = instance;
+ }
+
+ public void add(ProxyOutgoingAsyncBase outAsync, int interval)
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+ RetryTask task = new RetryTask(_instance, this, outAsync);
+ outAsync.cancelable(task); // This will throw if the request is canceled.
+ _instance.timer().schedule(task, interval);
+ _requests.Add(task, null);
+ }
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ Dictionary<RetryTask, object> keep = new Dictionary<RetryTask, object>();
+ foreach(RetryTask task in _requests.Keys)
+ {
+ if(_instance.timer().cancel(task))
+ {
+ task.destroy();
+ }
+ else
+ {
+ keep.Add(task, null);
+ }
+ }
+ _requests = keep;
+ _instance = null;
+ while(_requests.Count > 0)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ }
+ }
+
+ public void remove(RetryTask task)
+ {
+ lock(this)
+ {
+ if(_requests.Remove(task))
+ {
+ if(_instance == null && _requests.Count == 0)
+ {
+ // If we are destroying the queue, destroy is probably waiting on the queue to be empty.
+ System.Threading.Monitor.Pulse(this);
+ }
+ }
+ }
+ }
+
+ public bool cancel(RetryTask task)
+ {
+ lock(this)
+ {
+ if(_requests.Remove(task))
+ {
+ if(_instance == null && _requests.Count == 0)
+ {
+ // If we are destroying the queue, destroy is probably waiting on the queue to be empty.
+ System.Threading.Monitor.Pulse(this);
+ }
+ return _instance.timer().cancel(task);
+ }
+ return false;
+ }
+ }
+
+ private Instance _instance;
+ private Dictionary<RetryTask, object> _requests = new Dictionary<RetryTask, object>();
+ }
+}
diff --git a/csharp/src/Ice/RouterInfo.cs b/csharp/src/Ice/RouterInfo.cs
new file mode 100644
index 00000000000..bac2c3e2e9b
--- /dev/null
+++ b/csharp/src/Ice/RouterInfo.cs
@@ -0,0 +1,369 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+
+ public sealed class RouterInfo
+ {
+ public interface GetClientEndpointsCallback
+ {
+ void setEndpoints(EndpointI[] endpoints);
+ void setException(Ice.LocalException ex);
+ }
+
+ public interface AddProxyCallback
+ {
+ void addedProxy();
+ void setException(Ice.LocalException ex);
+ }
+
+ internal RouterInfo(Ice.RouterPrx router)
+ {
+ _router = router;
+
+ Debug.Assert(_router != null);
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ _clientEndpoints = new EndpointI[0];
+ _serverEndpoints = new EndpointI[0];
+ _adapter = null;
+ _identities.Clear();
+ }
+ }
+
+ public override bool Equals(System.Object obj)
+ {
+ if(object.ReferenceEquals(this, obj))
+ {
+ return true;
+ }
+
+ RouterInfo rhs = obj as RouterInfo;
+ return rhs == null ? false : _router.Equals(rhs._router);
+ }
+
+ public override int GetHashCode()
+ {
+ return _router.GetHashCode();
+ }
+
+ public Ice.RouterPrx getRouter()
+ {
+ //
+ // No mutex lock necessary, _router is immutable.
+ //
+ return _router;
+ }
+
+ public EndpointI[] getClientEndpoints()
+ {
+ lock(this)
+ {
+ if(_clientEndpoints != null) // Lazy initialization.
+ {
+ return _clientEndpoints;
+ }
+ }
+
+ return setClientEndpoints(_router.getClientProxy());
+ }
+
+ public void getClientEndpoints(GetClientEndpointsCallback callback)
+ {
+ EndpointI[] clientEndpoints = null;
+ lock(this)
+ {
+ clientEndpoints = _clientEndpoints;
+ }
+
+ if(clientEndpoints != null) // Lazy initialization.
+ {
+ callback.setEndpoints(clientEndpoints);
+ return;
+ }
+
+ _router.begin_getClientProxy().whenCompleted(
+ (Ice.ObjectPrx proxy) =>
+ {
+ callback.setEndpoints(setClientEndpoints(proxy));
+ },
+ (Ice.Exception ex) =>
+ {
+ Debug.Assert(ex is Ice.LocalException);
+ callback.setException((Ice.LocalException)ex);
+ });
+ }
+
+ public EndpointI[] getServerEndpoints()
+ {
+ lock(this)
+ {
+ if(_serverEndpoints != null) // Lazy initialization.
+ {
+ return _serverEndpoints;
+ }
+
+ }
+
+ return setServerEndpoints(_router.getServerProxy());
+ }
+
+ public void addProxy(Ice.ObjectPrx proxy)
+ {
+ Debug.Assert(proxy != null);
+ lock(this)
+ {
+ if(_identities.Contains(proxy.ice_getIdentity()))
+ {
+ //
+ // Only add the proxy to the router if it's not already in our local map.
+ //
+ return;
+ }
+ }
+
+ addAndEvictProxies(proxy, _router.addProxies(new Ice.ObjectPrx[] { proxy }));
+ }
+
+ public bool addProxy(Ice.ObjectPrx proxy, AddProxyCallback callback)
+ {
+ Debug.Assert(proxy != null);
+ lock(this)
+ {
+ if(_identities.Contains(proxy.ice_getIdentity()))
+ {
+ //
+ // Only add the proxy to the router if it's not already in our local map.
+ //
+ return true;
+ }
+ }
+ _router.begin_addProxies(new Ice.ObjectPrx[] { proxy }).whenCompleted(
+ (Ice.ObjectPrx[] evictedProxies) =>
+ {
+ addAndEvictProxies(proxy, evictedProxies);
+ callback.addedProxy();
+ },
+ (Ice.Exception ex) =>
+ {
+ Debug.Assert(ex is Ice.LocalException);
+ callback.setException((Ice.LocalException)ex);
+ });
+
+ return false;
+ }
+
+ public void setAdapter(Ice.ObjectAdapter adapter)
+ {
+ lock(this)
+ {
+ _adapter = adapter;
+ }
+ }
+
+ public Ice.ObjectAdapter getAdapter()
+ {
+ lock(this)
+ {
+ return _adapter;
+ }
+ }
+
+ public void clearCache(Reference @ref)
+ {
+ lock(this)
+ {
+ _identities.Remove(@ref.getIdentity());
+ }
+ }
+
+ private EndpointI[] setClientEndpoints(Ice.ObjectPrx clientProxy)
+ {
+ lock(this)
+ {
+ if(_clientEndpoints == null)
+ {
+ if(clientProxy == null)
+ {
+ //
+ // If getClientProxy() return nil, use router endpoints.
+ //
+ _clientEndpoints = ((Ice.ObjectPrxHelperBase)_router).reference__().getEndpoints();
+ }
+ else
+ {
+ clientProxy = clientProxy.ice_router(null); // The client proxy cannot be routed.
+
+ //
+ // In order to avoid creating a new connection to the
+ // router, we must use the same timeout as the already
+ // existing connection.
+ //
+ if(_router.ice_getConnection() != null)
+ {
+ clientProxy = clientProxy.ice_timeout(_router.ice_getConnection().timeout());
+ }
+
+ _clientEndpoints = ((Ice.ObjectPrxHelperBase)clientProxy).reference__().getEndpoints();
+ }
+ }
+ return _clientEndpoints;
+ }
+ }
+
+ private EndpointI[] setServerEndpoints(Ice.ObjectPrx serverProxy)
+ {
+ lock(this)
+ {
+ if(serverProxy == null)
+ {
+ throw new Ice.NoEndpointException();
+ }
+
+ serverProxy = serverProxy.ice_router(null); // The server proxy cannot be routed.
+ _serverEndpoints = ((Ice.ObjectPrxHelperBase)serverProxy).reference__().getEndpoints();
+ return _serverEndpoints;
+ }
+ }
+
+ private void addAndEvictProxies(Ice.ObjectPrx proxy, Ice.ObjectPrx[] evictedProxies)
+ {
+ lock(this)
+ {
+ //
+ // Check if the proxy hasn't already been evicted by a
+ // concurrent addProxies call. If it's the case, don't
+ // add it to our local map.
+ //
+ int index = _evictedIdentities.IndexOf(proxy.ice_getIdentity());
+ if(index >= 0)
+ {
+ _evictedIdentities.RemoveAt(index);
+ }
+ else
+ {
+ //
+ // If we successfully added the proxy to the router,
+ // we add it to our local map.
+ //
+ _identities.Add(proxy.ice_getIdentity());
+ }
+
+ //
+ // We also must remove whatever proxies the router evicted.
+ //
+ for(int i = 0; i < evictedProxies.Length; ++i)
+ {
+ if(!_identities.Remove(evictedProxies[i].ice_getIdentity()))
+ {
+ //
+ // It's possible for the proxy to not have been
+ // added yet in the local map if two threads
+ // concurrently call addProxies.
+ //
+ _evictedIdentities.Add(evictedProxies[i].ice_getIdentity());
+ }
+ }
+ }
+ }
+
+ private readonly Ice.RouterPrx _router;
+ private EndpointI[] _clientEndpoints;
+ private EndpointI[] _serverEndpoints;
+ private Ice.ObjectAdapter _adapter;
+ private HashSet<Ice.Identity> _identities = new HashSet<Ice.Identity>();
+ private List<Ice.Identity> _evictedIdentities = new List<Ice.Identity>();
+ }
+
+ public sealed class RouterManager
+ {
+ internal RouterManager()
+ {
+ _table = new Dictionary<Ice.RouterPrx, RouterInfo>();
+ }
+
+ internal void destroy()
+ {
+ lock(this)
+ {
+ foreach(RouterInfo i in _table.Values)
+ {
+ i.destroy();
+ }
+ _table.Clear();
+ }
+ }
+
+ //
+ // Returns router info for a given router. Automatically creates
+ // the router info if it doesn't exist yet.
+ //
+ public RouterInfo get(Ice.RouterPrx rtr)
+ {
+ if(rtr == null)
+ {
+ return null;
+ }
+
+ //
+ // The router cannot be routed.
+ //
+ Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null));
+
+ lock(this)
+ {
+ RouterInfo info = null;
+ if(!_table.TryGetValue(router, out info))
+ {
+ info = new RouterInfo(router);
+ _table.Add(router, info);
+ }
+
+ return info;
+ }
+ }
+
+ //
+ // Returns router info for a given router. Automatically creates
+ // the router info if it doesn't exist yet.
+ //
+ public RouterInfo erase(Ice.RouterPrx rtr)
+ {
+ RouterInfo info = null;
+ if(rtr != null)
+ {
+ //
+ // The router cannot be routed.
+ //
+ Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null));
+
+ lock(this)
+ {
+ if(_table.TryGetValue(router, out info))
+ {
+ _table.Remove(router);
+ }
+ }
+ }
+ return info;
+ }
+
+ private Dictionary<Ice.RouterPrx, RouterInfo> _table;
+ }
+
+}
diff --git a/csharp/src/Ice/ServantManager.cs b/csharp/src/Ice/ServantManager.cs
new file mode 100644
index 00000000000..c96d23f9c88
--- /dev/null
+++ b/csharp/src/Ice/ServantManager.cs
@@ -0,0 +1,375 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+using System.Collections.Generic;
+using System.Diagnostics;
+
+public sealed class ServantManager
+{
+ public void addServant(Ice.Object servant, Ice.Identity ident, string facet)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ if(facet == null)
+ {
+ facet = "";
+ }
+
+ Dictionary<string, Ice.Object> m;
+ _servantMapMap.TryGetValue(ident, out m);
+ if(m == null)
+ {
+ _servantMapMap[ident] = (m = new Dictionary<string, Ice.Object>());
+ }
+ else
+ {
+ if(m.ContainsKey(facet))
+ {
+ Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException();
+ ex.id = instance_.identityToString(ident);
+ ex.kindOfObject = "servant";
+ if(facet.Length > 0)
+ {
+ ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, "");
+ }
+ throw ex;
+ }
+ }
+
+ m[facet] = servant;
+ }
+ }
+
+ public void addDefaultServant(Ice.Object servant, string category)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+ Ice.Object obj = null;
+ _defaultServantMap.TryGetValue(category, out obj);
+ if(obj != null)
+ {
+ Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException();
+ ex.kindOfObject = "default servant";
+ ex.id = category;
+ throw ex;
+ }
+
+ _defaultServantMap[category] = servant;
+ }
+ }
+
+ public Ice.Object removeServant(Ice.Identity ident, string facet)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ if(facet == null)
+ {
+ facet = "";
+ }
+
+ Dictionary<string, Ice.Object> m;
+ _servantMapMap.TryGetValue(ident, out m);
+ Ice.Object obj = null;
+ if(m == null || !m.ContainsKey(facet))
+ {
+ Ice.NotRegisteredException ex = new Ice.NotRegisteredException();
+ ex.id = Ice.Util.identityToString(ident);
+ ex.kindOfObject = "servant";
+ if(facet.Length > 0)
+ {
+ ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, "");
+ }
+ throw ex;
+ }
+ obj = m[facet];
+ m.Remove(facet);
+
+ if(m.Count == 0)
+ {
+ _servantMapMap.Remove(ident);
+ }
+ return obj;
+ }
+ }
+
+ public Ice.Object removeDefaultServant(string category)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ Ice.Object obj = null;
+ _defaultServantMap.TryGetValue(category, out obj);
+ if(obj == null)
+ {
+ Ice.NotRegisteredException ex = new Ice.NotRegisteredException();
+ ex.kindOfObject = "default servant";
+ ex.id = category;
+ throw ex;
+ }
+
+ _defaultServantMap.Remove(category);
+ return obj;
+ }
+ }
+
+ public Dictionary<string, Ice.Object> removeAllFacets(Ice.Identity ident)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null);
+
+ Dictionary<string, Ice.Object> m;
+ _servantMapMap.TryGetValue(ident, out m);
+ if(m == null)
+ {
+ Ice.NotRegisteredException ex = new Ice.NotRegisteredException();
+ ex.id = Ice.Util.identityToString(ident);
+ ex.kindOfObject = "servant";
+ throw ex;
+ }
+ _servantMapMap.Remove(ident);
+
+ return m;
+ }
+ }
+
+ public Ice.Object findServant(Ice.Identity ident, string facet)
+ {
+ lock(this)
+ {
+ //
+ // This assert is not valid if the adapter dispatch incoming
+ // requests from bidir connections. This method might be called if
+ // requests are received over the bidir connection after the
+ // adapter was deactivated.
+ //
+ //Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ if(facet == null)
+ {
+ facet = "";
+ }
+
+ Dictionary<string, Ice.Object> m;
+ _servantMapMap.TryGetValue(ident, out m);
+ Ice.Object obj = null;
+ if(m == null)
+ {
+ _defaultServantMap.TryGetValue(ident.category, out obj);
+ if(obj == null)
+ {
+ _defaultServantMap.TryGetValue("", out obj);
+ }
+ }
+ else
+ {
+ m.TryGetValue(facet, out obj);
+ }
+
+ return obj;
+ }
+ }
+
+ public Ice.Object findDefaultServant(string category)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ Ice.Object obj = null;
+ _defaultServantMap.TryGetValue(category, out obj);
+ return obj;
+ }
+ }
+
+ public Dictionary<string, Ice.Object> findAllFacets(Ice.Identity ident)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ Dictionary<string, Ice.Object> m = _servantMapMap[ident];
+ if(m != null)
+ {
+ return new Dictionary<string, Ice.Object>(m);
+ }
+
+ return new Dictionary<string, Ice.Object>();
+ }
+ }
+
+ public bool hasServant(Ice.Identity ident)
+ {
+ lock(this)
+ {
+ //
+ // This assert is not valid if the adapter dispatch incoming
+ // requests from bidir connections. This method might be called if
+ // requests are received over the bidir connection after the
+ // adapter was deactivated.
+ //
+ //
+ //Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ Dictionary<string, Ice.Object> m;
+ _servantMapMap.TryGetValue(ident, out m);
+ if(m == null)
+ {
+ return false;
+ }
+ else
+ {
+ Debug.Assert(m.Count != 0);
+ return true;
+ }
+ }
+ }
+
+ public void addServantLocator(Ice.ServantLocator locator, string category)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ Ice.ServantLocator l;
+ _locatorMap.TryGetValue(category, out l);
+ if(l != null)
+ {
+ Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException();
+ ex.id = IceUtilInternal.StringUtil.escapeString(category, "");
+ ex.kindOfObject = "servant locator";
+ throw ex;
+ }
+
+ _locatorMap[category] = locator;
+ }
+ }
+
+ public Ice.ServantLocator removeServantLocator(string category)
+ {
+ lock(this)
+ {
+ Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ Ice.ServantLocator l;
+ _locatorMap.TryGetValue(category, out l);
+ if(l == null)
+ {
+ Ice.NotRegisteredException ex = new Ice.NotRegisteredException();
+ ex.id = IceUtilInternal.StringUtil.escapeString(category, "");
+ ex.kindOfObject = "servant locator";
+ throw ex;
+ }
+ _locatorMap.Remove(category);
+ return l;
+ }
+ }
+
+ public Ice.ServantLocator findServantLocator(string category)
+ {
+ lock(this)
+ {
+ //
+ // This assert is not valid if the adapter dispatch incoming
+ // requests from bidir connections. This method might be called if
+ // requests are received over the bidir connection after the
+ // adapter was deactivated.
+ //
+ //
+ //Debug.Assert(instance_ != null); // Must not be called after destruction.
+
+ Ice.ServantLocator result;
+ _locatorMap.TryGetValue(category, out result);
+ return result;
+ }
+ }
+
+ //
+ // Only for use by Ice.ObjectAdapterI.
+ //
+ public ServantManager(Instance instance, string adapterName)
+ {
+ instance_ = instance;
+ _adapterName = adapterName;
+ }
+
+ /*
+ ~ServantManager()
+ {
+ //
+ // Don't check whether destroy() has been called. It might have
+ // not been called if the associated object adapter was not
+ // properly deactivated.
+ //
+ //lock(this)
+ //{
+ //IceUtil.Assert.FinalizerAssert(instance_ == null);
+ //}
+ }
+ */
+
+ //
+ // Only for use by Ice.ObjectAdapterI.
+ //
+ public void destroy()
+ {
+ Dictionary<string, Ice.ServantLocator> locatorMap = null;
+ Ice.Logger logger = null;
+ lock(this)
+ {
+ //
+ // If the ServantManager has already been destroyed, we're done.
+ //
+ if(instance_ == null)
+ {
+ return;
+ }
+
+ logger = instance_.initializationData().logger;
+ _servantMapMap.Clear();
+
+ locatorMap = new Dictionary<string, Ice.ServantLocator>(_locatorMap);
+ _locatorMap.Clear();
+ instance_ = null;
+ }
+
+ foreach(KeyValuePair<string, Ice.ServantLocator> p in locatorMap)
+ {
+ Ice.ServantLocator locator = p.Value;
+ try
+ {
+ locator.deactivate(p.Key);
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception during locator deactivation:\n" + "object adapter: `"
+ + _adapterName + "'\n" + "locator category: `" + p.Key + "'\n" + ex;
+ logger.error(s);
+ }
+ }
+ }
+
+ private Instance instance_;
+ private readonly string _adapterName;
+ private Dictionary <Ice.Identity, Dictionary<string, Ice.Object>> _servantMapMap
+ = new Dictionary<Ice.Identity, Dictionary<string, Ice.Object>>();
+ private Dictionary <string, Ice.Object> _defaultServantMap = new Dictionary<string, Ice.Object>();
+ private Dictionary<string, Ice.ServantLocator> _locatorMap = new Dictionary<string, Ice.ServantLocator>();
+}
+
+}
diff --git a/csharp/src/Ice/SliceChecksums.cs b/csharp/src/Ice/SliceChecksums.cs
new file mode 100644
index 00000000000..9c600402643
--- /dev/null
+++ b/csharp/src/Ice/SliceChecksums.cs
@@ -0,0 +1,39 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Reflection;
+
+ public sealed class SliceChecksums
+ {
+ public static Dictionary<string, string> checksums = new Dictionary<string, string>();
+
+#if !COMPACT && !SILVERLIGHT
+ static SliceChecksums()
+ {
+ Type[] types = IceInternal.AssemblyUtil.findTypesWithPrefix("IceInternal.SliceChecksums");
+ foreach(Type t in types)
+ {
+ FieldInfo f = t.GetField("map", BindingFlags.Public | BindingFlags.Static);
+ Hashtable map = (Hashtable)f.GetValue(null);
+ foreach(DictionaryEntry entry in map)
+ {
+ checksums.Add((string)entry.Key, (string)entry.Value);
+ }
+ }
+ }
+#endif
+ }
+
+}
diff --git a/csharp/src/Ice/SlicedData.cs b/csharp/src/Ice/SlicedData.cs
new file mode 100644
index 00000000000..13ba4de17e2
--- /dev/null
+++ b/csharp/src/Ice/SlicedData.cs
@@ -0,0 +1,63 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ /// <summary>
+ /// SlicedData holds the slices of unknown class or exception types.
+ /// </summary>
+ public class SlicedData
+ {
+ public SlicedData(SliceInfo[] slices)
+ {
+ this.slices = slices;
+ }
+
+ /**
+ * The details of each slice, in order of most-derived to least-derived.
+ **/
+ public SliceInfo[] slices;
+ }
+
+ /// <summary>
+ /// SliceInfo encapsulates the details of a slice for an unknown class or exception type.
+ /// </summary>
+ public class SliceInfo
+ {
+ /// <summary>
+ /// The Slice type ID for this slice.
+ /// </summary>
+ public string typeId;
+
+ /// <summary>
+ /// The Slice compact type ID for this slice.
+ /// </summary>
+ public int compactId;
+
+ /// <summary>
+ /// The encoded bytes for this slice, including the leading size integer.
+ /// </summary>
+ public byte[] bytes;
+
+ /// <summary>
+ /// The Ice objects referenced by this slice.
+ /// </summary>
+ public Ice.Object[] objects;
+
+ /// <summary>
+ /// Whether or not the slice contains optional members.
+ /// </summary>
+ public bool hasOptionalMembers;
+
+ /// <summary>
+ /// Whether or not this is the last slice.
+ /// </summary>
+ public bool isLastSlice;
+ }
+}
diff --git a/csharp/src/Ice/SocketOperation.cs b/csharp/src/Ice/SocketOperation.cs
new file mode 100644
index 00000000000..51c71a6b351
--- /dev/null
+++ b/csharp/src/Ice/SocketOperation.cs
@@ -0,0 +1,19 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ public sealed class SocketOperation
+ {
+ public const int None = 0;
+ public const int Read = 1;
+ public const int Write = 2;
+ public const int Connect = 2;
+ }
+}
diff --git a/csharp/src/Ice/Stream.cs b/csharp/src/Ice/Stream.cs
new file mode 100644
index 00000000000..0802c0edcfe
--- /dev/null
+++ b/csharp/src/Ice/Stream.cs
@@ -0,0 +1,705 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Diagnostics;
+
+namespace Ice
+{
+ /// <summary>
+ /// Callback class to inform an application when a Slice class has been unmarshaled
+ /// from an input stream.
+ /// </summary>
+ public interface ReadObjectCallback
+ {
+ /// <summary>
+ /// The Ice run time calls this method when it has fully unmarshaled the state
+ /// of a Slice class.
+ /// </summary>
+ /// <param name="obj">The unmarshaled Slice class.</param>
+ void invoke(Ice.Object obj);
+ }
+
+ /// <summary>
+ /// Interface for input streams used to extract Slice types from a sequence of bytes.
+ /// </summary>
+ public interface InputStream
+ {
+ /// <summary>
+ /// Returns the communicator for this input stream.
+ /// </summary>
+ /// <returns>The communicator.</returns>
+ Communicator communicator();
+
+ /// <summary>
+ /// Determines the behavior of the stream when extracting Slice objects.
+ /// A Slice object is "sliced" when a factory cannot be found for a Slice type ID.
+ /// </summary>
+ /// <param name="slice">If true (the default), slicing is enabled; if false,
+ /// slicing is disabled. If slicing is disabled and the stream encounters a Slice type ID
+ /// during decoding for which no object factory is installed, it raises NoObjectFactoryException.</param>
+ void sliceObjects(bool slice);
+
+ /// <summary>
+ /// Extracts a boolean value from the stream.
+ /// </summary>
+ /// <returns>The extracted boolean.</returns>
+ bool readBool();
+
+ /// <summary>
+ /// Extracts a sequence of boolean values from the stream.
+ /// </summary>
+ /// <returns>The extracted boolean sequence.</returns>
+ bool[] readBoolSeq();
+
+ /// <summary>
+ /// Extracts a byte value from the stream.
+ /// </summary>
+ /// <returns>The extracted byte.</returns>
+ byte readByte();
+
+ /// <summary>
+ /// Extracts a sequence of byte values from the stream.
+ /// </summary>
+ /// <returns>The extracted byte sequence.</returns>
+ byte[] readByteSeq();
+
+ /// <summary>
+ /// Extracts a serializable .NET object from the stream.
+ /// </summary>
+ /// <returns>The deserialized .NET object.</returns>
+ object readSerializable();
+
+ /// <summary>
+ /// Extracts a short value from the stream.
+ /// </summary>
+ /// <returns>The extracted short value.</returns>
+ short readShort();
+
+ /// <summary>
+ /// Extracts a sequence of short values from the stream.
+ /// </summary>
+ /// <returns>The extracted short sequence.</returns>
+ short[] readShortSeq();
+
+ /// <summary>
+ /// Extracts an integer value from the stream.
+ /// </summary>
+ /// <returns>The extracted integer value.</returns>
+ int readInt();
+
+ /// <summary>
+ /// Extracts a sequence of integer values from the stream.
+ /// </summary>
+ /// <returns>The extracted integer sequence.</returns>
+ int[] readIntSeq();
+
+ /// <summary>
+ /// Extracts a long value from the stream.
+ /// </summary>
+ /// <returns>The extracted long value.</returns>
+ long readLong();
+
+ /// <summary>
+ /// Extracts a sequence of long values from the stream.
+ /// </summary>
+ /// <returns>The extracted long sequence.</returns>
+ long[] readLongSeq();
+
+ /// <summary>
+ /// Extracts a float value from the stream.
+ /// </summary>
+ /// <returns>The extracted float value.</returns>
+ float readFloat();
+
+ /// <summary>
+ /// Extracts a sequence of float values from the stream.
+ /// </summary>
+ /// <returns>The extracted float sequence.</returns>
+ float[] readFloatSeq();
+
+ /// <summary>
+ /// Extracts a double value from the stream.
+ /// </summary>
+ /// <returns>The extracted double value.</returns>
+ double readDouble();
+
+ /// <summary>
+ /// Extracts a sequence of double values from the stream.
+ /// </summary>
+ /// <returns>The extracted double sequence.</returns>
+ double[] readDoubleSeq();
+
+ /// <summary>
+ /// Extracts a string from the stream.
+ /// </summary>
+ /// <returns>The extracted double value.</returns>
+ string readString();
+
+ /// <summary>
+ /// Extracts a sequence of strings from the stream.
+ /// </summary>
+ /// <returns>The extracted string sequence.</returns>
+ string[] readStringSeq();
+
+ /// <summary>
+ /// Extracts a size from the stream.
+ /// </summary>
+ /// <returns>The extracted size.</returns>
+ int readSize();
+
+ /// <summary>
+ /// Extracts and check a sequence size from the stream. The check ensures not too much memory will
+ /// be pre-allocated for the sequence.
+ /// </summary>
+ /// <param name="minSize">The minimum size of an element of the sequence.</param>
+ /// <returns>The extracted size.</returns>
+ int readAndCheckSeqSize(int minSize);
+
+ /// <summary>
+ /// Extracts a proxy from the stream.
+ /// </summary>
+ /// <returns>The extracted proxy.</returns>
+ ObjectPrx readProxy();
+
+ /// <summary>
+ /// Extracts the index of a Slice class from the stream.
+ /// </summary>
+ /// <param name="cb">The callback to notify the application when the extracted instance is available.
+ /// The Ice run time extracts Slice classes in stages. The Ice run time calls ReadObjectCallback.invoke
+ /// when the corresponding instance has been fully unmarshaled.</param>
+ void readObject(ReadObjectCallback cb);
+
+ /// <summary>
+ /// Read an enumerated value.
+ /// </summary>
+ ///
+ /// <param name="maxValue">The maximum enumerator value in the definition.</param>
+ /// <returns>The enumerator.</returns>
+ int readEnum(int maxValue);
+
+ /// <summary>
+ /// Extracts a user exception from the stream and throws it.
+ /// </summary>
+ void throwException();
+
+ /// <summary>
+ /// Extracts a user exception from the stream and throws it.
+ /// Extracts a user exception from the stream and throws it, using the supplied
+ /// factory to instantiate a UserExceptionReader.
+ /// </summary>
+ /// <param name="factory">A factory that creates UserExceptionReader instances.</param>
+ void throwException(UserExceptionReaderFactory factory);
+
+ /// <summary>
+ /// Marks the start of an Ice object.
+ /// </summary>
+ void startObject();
+
+ /// <summary>
+ /// Marks the end of an Ice object.
+ /// </summary>
+ /// <param name="preserve">True if unknown slices should be preserved, false otherwise.</param>
+ /// <returns>A SlicedData object containing the preserved slices for unknown types.</returns>
+ SlicedData endObject(bool preserve);
+
+ /// <summary>
+ /// Marks the start of a user exception.
+ /// </summary>
+ void startException();
+
+ /// <summary>
+ /// Marks the end of a user exception.
+ /// </summary>
+ /// <param name="preserve">True if unknown slices should be preserved, false otherwise.</param>
+ /// <returns>A SlicedData object containing the preserved slices for unknown types.</returns>
+ SlicedData endException(bool preserve);
+
+ /// <summary>
+ /// Reads the start of an object or exception slice.
+ /// </summary>
+ /// <returns>The Slice type ID for this slice.</returns>
+ string startSlice();
+
+ /// <summary>
+ /// Indicates that the end of an object or exception slice has been reached.
+ /// </summary>
+ void endSlice();
+
+ /// <summary>
+ /// Skips over an object or exception slice.
+ /// </summary>
+ void skipSlice();
+
+ /// <summary>
+ /// Reads the start of an encapsulation.
+ /// </summary>
+ /// <returns>The encapsulation encoding version.</returns>
+ EncodingVersion startEncapsulation();
+
+ /// <summary>
+ /// Indicates that the end of an encapsulation has been reached.
+ /// </summary>
+ void endEncapsulation();
+
+ /// <summary>
+ /// Skips over an encapsulation.
+ /// </summary>
+ /// <returns>The encapsulation encoding version.</returns>
+ EncodingVersion skipEncapsulation();
+
+ /// <summary>
+ /// Determines the current encoding version.
+ /// </summary>
+ /// <returns>The encoding version.</returns>
+ EncodingVersion getEncoding();
+
+ /// <summary>
+ /// Indicates that unmarshaling is complete, except for any Slice objects. The application must
+ /// call this method only if the stream actually contains Slice objects. Calling readPendingObjects
+ /// triggers the calls to ReadObjectCallback.invoke that inform the application that unmarshaling
+ /// of a Slice object is complete.
+ /// </summary>
+ void readPendingObjects();
+
+ /// <summary>
+ /// Resets the read position of the stream to the beginning.
+ /// </summary>
+ void rewind();
+
+ /// <summary>
+ /// Skips ahead in the stream.
+ /// </summary>
+ /// <param name="sz">The number of bytes to skip.</param>
+ void skip(int sz);
+
+ /// <summary>
+ /// Skips over a size value.
+ /// </summary>
+ void skipSize();
+
+ /// <summary>
+ /// Determine if an optional value is available for reading.
+ /// </summary>
+ /// <param name="tag">The tag associated with the value.</param>
+ /// <param name="format">The optional format for the value.</param>
+ /// <returns>True if the value is present, false otherwise.</returns>
+ bool readOptional(int tag, OptionalFormat format);
+
+ /// <summary>
+ /// Determine the current position in the stream.
+ /// </summary>
+ /// <returns>The current position.</returns>
+ int pos();
+
+ /// <summary>
+ /// Destroys the stream and its associated resources. The application must call destroy prior
+ /// to releasing the last reference to a stream; failure to do so may result in resource leaks.
+ /// </summary>
+ void destroy();
+ }
+
+ /// <summary>
+ /// Interface for output streams used to write Slice types to a sequence
+ /// of bytes.
+ /// </summary>
+ public interface OutputStream
+ {
+ /// <summary>
+ /// Returns the communicator for this output stream.
+ /// </summary>
+ Communicator communicator();
+
+ /// <summary>
+ /// Writes a boolean to the stream.
+ /// </summary>
+ /// <param name="v">The boolean to write to the stream.</param>
+ void writeBool(bool v);
+
+ /// <summary>
+ /// Writes a sequence of booleans to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of booleans to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeBoolSeq(bool[] v);
+
+ /// <summary>
+ /// Writes a byte to the stream.
+ /// </summary>
+ /// <param name="v">The byte to write to the stream.</param>
+ void writeByte(byte v);
+
+ /// <summary>
+ /// Writes a sequence of bytes to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of bytes to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeByteSeq(byte[] v);
+
+ /// <summary>
+ /// Writes a serializable .NET object to the stream.
+ /// </summary>
+ /// <param name="v">The serializable object to write.</param>
+ void writeSerializable(object v);
+
+ /// <summary>
+ /// Writes a short to the stream.
+ /// </summary>
+ /// <param name="v">The short to write to the stream.</param>
+ void writeShort(short v);
+
+ /// <summary>
+ /// Writes a sequence of shorts to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of shorts to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeShortSeq(short[] v);
+
+ /// <summary>
+ /// Writes an integer to the stream.
+ /// </summary>
+ /// <param name="v">The integer to write to the stream.</param>
+ void writeInt(int v);
+
+ /// <summary>
+ /// Writes a sequence of integers to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of integers to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeIntSeq(int[] v);
+
+ /// <summary>
+ /// Writes a long to the stream.
+ /// </summary>
+ /// <param name="v">The long to write to the stream.</param>
+ void writeLong(long v);
+
+ /// <summary>
+ /// Writes a sequence of longs to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of longs to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeLongSeq(long[] v);
+
+ /// <summary>
+ /// Writes a float to the stream.
+ /// </summary>
+ /// <param name="v">The float to write to the stream.</param>
+ void writeFloat(float v);
+
+ /// <summary>
+ /// Writes a sequence of floats to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of floats to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeFloatSeq(float[] v);
+
+ /// <summary>
+ /// Writes a double to the stream.
+ /// </summary>
+ /// <param name="v">The double to write to the stream.</param>
+ void writeDouble(double v);
+
+ /// <summary>
+ /// Writes a sequence of doubles to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of doubles to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeDoubleSeq(double[] v);
+
+ /// <summary>
+ /// Writes a string to the stream.
+ /// </summary>
+ /// <param name="v">The string to write to the stream.
+ /// Passing null causes an empty string to be written to the stream.</param>
+ void writeString(string v);
+
+ /// <summary>
+ /// Writes a sequence of strings to the stream.
+ /// </summary>
+ /// <param name="v">The sequence of strings to write.
+ /// Passing null causes an empty sequence to be written to the stream.</param>
+ void writeStringSeq(string[] v);
+
+ /// <summary>
+ /// Writes a size to the stream.
+ /// </summary>
+ /// <param name="sz">The size to write.</param>
+ void writeSize(int sz);
+
+ /// <summary>
+ /// Writes a proxy to the stream.
+ /// </summary>
+ /// <param name="v">The proxy to write.</param>
+ void writeProxy(ObjectPrx v);
+
+ /// <summary>
+ /// Writes a Slice class to the stream.
+ /// </summary>
+ /// <param name="v">The class to write. This method writes the index of a Slice class; the state of the
+ /// class is written once writePendingObjects is called.</param>
+ void writeObject(Ice.Object v);
+
+ /// <summary>
+ /// Write an enumerated value.
+ /// </summary>
+ /// <param name="v">The enumerator.</param>
+ /// <param name="limit">The number of enumerators in the definition.</param>
+ void writeEnum(int v, int limit);
+
+ /// <summary>
+ /// Writes a user exception to the stream.
+ /// </summary>
+ /// <param name="ex">The user exception to write.</param>
+ void writeException(UserException ex);
+
+ /// <summary>
+ /// Marks the start of an Ice object.
+ /// </summary>
+ /// <param name="slicedData">Preserved slices for this object, or null.</param>
+ void startObject(SlicedData slicedData);
+
+ /// <summary>
+ /// Marks the end of an Ice object.
+ /// </summary>
+ void endObject();
+
+ /// <summary>
+ /// Marks the start of a user exception.
+ /// </summary>
+ /// <param name="slicedData">Preserved slices for this object, or null.</param>
+ void startException(SlicedData slicedData);
+
+ /// <summary>
+ /// Marks the end of a user exception.
+ /// </summary>
+ void endException();
+
+ /// <summary>
+ /// Marks the start of a new slice for an Ice object or user exception.
+ /// </summary>
+ /// <param name="typeId">The Slice type ID corresponding to this slice.</param>
+ /// <param name="compactId">The Slice compact type ID corresponding to this slice.</param>
+ /// <param name="last">True if this is the last slice, false otherwise.</param>
+ void startSlice(string typeId, int compactId, bool last);
+
+ /// <summary>
+ /// Marks the end of a slice for an Ice object or user exception.
+ /// </summary>
+ void endSlice();
+
+ /// <summary>
+ /// Writes the start of an encapsulation to the stream.
+ /// </summary>
+ /// <param name="encoding">The encoding version of the encapsulation.</param>
+ /// <param name="format">The format to use for encoding objects and user exceptions.</param>
+ void startEncapsulation(EncodingVersion encoding, FormatType format);
+
+ /// <summary>
+ /// Writes the start of an encapsulation to the stream.
+ /// </summary>
+ void startEncapsulation();
+
+ /// <summary>
+ /// Ends the previous encapsulation.
+ /// </summary>
+ void endEncapsulation();
+
+ /// <summary>
+ /// Determines the current encoding version.
+ /// </summary>
+ /// <returns>The encoding version.</returns>
+ EncodingVersion getEncoding();
+
+ /// <summary>
+ /// Writes the state of Slice classes whose index was previously
+ /// written with writeObject to the stream.
+ /// </summary>
+ void writePendingObjects();
+
+ /// <summary>
+ /// Write the header information for an optional value.
+ /// </summary>
+ /// <param name="tag">The numeric tag associated with the value.</param>
+ /// <param name="format">The optional format of the value.</param>
+ /// <returns>True if the optional should be written, false otherwise.</returns>
+ bool writeOptional(int tag, OptionalFormat format);
+
+ /// <summary>
+ /// Determines the current position in the stream.
+ /// </summary>
+ /// <returns>The current position.</returns>
+ int pos();
+
+ /// <summary>
+ /// Inserts a fixed 32-bit size value into the stream at the given position.
+ /// </summary>
+ /// <param name="sz">The 32-bit size value.</param>
+ /// <param name="pos">The position at which to write the value.</param>
+ void rewrite(int sz, int pos);
+
+ /// <summary>
+ /// Returns the current position and allocates four bytes for a fixed-length (32-bit)
+ /// size value.
+ /// </summary>
+ /// <returns>The current position.</returns>
+ int startSize();
+
+ /// <summary>
+ /// Computes the amount of data written since the previous call to startSize and
+ /// writes that value at the saved position.
+ /// </summary>
+ /// <param name="pos">The saved position at which to write the size.</param>
+ void endSize(int pos);
+
+ /// <summary>
+ /// Indicates that the marshaling of a request or reply is finished.
+ /// </summary>
+ /// <returns>The byte sequence containing the encoded request or reply.</returns>
+ byte[] finished();
+
+ /// <summary>
+ /// Resets this output stream. This method allows the stream to be reused, to avoid creating
+ /// unnecessary garbage.
+ /// </summary>
+ ///
+ /// <param name="clearBuffer">If true, the stream's internal buffer becomes eligible for
+ /// garbage collection; if false, the stream's internal buffer is retained, to avoid
+ /// creating unnecessary garbage. If retained, the internal buffer may be resized to a smaller
+ /// capacity. Either way, reset resets the stream's writing position to zero.</param>
+ void reset(bool clearBuffer);
+
+ /// <summary>
+ /// Destroys the stream and its associated resources. The application must call destroy prior
+ /// to releasing the last reference to a stream; failure to do so may result in resource leaks.
+ /// </summary>
+ void destroy();
+ }
+
+ /// <summary>
+ /// Base class for extracting objects from an input stream.
+ /// </summary>
+ public abstract class ObjectReader : ObjectImpl
+ {
+ /// <summary>
+ /// Read the object's data members.
+ /// </summary>
+ /// <param name="inStream">The input stream to read from.</param>
+ public abstract void read(InputStream inStream);
+
+ public override void write__(IceInternal.BasicStream os)
+ {
+ Debug.Assert(false);
+ }
+
+ public override void read__(IceInternal.BasicStream istr)
+ {
+ InputStream stream = (InputStream)istr.closure();
+ read(stream);
+ }
+ }
+
+ /// <summary>
+ /// Base class for writing objects to an output stream.
+ /// </summary>
+ public abstract class ObjectWriter : ObjectImpl
+ {
+ /// <summary>
+ /// Writes the state of this Slice class to an output stream.
+ /// </summary>
+ /// <param name="outStream">The stream to write to.</param>
+ public abstract void write(OutputStream outStream);
+
+ public override void write__(IceInternal.BasicStream os)
+ {
+ OutputStream stream = (OutputStream)os.closure();
+ write(stream);
+ }
+
+ public override void read__(IceInternal.BasicStream istr)
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ public abstract class UserExceptionReader : UserException
+ {
+ protected UserExceptionReader(Communicator communicator)
+ {
+ communicator_ = communicator;
+ }
+
+ public abstract void read(Ice.InputStream istr);
+
+ public override void write__(IceInternal.BasicStream ostr)
+ {
+ Debug.Assert(false);
+ }
+
+ public override void read__(IceInternal.BasicStream istr)
+ {
+ InputStream stream = (InputStream)istr.closure();
+ Debug.Assert(stream != null);
+ read(stream);
+ }
+
+ public override void write__(Ice.OutputStream ostr)
+ {
+ Debug.Assert(false);
+ }
+
+ public override void read__(Ice.InputStream istr)
+ {
+ read(istr);
+ }
+
+ protected Communicator communicator_;
+ }
+
+ public interface UserExceptionReaderFactory
+ {
+ void createAndThrow(string typeId);
+ }
+
+ public abstract class UserExceptionWriter : UserException
+ {
+ public UserExceptionWriter(Communicator communicator)
+ {
+ communicator_ = communicator;
+ }
+
+ public abstract void write(OutputStream os);
+
+ public override void write__(IceInternal.BasicStream os)
+ {
+ OutputStream stream = (OutputStream)os.closure();
+ if(stream == null)
+ {
+ stream = new OutputStreamI(communicator_, os);
+ }
+ write(stream);
+ }
+
+ public override void read__(IceInternal.BasicStream istr)
+ {
+ Debug.Assert(false);
+ }
+
+ public override void write__(Ice.OutputStream ostr)
+ {
+ write(ostr);
+ }
+
+ public override void read__(Ice.InputStream istr)
+ {
+ Debug.Assert(false);
+ }
+
+ protected Communicator communicator_;
+ }
+}
diff --git a/csharp/src/Ice/StreamI.cs b/csharp/src/Ice/StreamI.cs
new file mode 100644
index 00000000000..a9f528c8c8b
--- /dev/null
+++ b/csharp/src/Ice/StreamI.cs
@@ -0,0 +1,570 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ public class InputStreamI : InputStream
+ {
+ public InputStreamI(Communicator communicator, byte[] data, bool copyData)
+ {
+ _communicator = communicator;
+ IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
+ initialize(instance, data, instance.defaultsAndOverrides().defaultEncoding, copyData);
+ }
+
+ public InputStreamI(Communicator communicator, byte[] data, EncodingVersion v, bool copyData)
+ {
+ _communicator = communicator;
+ initialize(IceInternal.Util.getInstance(communicator), data, v, copyData);
+ }
+
+ private void initialize(IceInternal.Instance instance, byte[] data, EncodingVersion v, bool copyData)
+ {
+ if(copyData)
+ {
+ _is = new IceInternal.BasicStream(instance, v);
+ _is.resize(data.Length, true);
+ IceInternal.Buffer buf = _is.getBuffer();
+ buf.b.position(0);
+ buf.b.put(data);
+ buf.b.position(0);
+ }
+ else
+ {
+ _is = new IceInternal.BasicStream(instance, v, data);
+ }
+ _is.closure(this);
+ }
+
+ public Communicator communicator()
+ {
+ return _communicator;
+ }
+
+ public void sliceObjects(bool slice)
+ {
+ _is.sliceObjects(slice);
+ }
+
+ public bool readBool()
+ {
+ return _is.readBool();
+ }
+
+ public bool[] readBoolSeq()
+ {
+ return _is.readBoolSeq();
+ }
+
+ public byte readByte()
+ {
+ return _is.readByte();
+ }
+
+ public byte[] readByteSeq()
+ {
+ return _is.readByteSeq();
+ }
+
+ public object readSerializable()
+ {
+ return _is.readSerializable();
+ }
+
+ public short readShort()
+ {
+ return _is.readShort();
+ }
+
+ public short[] readShortSeq()
+ {
+ return _is.readShortSeq();
+ }
+
+ public int readInt()
+ {
+ return _is.readInt();
+ }
+
+ public int[] readIntSeq()
+ {
+ return _is.readIntSeq();
+ }
+
+ public long readLong()
+ {
+ return _is.readLong();
+ }
+
+ public long[] readLongSeq()
+ {
+ return _is.readLongSeq();
+ }
+
+ public float readFloat()
+ {
+ return _is.readFloat();
+ }
+
+ public float[] readFloatSeq()
+ {
+ return _is.readFloatSeq();
+ }
+
+ public double readDouble()
+ {
+ return _is.readDouble();
+ }
+
+ public double[] readDoubleSeq()
+ {
+ return _is.readDoubleSeq();
+ }
+
+ public string readString()
+ {
+ return _is.readString();
+ }
+
+ public string[] readStringSeq()
+ {
+ return _is.readStringSeq();
+ }
+
+ public int readSize()
+ {
+ return _is.readSize();
+ }
+
+ public int readAndCheckSeqSize(int minSize)
+ {
+ return _is.readAndCheckSeqSize(minSize);
+ }
+
+ public ObjectPrx readProxy()
+ {
+ return _is.readProxy();
+ }
+
+ private class Patcher<T> : IceInternal.Patcher
+ {
+ public Patcher(ReadObjectCallback cb) : base("unknown")
+ {
+ _cb = cb;
+ }
+
+ public override void patch(Ice.Object v)
+ {
+ _cb.invoke(v);
+ }
+
+ ReadObjectCallback _cb;
+ }
+
+ public void readObject(ReadObjectCallback cb)
+ {
+ _is.readObject(new Patcher<Ice.Object>(cb));
+ }
+
+ public int readEnum(int maxValue)
+ {
+ return _is.readEnum(maxValue);
+ }
+
+ public void throwException()
+ {
+ _is.throwException(null);
+ }
+
+ internal class UserExceptionFactoryI : IceInternal.UserExceptionFactory
+ {
+ internal UserExceptionFactoryI(UserExceptionReaderFactory factory)
+ {
+ _factory = factory;
+ }
+
+ public void createAndThrow(string id)
+ {
+ _factory.createAndThrow(id);
+ }
+
+ public void destroy()
+ {
+ }
+
+ private UserExceptionReaderFactory _factory;
+ }
+
+ public void throwException(UserExceptionReaderFactory factory)
+ {
+ _is.throwException(new UserExceptionFactoryI(factory));
+ }
+
+ public void startObject()
+ {
+ _is.startReadObject();
+ }
+
+ public SlicedData endObject(bool preserve)
+ {
+ return _is.endReadObject(preserve);
+ }
+
+ public void startException()
+ {
+ _is.startReadException();
+ }
+
+ public SlicedData endException(bool preserve)
+ {
+ return _is.endReadException(preserve);
+ }
+
+ public string startSlice()
+ {
+ return _is.startReadSlice();
+ }
+
+ public void endSlice()
+ {
+ _is.endReadSlice();
+ }
+
+ public void skipSlice()
+ {
+ _is.skipSlice();
+ }
+
+ public EncodingVersion startEncapsulation()
+ {
+ return _is.startReadEncaps();
+ }
+
+ public void endEncapsulation()
+ {
+ _is.endReadEncapsChecked();
+ }
+
+ public EncodingVersion skipEncapsulation()
+ {
+ return _is.skipEncaps();
+ }
+
+ public EncodingVersion getEncoding()
+ {
+ return _is.getReadEncoding();
+ }
+
+ public void readPendingObjects()
+ {
+ _is.readPendingObjects();
+ }
+
+ public void rewind()
+ {
+ _is.clear();
+ _is.getBuffer().b.position(0);
+ }
+
+ public void skip(int sz)
+ {
+ _is.skip(sz);
+ }
+
+ public void skipSize()
+ {
+ _is.skipSize();
+ }
+
+ public bool readOptional(int tag, OptionalFormat format)
+ {
+ return _is.readOpt(tag, format);
+ }
+
+ public int pos()
+ {
+ return _is.pos();
+ }
+
+ public void destroy()
+ {
+ if(_is != null)
+ {
+ _is = null;
+ }
+ }
+
+ private Communicator _communicator;
+ private IceInternal.BasicStream _is;
+ }
+
+ public class OutputStreamI : OutputStream
+ {
+ public OutputStreamI(Communicator communicator)
+ {
+ _communicator = communicator;
+
+ IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
+ _os = new IceInternal.BasicStream(instance, instance.defaultsAndOverrides().defaultEncoding);
+ _os.closure(this);
+ }
+
+ public OutputStreamI(Communicator communicator, EncodingVersion v)
+ {
+ _communicator = communicator;
+
+ IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
+ _os = new IceInternal.BasicStream(instance, v);
+ _os.closure(this);
+ }
+
+ public OutputStreamI(Communicator communicator, IceInternal.BasicStream os)
+ {
+ _communicator = communicator;
+ _os = os;
+ _os.closure(this);
+ }
+
+ public Communicator communicator()
+ {
+ return _communicator;
+ }
+
+ public void writeBool(bool v)
+ {
+ _os.writeBool(v);
+ }
+
+ public void writeBoolSeq(bool[] v)
+ {
+ _os.writeBoolSeq(v);
+ }
+
+ public void writeByte(byte v)
+ {
+ _os.writeByte(v);
+ }
+
+ public void writeByteSeq(byte[] v)
+ {
+ _os.writeByteSeq(v);
+ }
+
+ public void writeSerializable(object v)
+ {
+ _os.writeSerializable(v);
+ }
+
+ public void writeShort(short v)
+ {
+ _os.writeShort(v);
+ }
+
+ public void writeShortSeq(short[] v)
+ {
+ _os.writeShortSeq(v);
+ }
+
+ public void writeInt(int v)
+ {
+ _os.writeInt(v);
+ }
+
+ public void writeIntSeq(int[] v)
+ {
+ _os.writeIntSeq(v);
+ }
+
+ public void writeLong(long v)
+ {
+ _os.writeLong(v);
+ }
+
+ public void writeLongSeq(long[] v)
+ {
+ _os.writeLongSeq(v);
+ }
+
+ public void writeFloat(float v)
+ {
+ _os.writeFloat(v);
+ }
+
+ public void writeFloatSeq(float[] v)
+ {
+ _os.writeFloatSeq(v);
+ }
+
+ public void writeDouble(double v)
+ {
+ _os.writeDouble(v);
+ }
+
+ public void writeDoubleSeq(double[] v)
+ {
+ _os.writeDoubleSeq(v);
+ }
+
+ public void writeString(string v)
+ {
+ _os.writeString(v);
+ }
+
+ public void writeStringSeq(string[] v)
+ {
+ _os.writeStringSeq(v);
+ }
+
+ public void writeSize(int sz)
+ {
+ if(sz < 0)
+ {
+ throw new MarshalException();
+ }
+
+ _os.writeSize(sz);
+ }
+
+ public void writeProxy(ObjectPrx v)
+ {
+ _os.writeProxy(v);
+ }
+
+ public void writeObject(Ice.Object v)
+ {
+ _os.writeObject(v);
+ }
+
+ public void writeEnum(int v, int maxValue)
+ {
+ _os.writeEnum(v, maxValue);
+ }
+
+ public void writeException(UserException v)
+ {
+ _os.writeUserException(v);
+ }
+
+ public void startObject(SlicedData slicedData)
+ {
+ _os.startWriteObject(slicedData);
+ }
+
+ public void endObject()
+ {
+ _os.endWriteObject();
+ }
+
+ public void startException(SlicedData slicedData)
+ {
+ _os.startWriteException(slicedData);
+ }
+
+ public void endException()
+ {
+ _os.endWriteException();
+ }
+
+ public void startSlice(string typeId, int compactId, bool last)
+ {
+ _os.startWriteSlice(typeId, compactId, last);
+ }
+
+ public void endSlice()
+ {
+ _os.endWriteSlice();
+ }
+
+ public void startEncapsulation(EncodingVersion encoding, FormatType format)
+ {
+ _os.startWriteEncaps(encoding, format);
+ }
+
+ public void startEncapsulation()
+ {
+ _os.startWriteEncaps();
+ }
+
+ public void endEncapsulation()
+ {
+ _os.endWriteEncapsChecked();
+ }
+
+ public EncodingVersion getEncoding()
+ {
+ return _os.getWriteEncoding();
+ }
+
+ public void writePendingObjects()
+ {
+ _os.writePendingObjects();
+ }
+
+ public bool writeOptional(int tag, OptionalFormat format)
+ {
+ return _os.writeOpt(tag, format);
+ }
+
+ public int pos()
+ {
+ return _os.pos();
+ }
+
+ public void rewrite(int sz, int pos)
+ {
+ _os.rewriteInt(sz, pos);
+ }
+
+ public int startSize()
+ {
+ return _os.startSize();
+ }
+
+ public void endSize(int pos)
+ {
+ _os.endSize(pos);
+ }
+
+ public byte[] finished()
+ {
+ IceInternal.Buffer buf = _os.prepareWrite();
+ byte[] result = new byte[buf.b.limit()];
+ buf.b.get(result);
+
+ return result;
+ }
+
+ public void reset(bool clearBuffer)
+ {
+ _os.clear();
+
+ IceInternal.Buffer buf = _os.getBuffer();
+ if(clearBuffer)
+ {
+ buf.clear();
+ }
+ else
+ {
+ buf.reset();
+ }
+ buf.b.position(0);
+ }
+
+ public void destroy()
+ {
+ if(_os != null)
+ {
+ _os = null;
+ }
+ }
+
+ private Communicator _communicator;
+ private IceInternal.BasicStream _os;
+ }
+}
diff --git a/csharp/src/Ice/StreamSocket.cs b/csharp/src/Ice/StreamSocket.cs
new file mode 100644
index 00000000000..10c1f6488dc
--- /dev/null
+++ b/csharp/src/Ice/StreamSocket.cs
@@ -0,0 +1,644 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+//
+// .NET and Silverlight use the new socket asynchronous APIs whereas
+// the compact framework and mono still use the old Begin/End APIs.
+//
+#if !COMPACT && !__MonoCS__ && !UNITY
+#define ICE_SOCKET_ASYNC_API
+#endif
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Net.Sockets;
+
+ public sealed class StreamSocket
+ {
+ public StreamSocket(ProtocolInstance instance, NetworkProxy proxy, EndPoint addr, EndPoint sourceAddr)
+ {
+ _instance = instance;
+ _proxy = proxy;
+ _addr = addr;
+ _sourceAddr = sourceAddr;
+ _fd = Network.createSocket(false, (_proxy != null ? _proxy.getAddress() : _addr).AddressFamily);
+ _state = StateNeedConnect;
+
+ init();
+ }
+
+ public StreamSocket(ProtocolInstance instance, Socket fd)
+ {
+ _instance = instance;
+ _fd = fd;
+ _state = StateConnected;
+ _desc = IceInternal.Network.fdToString(_fd);
+ init();
+ }
+
+#if !SILVERLIGHT
+ public void setBlock(bool block)
+ {
+ Network.setBlock(_fd, block);
+ }
+#endif
+
+ public int connect(Buffer readBuffer, Buffer writeBuffer, ref bool moreData)
+ {
+ if(_state == StateNeedConnect)
+ {
+ _state = StateConnectPending;
+ return SocketOperation.Connect;
+ }
+ else if(_state <= StateConnectPending)
+ {
+#if ICE_SOCKET_ASYNC_API
+ if(_writeEventArgs.SocketError != SocketError.Success)
+ {
+ SocketException ex = new SocketException((int)_writeEventArgs.SocketError);
+ if(Network.connectionRefused(ex))
+ {
+ throw new Ice.ConnectionRefusedException(ex);
+ }
+ else
+ {
+ throw new Ice.ConnectFailedException(ex);
+ }
+ }
+#else
+ Network.doFinishConnectAsync(_fd, _writeResult);
+ _writeResult = null;
+#endif
+ _desc = Network.fdToString(_fd, _proxy, _addr);
+ _state = _proxy != null ? StateProxyWrite : StateConnected;
+ }
+
+ if(_state == StateProxyWrite)
+ {
+ _proxy.beginWrite(_addr, writeBuffer);
+ return SocketOperation.Write;
+ }
+ else if(_state == StateProxyRead)
+ {
+ _proxy.beginRead(readBuffer);
+ return SocketOperation.Read;
+ }
+ else if(_state == StateProxyConnected)
+ {
+ _proxy.finish(readBuffer, writeBuffer);
+
+ readBuffer.clear();
+ writeBuffer.clear();
+
+ _state = StateConnected;
+ }
+
+ Debug.Assert(_state == StateConnected);
+ return SocketOperation.None;
+ }
+
+ public bool isConnected()
+ {
+ return _state == StateConnected;
+ }
+
+ public Socket fd()
+ {
+ return _fd;
+ }
+
+ public int getSendPacketSize(int length)
+ {
+ return _maxSendPacketSize > 0 ? System.Math.Min(length, _maxSendPacketSize) : length;
+ }
+
+ public int getRecvPacketSize(int length)
+ {
+ return _maxRecvPacketSize > 0 ? System.Math.Min(length, _maxRecvPacketSize) : length;
+ }
+
+ public void setBufferSize(int rcvSize, int sndSize)
+ {
+ Network.setTcpBufSize(_fd, rcvSize, sndSize, _instance);
+ }
+
+ public int read(Buffer buf)
+ {
+ if(_state == StateProxyRead)
+ {
+ while(true)
+ {
+ int ret = read(buf.b);
+ if(ret == 0)
+ {
+ return SocketOperation.Read;
+ }
+
+ _state = toState(_proxy.endRead(buf));
+ if(_state != StateProxyRead)
+ {
+ return SocketOperation.None;
+ }
+ }
+ }
+ read(buf.b);
+ return buf.b.hasRemaining() ? SocketOperation.Read : SocketOperation.None;
+ }
+
+ public int write(Buffer buf)
+ {
+ if(_state == StateProxyWrite)
+ {
+ while(true)
+ {
+ int ret = write(buf.b);
+ if(ret == 0)
+ {
+ return SocketOperation.Write;
+ }
+ _state = toState(_proxy.endWrite(buf));
+ if(_state != StateProxyWrite)
+ {
+ return SocketOperation.None;
+ }
+ }
+ }
+ write(buf.b);
+ return buf.b.hasRemaining() ? SocketOperation.Write : SocketOperation.None;
+ }
+
+ public bool startRead(Buffer buf, AsyncCallback callback, object state)
+ {
+#if ICE_SOCKET_ASYNC_API
+ Debug.Assert(_fd != null && _readEventArgs != null);
+#else
+ Debug.Assert(_fd != null && _readResult == null);
+#endif
+
+ int packetSize = getRecvPacketSize(buf.b.remaining());
+ try
+ {
+ _readCallback = callback;
+#if ICE_SOCKET_ASYNC_API
+ _readEventArgs.UserToken = state;
+ _readEventArgs.SetBuffer(buf.b.rawBytes(), buf.b.position(), packetSize);
+ return !_fd.ReceiveAsync(_readEventArgs);
+#else
+ _readResult = _fd.BeginReceive(buf.b.rawBytes(), buf.b.position(), packetSize, SocketFlags.None,
+ readCompleted, state);
+ return _readResult.CompletedSynchronously;
+#endif
+ }
+ catch(SocketException ex)
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public void finishRead(Buffer buf)
+ {
+ if(_fd == null) // Transceiver was closed
+ {
+#if !ICE_SOCKET_ASYNC_API
+ _readResult = null;
+#endif
+ return;
+ }
+
+#if ICE_SOCKET_ASYNC_API
+ Debug.Assert(_fd != null && _readEventArgs != null);
+#else
+ Debug.Assert(_fd != null && _readResult != null);
+#endif
+ try
+ {
+#if ICE_SOCKET_ASYNC_API
+ if(_readEventArgs.SocketError != SocketError.Success)
+ {
+ throw new SocketException((int)_readEventArgs.SocketError);
+ }
+ int ret = _readEventArgs.BytesTransferred;
+#else
+ int ret = _fd.EndReceive(_readResult);
+ _readResult = null;
+#endif
+ if(ret == 0)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+
+ Debug.Assert(ret > 0);
+ buf.b.position(buf.b.position() + ret);
+
+ if(_state == StateProxyRead)
+ {
+ _state = toState(_proxy.endRead(buf));
+ }
+ }
+ catch(SocketException ex)
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ throw new Ice.SocketException(ex);
+ }
+ catch(ObjectDisposedException ex)
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ }
+
+ public bool startWrite(Buffer buf, AsyncCallback callback, object state, out bool completed)
+ {
+#if ICE_SOCKET_ASYNC_API
+ Debug.Assert(_fd != null && _writeEventArgs != null);
+#else
+ Debug.Assert(_fd != null && _writeResult == null);
+#endif
+
+ if(_state == StateConnectPending)
+ {
+ completed = false;
+ _writeCallback = callback;
+ try
+ {
+ EndPoint addr = _proxy != null ? _proxy.getAddress() : _addr;
+#if ICE_SOCKET_ASYNC_API
+ _writeEventArgs.RemoteEndPoint = addr;
+ _writeEventArgs.UserToken = state;
+ return !_fd.ConnectAsync(_writeEventArgs);
+#else
+ _writeResult = Network.doConnectAsync(_fd, addr, _sourceAddr, callback, state);
+ return _writeResult.CompletedSynchronously;
+#endif
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ int packetSize = getSendPacketSize(buf.b.remaining());
+ try
+ {
+ _writeCallback = callback;
+#if ICE_SOCKET_ASYNC_API
+ _writeEventArgs.UserToken = state;
+ _writeEventArgs.SetBuffer(buf.b.rawBytes(), buf.b.position(), packetSize);
+ bool completedSynchronously = !_fd.SendAsync(_writeEventArgs);
+#else
+ _writeResult = _fd.BeginSend(buf.b.rawBytes(), buf.b.position(), packetSize, SocketFlags.None,
+ writeCompleted, state);
+ bool completedSynchronously = _writeResult.CompletedSynchronously;
+#endif
+ completed = packetSize == buf.b.remaining();
+ return completedSynchronously;
+ }
+ catch(SocketException ex)
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ throw new Ice.SocketException(ex);
+ }
+ catch(ObjectDisposedException ex)
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ }
+
+ public void finishWrite(Buffer buf)
+ {
+ if(_fd == null) // Transceiver was closed
+ {
+ if(buf.size() - buf.b.position() < _maxSendPacketSize)
+ {
+ buf.b.position(buf.b.limit()); // Assume all the data was sent for at-most-once semantics.
+ }
+#if !ICE_SOCKET_ASYNC_API
+ _writeResult = null;
+#endif
+ return;
+ }
+
+#if ICE_SOCKET_ASYNC_API
+ Debug.Assert(_fd != null && _writeEventArgs != null);
+#else
+ Debug.Assert(_fd != null && _writeResult != null);
+#endif
+
+ if(_state < StateConnected && _state != StateProxyWrite)
+ {
+ return;
+ }
+
+ try
+ {
+#if ICE_SOCKET_ASYNC_API
+ if(_writeEventArgs.SocketError != SocketError.Success)
+ {
+ throw new SocketException((int)_writeEventArgs.SocketError);
+ }
+ int ret = _writeEventArgs.BytesTransferred;
+#else
+ int ret = _fd.EndSend(_writeResult);
+ _writeResult = null;
+#endif
+ if(ret == 0)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+
+ Debug.Assert(ret > 0);
+ buf.b.position(buf.b.position() + ret);
+
+ if(_state == StateProxyWrite)
+ {
+ _state = toState(_proxy.endWrite(buf));
+ }
+ }
+ catch(SocketException ex)
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+
+ throw new Ice.SocketException(ex);
+ }
+ catch(ObjectDisposedException ex)
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ }
+
+ public void close()
+ {
+ Debug.Assert(_fd != null);
+ try
+ {
+ _fd.Close();
+ }
+ catch(SocketException ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+ finally
+ {
+ _fd = null;
+ }
+ }
+
+ public void destroy()
+ {
+#if ICE_SOCKET_ASYNC_API
+ Debug.Assert(_readEventArgs != null && _writeEventArgs != null);
+ _readEventArgs.Dispose();
+ _writeEventArgs.Dispose();
+#endif
+ }
+
+ public override string ToString()
+ {
+ return _desc;
+ }
+
+ private int read(ByteBuffer buf)
+ {
+ Debug.Assert(_fd != null);
+
+#if COMPACT || SILVERLIGHT
+ //
+ // Silverlight and the Compact .NET Framework don't
+ // support the use of synchronous socket operations on a
+ // non-blocking socket. Returning 0 here forces the caller
+ // to schedule an asynchronous operation.
+ //
+ return 0;
+#else
+ int read = 0;
+ while(buf.hasRemaining())
+ {
+ try
+ {
+ int ret = _fd.Receive(buf.rawBytes(), buf.position(), buf.remaining(), SocketFlags.None);
+ if(ret == 0)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ read += ret;
+ buf.position(buf.position() + ret);
+ }
+ catch(SocketException ex)
+ {
+ if(Network.wouldBlock(ex))
+ {
+ return read;
+ }
+ else if(Network.interrupted(ex))
+ {
+ continue;
+ }
+ else if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+
+ throw new Ice.SocketException(ex);
+ }
+ }
+ return read;
+#endif
+ }
+
+ private int write(ByteBuffer buf)
+ {
+ Debug.Assert(_fd != null);
+
+#if COMPACT || SILVERLIGHT
+ //
+ // Silverlight and the Compact .NET Frameworks don't
+ // support the use of synchronous socket operations on a
+ // non-blocking socket. Returning 0 here forces the caller
+ // to schedule an asynchronous operation.
+ //
+ return 0;
+#else
+
+ int packetSize = buf.remaining();
+ if(AssemblyUtil.platform_ == AssemblyUtil.Platform.Windows)
+ {
+ //
+ // On Windows, limiting the buffer size is important to prevent
+ // poor throughput performances when transfering large amount of
+ // data. See Microsoft KB article KB823764.
+ //
+ if(_maxSendPacketSize > 0 && packetSize > _maxSendPacketSize / 2)
+ {
+ packetSize = _maxSendPacketSize / 2;
+ }
+ }
+
+ int sent = 0;
+ while(buf.hasRemaining())
+ {
+ try
+ {
+ int ret = _fd.Send(buf.rawBytes(), buf.position(), packetSize, SocketFlags.None);
+ Debug.Assert(ret > 0);
+
+ sent += ret;
+ buf.position(buf.position() + ret);
+ if(packetSize > buf.remaining())
+ {
+ packetSize = buf.remaining();
+ }
+ }
+ catch(SocketException ex)
+ {
+ if(Network.wouldBlock(ex))
+ {
+ return sent;
+ }
+ else if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ throw new Ice.SocketException(ex);
+ }
+ }
+ return sent;
+#endif
+ }
+
+#if ICE_SOCKET_ASYNC_API
+ private void ioCompleted(object sender, SocketAsyncEventArgs e)
+ {
+ switch (e.LastOperation)
+ {
+ case SocketAsyncOperation.Receive:
+ _readCallback(e.UserToken);
+ break;
+ case SocketAsyncOperation.Send:
+ case SocketAsyncOperation.Connect:
+ _writeCallback(e.UserToken);
+ break;
+ default:
+ throw new ArgumentException("The last operation completed on the socket was not a receive or send");
+ }
+ }
+#else
+ private void readCompleted(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ _readCallback(result.AsyncState);
+ }
+ }
+
+ private void writeCompleted(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ _writeCallback(result.AsyncState);
+ }
+ }
+#endif
+
+ private void init()
+ {
+#if !SILVERLIGHT
+ Network.setBlock(_fd, false);
+#endif
+ Network.setTcpBufSize(_fd, _instance);
+
+#if ICE_SOCKET_ASYNC_API
+ _readEventArgs = new SocketAsyncEventArgs();
+ _readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
+
+ _writeEventArgs = new SocketAsyncEventArgs();
+ _writeEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
+# if SILVERLIGHT
+ String policy = _instance.properties().getProperty("Ice.ClientAccessPolicyProtocol");
+ if(policy.Equals("Http"))
+ {
+ _readEventArgs.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Http;
+ _writeEventArgs.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Http;
+ }
+ else if(!String.IsNullOrEmpty(policy))
+ {
+ _instance.logger().warning("Ignoring invalid Ice.ClientAccessPolicyProtocol value `" + policy + "'");
+ }
+# endif
+#endif
+
+ //
+ // For timeouts to work properly, we need to receive/send
+ // the data in several chunks. Otherwise, we would only be
+ // notified when all the data is received/written. The
+ // connection timeout could easily be triggered when
+ // receiging/sending large messages.
+ //
+ _maxSendPacketSize = System.Math.Max(512, Network.getSendBufferSize(_fd));
+ _maxRecvPacketSize = System.Math.Max(512, Network.getRecvBufferSize(_fd));
+ }
+
+ private int toState(int operation)
+ {
+ switch(operation)
+ {
+ case SocketOperation.Read:
+ return StateProxyRead;
+ case SocketOperation.Write:
+ return StateProxyWrite;
+ default:
+ return StateProxyConnected;
+ }
+ }
+
+ private readonly ProtocolInstance _instance;
+ private readonly IceInternal.NetworkProxy _proxy;
+ private readonly EndPoint _addr;
+ private readonly EndPoint _sourceAddr;
+
+ private Socket _fd;
+ private int _maxSendPacketSize;
+ private int _maxRecvPacketSize;
+ private int _state;
+ private string _desc;
+
+#if ICE_SOCKET_ASYNC_API
+ private SocketAsyncEventArgs _writeEventArgs;
+ private SocketAsyncEventArgs _readEventArgs;
+#else
+ private IAsyncResult _writeResult;
+ private IAsyncResult _readResult;
+#endif
+
+ AsyncCallback _writeCallback;
+ AsyncCallback _readCallback;
+
+ private const int StateNeedConnect = 0;
+ private const int StateConnectPending = 1;
+ private const int StateProxyWrite = 2;
+ private const int StateProxyRead = 3;
+ private const int StateProxyConnected = 4;
+ private const int StateConnected = 5;
+ }
+
+}
diff --git a/csharp/src/Ice/StreamWrapper.cs b/csharp/src/Ice/StreamWrapper.cs
new file mode 100644
index 00000000000..7ff9c8f3c97
--- /dev/null
+++ b/csharp/src/Ice/StreamWrapper.cs
@@ -0,0 +1,311 @@
+
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Text;
+
+ //
+ // Class to provide a System.IO.Stream interface on top of a BasicStream.
+ // We use this to serialize arbitrary .NET serializable classes into
+ // a Slice byte sequence.
+ //
+ // For input streams, this class is a wrapper around the BasicStream
+ // class that passes all methods through.
+ //
+ // For output streams, we use a different stragegy:
+ // Slice sequences are encoded on the wire as a count of elements, followed
+ // by the sequence contents. For arbitrary .NET classes, we do not know how
+ // big the sequence that is eventually written will be. To avoid excessive
+ // data copying, this class mantains a private bytes_ array of 254 bytes and,
+ // initially, writes data into that array. If more than 254 bytes end up being
+ // written, we write a dummy sequence size of 255 (which occupies five bytes
+ // on the wire) into the BasicStream and, once this class is disposed, patch
+ // that size to match the actual size. Otherwise, if the bytes_ buffer contains
+ // fewer than 255 bytes when this class is disposed, we write the sequence size
+ // as a single byte, followed by the contents of the bytes_ buffer.
+ //
+
+ enum StreamType { Read, Write };
+
+ public class StreamWrapper : System.IO.Stream, System.IDisposable
+ {
+ //
+ // Writeable stream constructor
+ //
+ public StreamWrapper(BasicStream s)
+ {
+ type_ = StreamType.Write;
+ s_ = s;
+ spos_ = s.pos();
+ bytes_ = new byte[254];
+ pos_ = 0;
+ length_ = 0;
+ }
+
+ //
+ // Readable stream constructor
+ //
+ public StreamWrapper(int size, BasicStream s)
+ {
+ type_ = StreamType.Read;
+ s_ = s;
+ spos_ = 0;
+ bytes_ = null;
+ pos_ = 0;
+ length_ = size;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ Debug.Assert(buffer != null && offset >= 0 && count >= 0 && offset + count <= buffer.Length);
+ try
+ {
+ s_.getBuffer().b.get(buffer, offset, count);
+ }
+ catch(System.Exception ex)
+ {
+ throw new IOException("could not read from stream", ex);
+ }
+ return count;
+ }
+
+ public override int ReadByte()
+ {
+ try
+ {
+ return s_.getBuffer().b.get();
+ }
+ catch(System.Exception ex)
+ {
+ throw new IOException("could not read from stream", ex);
+ }
+ }
+
+ public override void Write(byte[] array, int offset, int count)
+ {
+ Debug.Assert(type_ == StreamType.Write);
+ Debug.Assert(array != null && offset >= 0 && count >= 0 && offset + count <= array.Length);
+ try
+ {
+ if(bytes_ != null)
+ {
+ //
+ // If we can fit the data into the first 254 bytes, write it to bytes_.
+ //
+ if(count <= bytes_.Length - pos_)
+ {
+ System.Buffer.BlockCopy(array, offset, bytes_, pos_, count);
+ pos_ += count;
+ return;
+ }
+
+ s_.writeSize(255); // Dummy size, until we know how big the stream
+ // really is and can patch the size.
+ if(pos_ > 0)
+ {
+ //
+ // Write the current contents of bytes_.
+ //
+ s_.expand(pos_);
+ s_.getBuffer().b.put(bytes_, 0, pos_);
+ }
+
+ bytes_ = null;
+ }
+
+ //
+ // Write data passed by caller.
+ //
+ s_.expand(count);
+ s_.getBuffer().b.put(array, offset, count);
+ pos_ += count;
+ }
+ catch(System.Exception ex)
+ {
+ throw new IOException("could not write to stream", ex);
+ }
+ }
+
+ public override void WriteByte(byte value)
+ {
+ Debug.Assert(type_ == StreamType.Write);
+ try
+ {
+ if(bytes_ != null)
+ {
+ //
+ // If we can fit the data into the first 254 bytes, write it to bytes_.
+ //
+ if(pos_ < bytes_.Length)
+ {
+ bytes_[pos_++] = value;
+ return;
+ }
+
+ s_.writeSize(255); // Dummy size, until we know how big the stream
+ // really is and can patch the size.
+ if(pos_ > 0)
+ {
+ //
+ // Write the current contents of bytes_.
+ //
+ s_.expand(pos_);
+ s_.getBuffer().b.put(bytes_, 0, pos_);
+ }
+
+ bytes_ = null;
+ }
+
+ //
+ // Write data passed by caller.
+ //
+ s_.expand(1);
+ s_.getBuffer().b.put(value);
+ pos_ += 1;
+ }
+ catch(System.Exception ex)
+ {
+ throw new IOException("could not write to stream", ex);
+ }
+ }
+
+ public override bool CanRead
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public override bool CanWrite
+ {
+ get
+ {
+ return type_ == StreamType.Write;
+ }
+ }
+
+ public override bool CanSeek
+ {
+ get
+ {
+ if(AssemblyUtil.runtime_ == AssemblyUtil.Runtime.Mono)
+ {
+ //
+ // The Mono deserialization implementation has a bug that causes a call to Seek() such
+ // that the reading position is set to -1.
+ //
+ return false;
+ }
+ else
+ {
+ return type_ == StreamType.Read;
+ }
+ }
+ }
+
+ public override void Flush()
+ {
+ try
+ {
+ if(bytes_ != null)
+ {
+ Debug.Assert(pos_ <= bytes_.Length);
+ s_.pos(spos_);
+ s_.writeSize(pos_);
+ s_.expand(pos_);
+ s_.getBuffer().b.put(bytes_, 0, pos_);
+ }
+ else
+ {
+ int currentPos = s_.pos();
+ s_.pos(spos_);
+ s_.writeSize(pos_); // Patch previously-written dummy value.
+ s_.pos(currentPos);
+ }
+ }
+ catch(System.Exception ex)
+ {
+ throw new IOException("could not flush stream", ex);
+ }
+ }
+
+ public override long Length
+ {
+ get
+ {
+ return length_;
+ }
+ }
+
+ public override long Position
+ {
+ get
+ {
+ return pos_;
+ }
+
+ set
+ {
+ Seek(value, SeekOrigin.Begin);
+ }
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ Debug.Assert(type_ != StreamType.Write);
+
+ // Deliberately no size check here--positioning beyond the limit of the stream is legal.
+ switch(origin)
+ {
+ case SeekOrigin.Begin:
+ {
+ pos_ = (int)offset;
+ break;
+ }
+ case SeekOrigin.Current:
+ {
+ pos_ += (int)offset;
+ break;
+ }
+ case SeekOrigin.End:
+ {
+ pos_ = (int)length_ + (int)offset;
+ break;
+ }
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+ s_.pos(pos_);
+ return pos_;
+ }
+
+ public override void SetLength(long value)
+ {
+ Debug.Assert(type_ == StreamType.Write && value >= 0);
+ length_ = value;
+ }
+
+ private StreamType type_;
+ private BasicStream s_;
+ private int spos_;
+ private byte[] bytes_;
+ private int pos_;
+ private long length_;
+ }
+}
diff --git a/csharp/src/Ice/StringUtil.cs b/csharp/src/Ice/StringUtil.cs
new file mode 100644
index 00000000000..32ce2d4b55e
--- /dev/null
+++ b/csharp/src/Ice/StringUtil.cs
@@ -0,0 +1,515 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Text;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace IceUtilInternal
+{
+
+ public sealed class StringUtil
+ {
+ //
+ // Return the index of the first character in str to
+ // appear in match, starting from 0. Returns -1 if none is
+ // found.
+ //
+ public static int findFirstOf(string str, string match)
+ {
+ return findFirstOf(str, match, 0);
+ }
+
+ //
+ // Return the index of the first character in str to
+ // appear in match, starting from start. Returns -1 if none is
+ // found.
+ //
+ public static int findFirstOf(string str, string match, int start)
+ {
+ int len = str.Length;
+ for(int i = start; i < len; i++)
+ {
+ char ch = str[i];
+ if(match.IndexOf((char) ch) != -1)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ //
+ // Return the index of the first character in str which does
+ // not appear in match, starting from 0. Returns -1 if none is
+ // found.
+ //
+ public static int findFirstNotOf(string str, string match)
+ {
+ return findFirstNotOf(str, match, 0);
+ }
+
+ //
+ // Return the index of the first character in str which does
+ // not appear in match, starting from start. Returns -1 if none is
+ // found.
+ //
+ public static int findFirstNotOf(string str, string match, int start)
+ {
+ int len = str.Length;
+ for(int i = start; i < len; i++)
+ {
+ char ch = str[i];
+ if(match.IndexOf((char) ch) == -1)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ //
+ // Write the byte b as an escape sequence if it isn't a printable ASCII
+ // character and append the escape sequence to sb. Additional characters
+ // that should be escaped can be passed in special. If b is any of these
+ // characters, b is preceded by a backslash in sb.
+ //
+ private static void encodeChar(byte b, StringBuilder sb, string special)
+ {
+ switch((char)b)
+ {
+ case '\\':
+ {
+ sb.Append("\\\\");
+ break;
+ }
+
+ case '\'':
+ {
+ sb.Append("\\'");
+ break;
+ }
+
+ case '"':
+ {
+ sb.Append("\\\"");
+ break;
+ }
+
+ case '\b':
+ {
+ sb.Append("\\b");
+ break;
+ }
+
+ case '\f':
+ {
+ sb.Append("\\f");
+ break;
+ }
+
+ case '\n':
+ {
+ sb.Append("\\n");
+ break;
+ }
+
+ case '\r':
+ {
+ sb.Append("\\r");
+ break;
+ }
+
+ case '\t':
+ {
+ sb.Append("\\t");
+ break;
+ }
+
+ default:
+ {
+ if(!(b >= 32 && b <= 126))
+ {
+ sb.Append('\\');
+ string octal = System.Convert.ToString(b, 8);
+ //
+ // Add leading zeroes so that we avoid problems during
+ // decoding. For example, consider the encoded string
+ // \0013 (i.e., a character with value 1 followed by
+ // the character '3'). If the leading zeroes were omitted,
+ // the result would be incorrectly interpreted by the
+ // decoder as a single character with value 11.
+ //
+ for(int j = octal.Length; j < 3; j++)
+ {
+ sb.Append('0');
+ }
+ sb.Append(octal);
+ }
+ else if(special != null && special.IndexOf((char)b) != -1)
+ {
+ sb.Append('\\');
+ sb.Append((char)b);
+ }
+ else
+ {
+ sb.Append((char)b);
+ }
+ }
+ break;
+ }
+ }
+
+ //
+ // Add escape sequences (such as "\n", or "\007") to make a string
+ // readable in ASCII. Any characters that appear in special are
+ // prefixed with a backslash in the returned string.
+ //
+ public static string escapeString(string s, string special)
+ {
+ if(special != null)
+ {
+ for(int i = 0; i < special.Length; ++i)
+ {
+ if((int)special[i] < 32 || (int)special[i] > 126)
+ {
+ throw new System.ArgumentException("special characters must be in ASCII range 32-126",
+ "special");
+ }
+ }
+ }
+
+ UTF8Encoding utf8 = new UTF8Encoding();
+ byte[] bytes = utf8.GetBytes(s);
+
+ StringBuilder result = new StringBuilder(bytes.Length);
+ for(int i = 0; i < bytes.Length; i++)
+ {
+ encodeChar(bytes[i], result, special);
+ }
+
+ return result.ToString();
+ }
+
+ private static char checkChar(string s, int pos)
+ {
+ char c = s[pos];
+ if(!(c >= 32 && c <= 126))
+ {
+ string msg;
+ if(pos > 0)
+ {
+ msg = "character after `" + s.Substring(0, pos) + "'";
+ }
+ else
+ {
+ msg = "first character";
+ }
+ msg += " is not a printable ASCII character (ordinal " + (int)c + ")";
+ throw new System.ArgumentException(msg);
+ }
+ return c;
+ }
+
+ //
+ // Decode the character or escape sequence starting at start and return it.
+ // end marks the one-past-the-end position of the substring to be scanned.
+ // nextStart is set to the index of the first character following the decoded
+ // character or escape sequence.
+ //
+ private static char decodeChar(string s, int start, int end, out int nextStart)
+ {
+ Debug.Assert(start >= 0);
+ Debug.Assert(start < end);
+ Debug.Assert(end <= s.Length);
+
+ char c;
+
+ if(s[start] != '\\')
+ {
+ c = checkChar(s, start++);
+ }
+ else
+ {
+ if(start + 1 == end)
+ {
+ throw new System.ArgumentException("trailing backslash");
+ }
+ switch(s[++start])
+ {
+ case '\\':
+ case '\'':
+ case '"':
+ {
+ c = s[start++];
+ break;
+ }
+ case 'b':
+ {
+ ++start;
+ c = '\b';
+ break;
+ }
+ case 'f':
+ {
+ ++start;
+ c = '\f';
+ break;
+ }
+ case 'n':
+ {
+ ++start;
+ c = '\n';
+ break;
+ }
+ case 'r':
+ {
+ ++start;
+ c = '\r';
+ break;
+ }
+ case 't':
+ {
+ ++start;
+ c = '\t';
+ break;
+ }
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int val = 0;
+ for(int j = 0; j < 3 && start < end; ++j)
+ {
+ int charVal = s[start++] - '0';
+ if(charVal < 0 || charVal > 7)
+ {
+ --start;
+ break;
+ }
+ val = val * 8 + charVal;
+ }
+ if(val > 255)
+ {
+ string msg = "octal value \\" + System.Convert.ToString(val, 8) + " (" + val +
+ ") is out of range";
+ throw new System.ArgumentException(msg, "s");
+ }
+ c = System.Convert.ToChar(val);
+ break;
+ }
+ default:
+ {
+ c = checkChar(s, start++);
+ break;
+ }
+ }
+ }
+ nextStart = start;
+ return c;
+ }
+
+ //
+ // Remove escape sequences from s and append the result to sb.
+ // Return true if successful, false otherwise.
+ //
+ private static void decodeString(string s, int start, int end, StringBuilder sb)
+ {
+ while(start < end)
+ {
+ sb.Append(decodeChar(s, start, end, out start));
+ }
+ }
+
+ //
+ // Remove escape sequences added by escapeString. Throws System.ArgumentException
+ // for an invalid input string.
+ //
+ public static string unescapeString(string s, int start, int end)
+ {
+ Debug.Assert(start >= 0 && start <= end && end <= s.Length);
+
+ StringBuilder sb = new StringBuilder();
+ decodeString(s, start, end, sb);
+ string decodedString = sb.ToString();
+
+ byte[] arr = new byte[decodedString.Length];
+ for(int i = 0; i < arr.Length; ++i)
+ {
+ arr[i] = (byte)decodedString[i];
+ }
+
+ UTF8Encoding utf8 = new UTF8Encoding(false, true);
+ return utf8.GetString(arr, 0, arr.Length); // May raise ArgumentException.
+ }
+
+ //
+ // Split string helper; returns null for unmatched quotes
+ //
+ static public string[] splitString(string str, string delim)
+ {
+ List<string> l = new List<string>();
+ char[] arr = new char[str.Length];
+ int pos = 0;
+
+ int n = 0;
+ char quoteChar = '\0';
+ while(pos < str.Length)
+ {
+ if(quoteChar == '\0' && (str[pos] == '"' || str[pos] == '\''))
+ {
+ quoteChar = str[pos++];
+ continue; // Skip the quote.
+ }
+ else if(quoteChar == '\0' && str[pos] == '\\' && pos + 1 < str.Length &&
+ (str[pos + 1] == '\'' || str[pos + 1] == '"'))
+ {
+ ++pos; // Skip the backslash
+ }
+ else if(quoteChar != '\0' && str[pos] == '\\' && pos + 1 < str.Length && str[pos + 1] == quoteChar)
+ {
+ ++pos; // Skip the backslash
+ }
+ else if(quoteChar != '\0' && str[pos] == quoteChar)
+ {
+ ++pos;
+ quoteChar = '\0';
+ continue; // Skip the quote.
+ }
+ else if(delim.IndexOf(str[pos]) != -1)
+ {
+ if(quoteChar == '\0')
+ {
+ ++pos;
+ if(n > 0)
+ {
+ l.Add(new string(arr, 0, n));
+ n = 0;
+ }
+ continue;
+ }
+ }
+
+ if(pos < str.Length)
+ {
+ arr[n++] = str[pos++];
+ }
+
+ }
+
+ if(n > 0)
+ {
+ l.Add(new string(arr, 0, n));
+ }
+ if(quoteChar != '\0')
+ {
+ return null; // Unmatched quote.
+ }
+ return l.ToArray();
+ }
+
+ public static int checkQuote(string s)
+ {
+ return checkQuote(s, 0);
+ }
+
+ //
+ // If a single or double quotation mark is found at the start position,
+ // then the position of the matching closing quote is returned. If no
+ // quotation mark is found at the start position, then 0 is returned.
+ // If no matching closing quote is found, then -1 is returned.
+ //
+ public static int checkQuote(string s, int start)
+ {
+ char quoteChar = s[start];
+ if(quoteChar == '"' || quoteChar == '\'')
+ {
+ start++;
+ int len = s.Length;
+ int pos;
+ while(start < len && (pos = s.IndexOf(quoteChar, start)) != -1)
+ {
+ if(s[pos - 1] != '\\')
+ {
+ return pos;
+ }
+ start = pos + 1;
+ }
+ return -1; // Unmatched quote
+ }
+ return 0; // Not quoted
+ }
+
+ public static bool match(string s, string pat, bool emptyMatch)
+ {
+ Debug.Assert(s.Length > 0);
+ Debug.Assert(pat.Length > 0);
+
+ //
+ // If pattern does not contain a wildcard just compare strings.
+ //
+ int beginIndex = pat.IndexOf('*');
+ if(beginIndex < 0)
+ {
+ return s.Equals(pat);
+ }
+
+ //
+ // Make sure start of the strings match
+ //
+ if(beginIndex > s.Length || !s.Substring(0, beginIndex).Equals(pat.Substring(0, beginIndex)))
+ {
+ return false;
+ }
+
+ //
+ // Make sure there is something present in the middle to match the
+ // wildcard. If emptyMatch is true, allow a match of "".
+ //
+ int endLength = pat.Length - beginIndex - 1;
+ if(endLength > s.Length)
+ {
+ return false;
+ }
+ int endIndex = s.Length - endLength;
+ if(endIndex < beginIndex || (!emptyMatch && endIndex == beginIndex))
+ {
+ return false;
+ }
+
+ //
+ // Make sure end of the strings match
+ //
+ if(!s.Substring(endIndex, s.Length - endIndex).Equals(
+ pat.Substring(beginIndex + 1, pat.Length - beginIndex - 1)))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private class OrdinalStringComparerImpl : System.Collections.Generic.IComparer<string>
+ {
+ public int Compare(string l, string r)
+ {
+ return string.CompareOrdinal(l, r);
+ }
+ }
+ public static System.Collections.Generic.IComparer<string> OrdinalStringComparer =
+ new OrdinalStringComparerImpl();
+ }
+}
diff --git a/csharp/src/Ice/SysLoggerI.cs b/csharp/src/Ice/SysLoggerI.cs
new file mode 100644
index 00000000000..b8cfa08df57
--- /dev/null
+++ b/csharp/src/Ice/SysLoggerI.cs
@@ -0,0 +1,234 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#if !SILVERLIGHT
+using System.Net.Sockets;
+
+namespace Ice
+{
+
+ public sealed class SysLoggerI : Logger
+ {
+ public SysLoggerI(string prefix, string facilityString)
+ {
+ int facility;
+ if(facilityString.Equals("LOG_KERN"))
+ {
+ facility = LOG_KERN;
+ }
+ else if(facilityString.Equals("LOG_USER"))
+ {
+ facility = LOG_USER;
+ }
+ else if(facilityString.Equals("LOG_MAIL"))
+ {
+ facility = LOG_MAIL;
+ }
+ else if(facilityString.Equals("LOG_DAEMON"))
+ {
+ facility = LOG_DAEMON;
+ }
+ else if(facilityString.Equals("LOG_AUTH"))
+ {
+ facility = LOG_AUTH;
+ }
+ else if(facilityString.Equals("LOG_SYSLOG"))
+ {
+ facility = LOG_SYSLOG;
+ }
+ else if(facilityString.Equals("LOG_LPR"))
+ {
+ facility = LOG_LPR;
+ }
+ else if(facilityString.Equals("LOG_NEWS"))
+ {
+ facility = LOG_NEWS;
+ }
+ else if(facilityString.Equals("LOG_UUCP"))
+ {
+ facility = LOG_UUCP;
+ }
+ else if(facilityString.Equals("LOG_CRON"))
+ {
+ facility = LOG_CRON;
+ }
+ else if(facilityString.Equals("LOG_AUTHPRIV"))
+ {
+ facility = LOG_AUTHPRIV;
+ }
+ else if(facilityString.Equals("LOG_FTP"))
+ {
+ facility = LOG_FTP;
+ }
+ else if(facilityString.Equals("LOG_LOCAL0"))
+ {
+ facility = LOG_LOCAL0;
+ }
+ else if(facilityString.Equals("LOG_LOCAL1"))
+ {
+ facility = LOG_LOCAL1;
+ }
+ else if(facilityString.Equals("LOG_LOCAL2"))
+ {
+ facility = LOG_LOCAL2;
+ }
+ else if(facilityString.Equals("LOG_LOCAL3"))
+ {
+ facility = LOG_LOCAL3;
+ }
+ else if(facilityString.Equals("LOG_LOCAL4"))
+ {
+ facility = LOG_LOCAL4;
+ }
+ else if(facilityString.Equals("LOG_LOCAL5"))
+ {
+ facility = LOG_LOCAL5;
+ }
+ else if(facilityString.Equals("LOG_LOCAL6"))
+ {
+ facility = LOG_LOCAL6;
+ }
+ else if(facilityString.Equals("LOG_LOCAL7"))
+ {
+ facility = LOG_LOCAL7;
+ }
+ else
+ {
+ throw new Ice.InitializationException("Invalid value for Ice.SyslogFacility: " + facilityString);
+ }
+ initialize(prefix, facility);
+ }
+
+ private SysLoggerI(string prefix, int facility)
+ {
+ initialize(prefix, facility);
+ }
+
+ private void initialize(string prefix, int facility)
+ {
+ _prefix = prefix;
+ _facility = facility;
+
+ //
+ // Open a datagram socket to communicate with the localhost
+ // syslog daemon.
+ //
+ try
+ {
+ _host = ((System.Net.IPEndPoint)IceInternal.Network.getAddressForServer(
+ System.Net.Dns.GetHostName(), _port, IceInternal.Network.EnableBoth, false)).Address;
+ _socket = new UdpClient();
+ _socket.Connect(_host, _port);
+ }
+ catch(System.Exception ex)
+ {
+ throw new Ice.DNSException(ex);
+ }
+ }
+
+ public void print(string message)
+ {
+ log(LOG_INFO, message);
+ }
+
+ public void trace(string category, string message)
+ {
+ log(LOG_INFO, category + ": " + message);
+ }
+
+ public void warning(string message)
+ {
+ log(LOG_WARNING, message);
+ }
+
+ public void error(string message)
+ {
+ log(LOG_ERR, message);
+ }
+
+ public string getPrefix()
+ {
+ return _prefix;
+ }
+
+ public Logger cloneWithPrefix(string prefix)
+ {
+ return new SysLoggerI(prefix, _facility);
+ }
+
+ private void log(int severity, string message)
+ {
+ try
+ {
+ //
+ // Create a syslog message as defined by the RFC 3164:
+ // <PRI>HEADER MSG. PRI is the priority and is calculated
+ // from the facility and the severity. We don't specify
+ // the HEADER. MSG contains the identifier followed by a
+ // colon character and the message.
+ //
+
+ int priority = (_facility << 3) | severity;
+
+ string msg = '<' + priority + '>' + _prefix + ": " + message;
+
+ byte[] buf = new byte[msg.Length];
+ for(int i = 0; i < msg.Length; i++)
+ {
+ buf[i] = (byte)msg[i];
+ }
+ _socket.Send(buf, buf.Length);
+ }
+ catch(System.IO.IOException ex)
+ {
+ Ice.SocketException se = new Ice.SocketException(ex);
+ throw se;
+ }
+ }
+
+ private string _prefix;
+ private int _facility;
+ private UdpClient _socket;
+ private System.Net.IPAddress _host;
+ private static int _port = 514;
+
+ //
+ // Syslog facilities (as defined in syslog.h)
+ //
+ private const int LOG_KERN = 0;
+ private const int LOG_USER = 1;
+ private const int LOG_MAIL = 2;
+ private const int LOG_DAEMON = 3;
+ private const int LOG_AUTH = 4;
+ private const int LOG_SYSLOG = 5;
+ private const int LOG_LPR = 6;
+ private const int LOG_NEWS = 7;
+ private const int LOG_UUCP = 8;
+ private const int LOG_CRON = 9;
+ private const int LOG_AUTHPRIV = 10;
+ private const int LOG_FTP = 11;
+ private const int LOG_LOCAL0 = 16;
+ private const int LOG_LOCAL1 = 17;
+ private const int LOG_LOCAL2 = 18;
+ private const int LOG_LOCAL3 = 19;
+ private const int LOG_LOCAL4 = 20;
+ private const int LOG_LOCAL5 = 21;
+ private const int LOG_LOCAL6 = 22;
+ private const int LOG_LOCAL7 = 23;
+
+ //
+ // Syslog priorities (as defined in syslog.h)
+ //
+ private const int LOG_ERR = 3;
+ private const int LOG_WARNING = 4;
+ private const int LOG_INFO = 6;
+ }
+
+}
+#endif
diff --git a/csharp/src/Ice/TcpAcceptor.cs b/csharp/src/Ice/TcpAcceptor.cs
new file mode 100644
index 00000000000..d896d4367df
--- /dev/null
+++ b/csharp/src/Ice/TcpAcceptor.cs
@@ -0,0 +1,176 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#if !SILVERLIGHT
+
+namespace IceInternal
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Text;
+
+ class TcpAcceptor : Acceptor
+ {
+ public virtual void close()
+ {
+ Debug.Assert(_acceptFd == null);
+ if(_fd != null)
+ {
+ Network.closeSocketNoThrow(_fd);
+ _fd = null;
+ }
+ }
+
+ public virtual EndpointI listen()
+ {
+ try
+ {
+ _addr = Network.doBind(_fd, _addr);
+ Network.doListen(_fd, _backlog);
+ }
+ catch(SystemException)
+ {
+ _fd = null;
+ throw;
+ }
+ _endpoint = _endpoint.endpoint(this);
+ return _endpoint;
+ }
+
+ public virtual bool startAccept(AsyncCallback callback, object state)
+ {
+ try
+ {
+ _result = _fd.BeginAccept(delegate(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ callback(result.AsyncState);
+ }
+ }, state);
+ }
+ catch(SocketException ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+ return _result.CompletedSynchronously;
+ }
+
+ public virtual void finishAccept()
+ {
+ if(_fd != null)
+ {
+ _acceptFd = null;
+ try
+ {
+ _acceptFd = _fd.EndAccept(_result);
+ }
+ catch(SocketException ex)
+ {
+ _acceptError = ex;
+ }
+ }
+ }
+
+ public virtual Transceiver accept()
+ {
+ if(_acceptFd == null)
+ {
+ throw _acceptError;
+ }
+
+ Socket acceptFd = _acceptFd;
+ _acceptFd = null;
+ _acceptError = null;
+ return new TcpTransceiver(_instance, new StreamSocket(_instance, acceptFd));
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public override string ToString()
+ {
+ return Network.addrToString(_addr);
+ }
+
+ public string toDetailedString()
+ {
+ StringBuilder s = new StringBuilder("local address = ");
+ s.Append(ToString());
+
+ List<string> intfs =
+ Network.getHostsForEndpointExpand(_addr.Address.ToString(), _instance.protocolSupport(), true);
+ if(intfs.Count != 0)
+ {
+ s.Append("\nlocal interfaces = ");
+ s.Append(String.Join(", ", intfs.ToArray()));
+ }
+ return s.ToString();
+ }
+
+ internal int effectivePort()
+ {
+ return _addr.Port;
+ }
+
+ internal TcpAcceptor(TcpEndpointI endpoint, ProtocolInstance instance, string host, int port)
+ {
+ _endpoint = endpoint;
+ _instance = instance;
+ _backlog = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.Backlog", 511);
+
+ try
+ {
+ int protocol = _instance.protocolSupport();
+ _addr = (IPEndPoint)Network.getAddressForServer(host, port, protocol, _instance.preferIPv6());
+ _fd = Network.createServerSocket(false, _addr.AddressFamily, protocol);
+ Network.setBlock(_fd, false);
+# if !COMPACT
+ Network.setTcpBufSize(_fd, _instance);
+# endif
+ if(AssemblyUtil.platform_ != AssemblyUtil.Platform.Windows)
+ {
+ //
+ // Enable SO_REUSEADDR on Unix platforms to allow re-using the
+ // socket even if it's in the TIME_WAIT state. On Windows,
+ // this doesn't appear to be necessary and enabling
+ // SO_REUSEADDR would actually not be a good thing since it
+ // allows a second process to bind to an address even it's
+ // already bound by another process.
+ //
+ // TODO: using SO_EXCLUSIVEADDRUSE on Windows would probably
+ // be better but it's only supported by recent Windows
+ // versions (XP SP2, Windows Server 2003).
+ //
+ Network.setReuseAddress(_fd, true);
+ }
+ }
+ catch(System.Exception)
+ {
+ _fd = null;
+ throw;
+ }
+ }
+
+ private TcpEndpointI _endpoint;
+ private ProtocolInstance _instance;
+ private Socket _fd;
+ private Socket _acceptFd;
+ private System.Exception _acceptError;
+ private int _backlog;
+ private IPEndPoint _addr;
+ private IAsyncResult _result;
+ }
+}
+#endif
diff --git a/csharp/src/Ice/TcpConnector.cs b/csharp/src/Ice/TcpConnector.cs
new file mode 100644
index 00000000000..c061171a9de
--- /dev/null
+++ b/csharp/src/Ice/TcpConnector.cs
@@ -0,0 +1,101 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Net.Sockets;
+
+ sealed class TcpConnector : Connector
+ {
+ public Transceiver connect()
+ {
+ return new TcpTransceiver(_instance, new StreamSocket(_instance, _proxy, _addr, _sourceAddr));
+ }
+
+ public short type()
+ {
+ return _instance.type();
+ }
+
+ //
+ // Only for use by TcpEndpoint
+ //
+ internal TcpConnector(ProtocolInstance instance, EndPoint addr, NetworkProxy proxy, EndPoint sourceAddr,
+ int timeout, string connectionId)
+ {
+ _instance = instance;
+ _addr = addr;
+ _proxy = proxy;
+ _sourceAddr = sourceAddr;
+ _timeout = timeout;
+ _connectionId = connectionId;
+
+ _hashCode = 5381;
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _addr);
+ if(_sourceAddr != null)
+ {
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _sourceAddr);
+ }
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _timeout);
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _connectionId);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(!(obj is TcpConnector))
+ {
+ return false;
+ }
+
+ if(this == obj)
+ {
+ return true;
+ }
+
+ TcpConnector p = (TcpConnector)obj;
+ if(_timeout != p._timeout)
+ {
+ return false;
+ }
+
+ if(!Network.addressEquals(_sourceAddr, p._sourceAddr))
+ {
+ return false;
+ }
+
+ if(!_connectionId.Equals(p._connectionId))
+ {
+ return false;
+ }
+
+ return _addr.Equals(p._addr);
+ }
+
+ public override string ToString()
+ {
+ return Network.addrToString(_proxy == null ? _addr : _proxy.getAddress());
+ }
+
+ public override int GetHashCode()
+ {
+ return _hashCode;
+ }
+
+ private ProtocolInstance _instance;
+ private EndPoint _addr;
+ private NetworkProxy _proxy;
+ private EndPoint _sourceAddr;
+ private int _timeout;
+ private string _connectionId;
+ private int _hashCode;
+ }
+}
diff --git a/csharp/src/Ice/TcpEndpointI.cs b/csharp/src/Ice/TcpEndpointI.cs
new file mode 100644
index 00000000000..fcfa84ab0c3
--- /dev/null
+++ b/csharp/src/Ice/TcpEndpointI.cs
@@ -0,0 +1,338 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Diagnostics;
+ using System.Collections.Generic;
+ using System.Net;
+ using System;
+ using System.Globalization;
+
+ sealed class TcpEndpointI : IPEndpointI
+ {
+ public TcpEndpointI(ProtocolInstance instance, string ho, int po, EndPoint sourceAddr, int ti, string conId,
+ bool co) :
+ base(instance, ho, po, sourceAddr, conId)
+ {
+ _timeout = ti;
+ _compress = co;
+ }
+
+ public TcpEndpointI(ProtocolInstance instance) :
+ base(instance)
+ {
+ _timeout = instance.defaultTimeout();
+ _compress = false;
+ }
+
+ public TcpEndpointI(ProtocolInstance instance, BasicStream s) :
+ base(instance, s)
+ {
+ _timeout = s.readInt();
+ _compress = s.readBool();
+ }
+
+ private sealed class InfoI : Ice.TCPEndpointInfo
+ {
+ public InfoI(IPEndpointI e)
+ {
+ _endpoint = e;
+ }
+
+ public override short type()
+ {
+ return _endpoint.type();
+ }
+
+ public override bool datagram()
+ {
+ return _endpoint.datagram();
+ }
+
+ public override bool secure()
+ {
+ return _endpoint.secure();
+ }
+
+ private IPEndpointI _endpoint;
+ }
+
+ public override Ice.EndpointInfo getInfo()
+ {
+ InfoI info = new InfoI(this);
+ fillEndpointInfo(info);
+ return info;
+ }
+
+ public override int timeout()
+ {
+ return _timeout;
+ }
+
+ public override EndpointI timeout(int timeout)
+ {
+ if(timeout == _timeout)
+ {
+ return this;
+ }
+ else
+ {
+ return new TcpEndpointI(instance_, host_, port_, sourceAddr_, timeout, connectionId_, _compress);
+ }
+ }
+
+ public override bool compress()
+ {
+ return _compress;
+ }
+
+ public override EndpointI compress(bool compress)
+ {
+ if(compress == _compress)
+ {
+ return this;
+ }
+ else
+ {
+ return new TcpEndpointI(instance_, host_, port_, sourceAddr_, _timeout, connectionId_, compress);
+ }
+ }
+
+ public override bool datagram()
+ {
+ return false;
+ }
+
+ public override Transceiver transceiver()
+ {
+ return null;
+ }
+
+ public override Acceptor acceptor(string adapterName)
+ {
+#if SILVERLIGHT
+ throw new Ice.FeatureNotSupportedException("server endpoint not supported for `" + ToString() + "'");
+#else
+ return new TcpAcceptor(this, instance_, host_, port_);
+#endif
+ }
+
+#if !SILVERLIGHT
+ public TcpEndpointI endpoint(TcpAcceptor acceptor)
+ {
+ return new TcpEndpointI(instance_, host_, acceptor.effectivePort(), sourceAddr_, _timeout, connectionId_,
+ _compress);
+ }
+#endif
+
+ public override string options()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ string s = base.options();
+
+ if(_timeout == -1)
+ {
+ s += " -t infinite";
+ }
+ else
+ {
+ s += " -t " + _timeout;
+ }
+
+ if(_compress)
+ {
+ s += " -z";
+ }
+
+ return s;
+ }
+
+ public override int CompareTo(EndpointI obj)
+ {
+ if(!(obj is TcpEndpointI))
+ {
+ return type() < obj.type() ? -1 : 1;
+ }
+
+ TcpEndpointI p = (TcpEndpointI)obj;
+ if(this == p)
+ {
+ return 0;
+ }
+
+ if(_timeout < p._timeout)
+ {
+ return -1;
+ }
+ else if(p._timeout < _timeout)
+ {
+ return 1;
+ }
+
+ if(!_compress && p._compress)
+ {
+ return -1;
+ }
+ else if(!p._compress && _compress)
+ {
+ return 1;
+ }
+
+ return base.CompareTo(p);
+ }
+
+ public override void streamWriteImpl(BasicStream s)
+ {
+ base.streamWriteImpl(s);
+ s.writeInt(_timeout);
+ s.writeBool(_compress);
+ }
+
+ public override void hashInit(ref int h)
+ {
+ base.hashInit(ref h);
+ IceInternal.HashUtil.hashAdd(ref h, _timeout);
+ IceInternal.HashUtil.hashAdd(ref h, _compress);
+ }
+
+ public override void fillEndpointInfo(Ice.IPEndpointInfo info)
+ {
+ base.fillEndpointInfo(info);
+ info.timeout = _timeout;
+ info.compress = _compress;
+ }
+
+ protected override bool checkOption(string option, string argument, string endpoint)
+ {
+ if(base.checkOption(option, argument, endpoint))
+ {
+ return true;
+ }
+
+ switch(option[1])
+ {
+ case 't':
+ {
+ if(argument == null)
+ {
+ throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " +
+ endpoint);
+ }
+
+ if(argument.Equals("infinite"))
+ {
+ _timeout = -1;
+ }
+ else
+ {
+ try
+ {
+ _timeout = System.Int32.Parse(argument, CultureInfo.InvariantCulture);
+ if(_timeout < 1)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "invalid timeout value `" + argument + "' in endpoint " + endpoint;
+ throw e;
+ }
+ }
+ catch(System.FormatException ex)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException(ex);
+ e.str = "invalid timeout value `" + argument + "' in endpoint " + endpoint;
+ throw e;
+ }
+ }
+
+ return true;
+ }
+
+ case 'z':
+ {
+ if(argument != null)
+ {
+ throw new Ice.EndpointParseException("unexpected argument `" + argument +
+ "' provided for -z option in " + endpoint);
+ }
+
+ _compress = true;
+
+ return true;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
+ protected override Connector createConnector(EndPoint addr, NetworkProxy proxy)
+ {
+ return new TcpConnector(instance_, addr, proxy, sourceAddr_, _timeout, connectionId_);
+ }
+
+ protected override IPEndpointI createEndpoint(string host, int port, string connectionId)
+ {
+ return new TcpEndpointI(instance_, host, port, sourceAddr_, _timeout, connectionId, _compress);
+ }
+
+ private int _timeout;
+ private bool _compress;
+ }
+
+ sealed class TcpEndpointFactory : EndpointFactory
+ {
+ internal TcpEndpointFactory(ProtocolInstance instance)
+ {
+ _instance = instance;
+ }
+
+ public short type()
+ {
+ return _instance.type();
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public EndpointI create(List<string> args, bool oaEndpoint)
+ {
+ IPEndpointI endpt = new TcpEndpointI(_instance);
+ endpt.initWithOptions(args, oaEndpoint);
+ return endpt;
+ }
+
+ public EndpointI read(BasicStream s)
+ {
+ return new TcpEndpointI(_instance, s);
+ }
+
+ public void destroy()
+ {
+ _instance = null;
+ }
+
+ public EndpointFactory clone(ProtocolInstance instance)
+ {
+ return new TcpEndpointFactory(instance);
+ }
+
+ private ProtocolInstance _instance;
+ }
+
+}
diff --git a/csharp/src/Ice/TcpTransceiver.cs b/csharp/src/Ice/TcpTransceiver.cs
new file mode 100644
index 00000000000..11f7fd49578
--- /dev/null
+++ b/csharp/src/Ice/TcpTransceiver.cs
@@ -0,0 +1,136 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Net.Sockets;
+
+ sealed class TcpTransceiver : Transceiver
+ {
+ public Socket fd()
+ {
+ return _stream.fd();
+ }
+
+ public int initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData)
+ {
+ return _stream.connect(readBuffer, writeBuffer, ref hasMoreData);
+ }
+
+ public int closing(bool initiator, Ice.LocalException ex)
+ {
+ // If we are initiating the connection closure, wait for the peer
+ // to close the TCP/IP connection. Otherwise, close immediately.
+ return initiator ? SocketOperation.Read : SocketOperation.None;
+ }
+
+ public void close()
+ {
+ _stream.close();
+ }
+
+ public EndpointI bind()
+ {
+ Debug.Assert(false);
+ return null;
+ }
+
+ public void destroy()
+ {
+ _stream.destroy();
+ }
+
+ public int write(Buffer buf)
+ {
+ return _stream.write(buf);
+ }
+
+ public int read(Buffer buf, ref bool hasMoreData)
+ {
+ return _stream.read(buf);
+ }
+
+ public bool startRead(Buffer buf, AsyncCallback callback, object state)
+ {
+ return _stream.startRead(buf, callback, state);
+ }
+
+ public void finishRead(Buffer buf)
+ {
+ _stream.finishRead(buf);
+ }
+
+ public bool startWrite(Buffer buf, AsyncCallback callback, object state, out bool completed)
+ {
+ return _stream.startWrite(buf, callback, state, out completed);
+ }
+
+ public void finishWrite(Buffer buf)
+ {
+ _stream.finishWrite(buf);
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public Ice.ConnectionInfo getInfo()
+ {
+ Ice.TCPConnectionInfo info = new Ice.TCPConnectionInfo();
+ if(_stream.fd() != null)
+ {
+ EndPoint localEndpoint = Network.getLocalAddress(_stream.fd());
+ info.localAddress = Network.endpointAddressToString(localEndpoint);
+ info.localPort = Network.endpointPort(localEndpoint);
+ EndPoint remoteEndpoint = Network.getRemoteAddress(_stream.fd());
+ info.remoteAddress = Network.endpointAddressToString(remoteEndpoint);
+ info.remotePort = Network.endpointPort(remoteEndpoint);
+ info.rcvSize = Network.getRecvBufferSize(_stream.fd());
+ info.sndSize = Network.getSendBufferSize(_stream.fd());
+ }
+ return info;
+ }
+
+ public void checkSendSize(Buffer buf)
+ {
+ }
+
+ public void setBufferSize(int rcvSize, int sndSize)
+ {
+ _stream.setBufferSize(rcvSize, sndSize);
+ }
+
+ public override string ToString()
+ {
+ return _stream.ToString();
+ }
+
+ public string toDetailedString()
+ {
+ return ToString();
+ }
+
+ //
+ // Only for use by TcpConnector, TcpAcceptor
+ //
+ internal TcpTransceiver(ProtocolInstance instance, StreamSocket stream)
+ {
+ _instance = instance;
+ _stream = stream;
+ }
+
+ private readonly ProtocolInstance _instance;
+ private readonly StreamSocket _stream;
+ }
+}
diff --git a/csharp/src/Ice/ThreadHookPlugin.cs b/csharp/src/Ice/ThreadHookPlugin.cs
new file mode 100644
index 00000000000..35ca94759b5
--- /dev/null
+++ b/csharp/src/Ice/ThreadHookPlugin.cs
@@ -0,0 +1,59 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ /// <summary>
+ /// Class to support thread notification hooks. Applications using
+ /// thread notification hooks instantiate a ThreadHookPlugin with a
+ /// thread notification hook and return the instance from their
+ /// PluginFactory implementation.
+ /// </summary>
+ public class ThreadHookPlugin : Ice.Plugin
+ {
+ /// <summary>
+ /// Installs a custom logger for a communicator.
+ /// </summary>
+ /// <param name="communicator">The communicator using the thread notification hook.</param>
+ /// <param name="threadHook">The thread notification hook for the communicator.</param>
+ public
+ ThreadHookPlugin(Communicator communicator, ThreadNotification threadHook)
+ {
+ if(communicator == null)
+ {
+ PluginInitializationException ex = new PluginInitializationException();
+ ex.reason = "Communicator cannot be null";
+ throw ex;
+ }
+
+ IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
+ instance.setThreadHook(threadHook);
+ }
+
+ /// <summary>
+ /// Called by the Ice run time during communicator initialization. The derived class
+ /// can override this method to perform any initialization that might be required
+ /// by the thread notification hook.
+ /// </summary>
+ public void
+ initialize()
+ {
+ }
+
+ /// <summary>
+ /// Called by the Ice run time when the communicator is destroyed. The derived class
+ /// can override this method to perform any finalization that might be required
+ /// by thread notification hook.
+ /// </summary>
+ public void
+ destroy()
+ {
+ }
+ }
+}
diff --git a/csharp/src/Ice/ThreadPool.cs b/csharp/src/Ice/ThreadPool.cs
new file mode 100644
index 00000000000..1690d8ccb5c
--- /dev/null
+++ b/csharp/src/Ice/ThreadPool.cs
@@ -0,0 +1,876 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Threading;
+
+ public delegate void ThreadPoolWorkItem();
+ public delegate void AsyncCallback(object state);
+
+ internal struct ThreadPoolMessage
+ {
+ public ThreadPoolMessage(object mutex)
+ {
+ _mutex = mutex;
+ _finish = false;
+ _finishWithIO = false;
+ }
+
+ public bool startIOScope(ref ThreadPoolCurrent current)
+ {
+ // This must be called with the handler locked.
+ _finishWithIO = current.startMessage();
+ return _finishWithIO;
+ }
+
+ public void finishIOScope(ref ThreadPoolCurrent current)
+ {
+ if(_finishWithIO)
+ {
+ lock(_mutex)
+ {
+ current.finishMessage(true);
+ }
+ }
+ }
+
+ public void completed(ref ThreadPoolCurrent current)
+ {
+ //
+ // Call finishMessage once IO is completed only if serialization is not enabled.
+ // Otherwise, finishMessage will be called when the event handler is done with
+ // the message (it will be called from destroy below).
+ //
+ Debug.Assert(_finishWithIO);
+ if(current.ioCompleted())
+ {
+ _finishWithIO = false;
+ _finish = true;
+ }
+ }
+
+ public void destroy(ref ThreadPoolCurrent current)
+ {
+ if(_finish)
+ {
+ //
+ // A ThreadPoolMessage instance must be created outside the synchronization
+ // of the event handler. We need to lock the event handler here to call
+ // finishMessage.
+ //
+ lock(_mutex)
+ {
+ current.finishMessage(false);
+ Debug.Assert(!current.completedSynchronously);
+ }
+ }
+ }
+
+ private object _mutex;
+ private bool _finish;
+ private bool _finishWithIO;
+ }
+
+ public struct ThreadPoolCurrent
+ {
+ public ThreadPoolCurrent(ThreadPool threadPool, EventHandler handler, int op)
+ {
+ _threadPool = threadPool;
+ _handler = handler;
+ operation = op;
+ completedSynchronously = false;
+ }
+
+ public readonly int operation;
+ public bool completedSynchronously;
+
+ public bool ioCompleted()
+ {
+ return _threadPool.serialize();
+ }
+
+ public bool startMessage()
+ {
+ return _threadPool.startMessage(ref this);
+ }
+
+ public void finishMessage(bool fromIOThread)
+ {
+ _threadPool.finishMessage(ref this, fromIOThread);
+ }
+
+ internal readonly ThreadPool _threadPool;
+ internal readonly EventHandler _handler;
+ }
+
+ public sealed class ThreadPool
+ {
+ public ThreadPool(Instance instance, string prefix, int timeout)
+ {
+ Ice.Properties properties = instance.initializationData().properties;
+
+ _instance = instance;
+ _dispatcher = instance.initializationData().dispatcher;
+ _destroyed = false;
+ _prefix = prefix;
+ _threadIndex = 0;
+ _inUse = 0;
+ _serialize = properties.getPropertyAsInt(_prefix + ".Serialize") > 0;
+ _serverIdleTime = timeout;
+
+ string programName = properties.getProperty("Ice.ProgramName");
+ if(programName.Length > 0)
+ {
+ _threadPrefix = programName + "-" + _prefix;
+ }
+ else
+ {
+ _threadPrefix = _prefix;
+ }
+
+ //
+ // We use just one thread as the default. This is the fastest
+ // possible setting, still allows one level of nesting, and
+ // doesn't require to make the servants thread safe.
+ //
+ int size = properties.getPropertyAsIntWithDefault(_prefix + ".Size", 1);
+ if(size < 1)
+ {
+ string s = _prefix + ".Size < 1; Size adjusted to 1";
+ _instance.initializationData().logger.warning(s);
+ size = 1;
+ }
+
+ int sizeMax = properties.getPropertyAsIntWithDefault(_prefix + ".SizeMax", size);
+ if(sizeMax < size)
+ {
+ string s = _prefix + ".SizeMax < " + _prefix + ".Size; SizeMax adjusted to Size (" + size + ")";
+ _instance.initializationData().logger.warning(s);
+ sizeMax = size;
+ }
+
+ int sizeWarn = properties.getPropertyAsInt(_prefix + ".SizeWarn");
+ if(sizeWarn != 0 && sizeWarn < size)
+ {
+ string s = _prefix + ".SizeWarn < " + _prefix + ".Size; adjusted SizeWarn to Size (" + size + ")";
+ _instance.initializationData().logger.warning(s);
+ sizeWarn = size;
+ }
+ else if(sizeWarn > sizeMax)
+ {
+ string s = _prefix + ".SizeWarn > " + _prefix + ".SizeMax; adjusted SizeWarn to SizeMax ("
+ + sizeMax + ")";
+ _instance.initializationData().logger.warning(s);
+ sizeWarn = sizeMax;
+ }
+
+ int threadIdleTime = properties.getPropertyAsIntWithDefault(_prefix + ".ThreadIdleTime", 60);
+ if(threadIdleTime < 0)
+ {
+ string s = _prefix + ".ThreadIdleTime < 0; ThreadIdleTime adjusted to 0";
+ _instance.initializationData().logger.warning(s);
+ threadIdleTime = 0;
+ }
+
+ _size = size;
+ _sizeMax = sizeMax;
+ _sizeWarn = sizeWarn;
+ _threadIdleTime = threadIdleTime;
+
+ int stackSize = properties.getPropertyAsInt(_prefix + ".StackSize");
+ if(stackSize < 0)
+ {
+ string s = _prefix + ".StackSize < 0; Size adjusted to OS default";
+ _instance.initializationData().logger.warning(s);
+ stackSize = 0;
+ }
+ _stackSize = stackSize;
+
+#if !SILVERLIGHT
+ _hasPriority = properties.getProperty(_prefix + ".ThreadPriority").Length > 0;
+ _priority = IceInternal.Util.stringToThreadPriority(properties.getProperty(_prefix + ".ThreadPriority"));
+ if(!_hasPriority)
+ {
+ _hasPriority = properties.getProperty("Ice.ThreadPriority").Length > 0;
+ _priority = IceInternal.Util.stringToThreadPriority(properties.getProperty("Ice.ThreadPriority"));
+ }
+#endif
+
+ if(_instance.traceLevels().threadPool >= 1)
+ {
+ string s = "creating " + _prefix + ": Size = " + _size + ", SizeMax = " + _sizeMax + ", SizeWarn = " +
+ _sizeWarn;
+ _instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s);
+ }
+
+ _workItems = new Queue<ThreadPoolWorkItem>();
+
+ try
+ {
+ _threads = new List<WorkerThread>();
+ for(int i = 0; i < _size; ++i)
+ {
+ WorkerThread thread = new WorkerThread(this, _threadPrefix + "-" + _threadIndex++);
+#if !SILVERLIGHT
+ if(_hasPriority)
+ {
+ thread.start(_priority);
+ }
+ else
+ {
+ thread.start(ThreadPriority.Normal);
+ }
+#else
+ thread.start();
+#endif
+ _threads.Add(thread);
+ }
+ }
+ catch(System.Exception ex)
+ {
+ string s = "cannot create thread for `" + _prefix + "':\n" + ex;
+ _instance.initializationData().logger.error(s);
+
+ destroy();
+ joinWithAllThreads();
+ throw;
+ }
+ }
+
+ public void destroy()
+ {
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ return;
+ }
+ _destroyed = true;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public void updateObservers()
+ {
+ lock(this)
+ {
+ foreach(WorkerThread t in _threads)
+ {
+ t.updateObserver();
+ }
+ }
+ }
+
+ public void initialize(EventHandler handler)
+ {
+ // Nothing to do.
+ }
+
+ public void register(EventHandler handler, int op)
+ {
+ update(handler, SocketOperation.None, op);
+ }
+
+ public void update(EventHandler handler, int remove, int add)
+ {
+ lock(this)
+ {
+ Debug.Assert(!_destroyed);
+
+ // Don't remove what needs to be added
+ remove &= ~add;
+
+ // Don't remove/add if already un-registered or registered
+ remove &= handler._registered;
+ add &= ~handler._registered;
+ if(remove == add)
+ {
+ return;
+ }
+
+ handler._registered &= ~remove;
+ handler._registered |= add;
+
+ if((add & SocketOperation.Read) != 0 && (handler._pending & SocketOperation.Read) == 0)
+ {
+ handler._pending |= SocketOperation.Read;
+ executeNonBlocking(() =>
+ {
+ messageCallback(new ThreadPoolCurrent(this, handler, SocketOperation.Read));
+ });
+ }
+ else if((add & SocketOperation.Write) != 0 && (handler._pending & SocketOperation.Write) == 0)
+ {
+ handler._pending |= SocketOperation.Write;
+ executeNonBlocking(() =>
+ {
+ messageCallback(new ThreadPoolCurrent(this, handler, SocketOperation.Write));
+ });
+ }
+ }
+ }
+
+ public void unregister(EventHandler handler, int op)
+ {
+ update(handler, op, SocketOperation.None);
+ }
+
+ public void finish(EventHandler handler)
+ {
+ lock(this)
+ {
+ Debug.Assert(!_destroyed);
+
+ //
+ // If there are no pending asynchronous operations, we can call finish on the handler now.
+ //
+ if(handler._pending == 0)
+ {
+ handler._registered = SocketOperation.None;
+ executeNonBlocking(() =>
+ {
+ ThreadPoolCurrent current = new ThreadPoolCurrent(this, handler, SocketOperation.None);
+ handler.finished(ref current);
+ });
+ }
+ else
+ {
+ handler._finish = true;
+ }
+ }
+ }
+
+#if COMPACT
+ public void dispatchFromThisThread(Ice.VoidAction call, Ice.Connection con)
+#else
+ public void dispatchFromThisThread(System.Action call, Ice.Connection con)
+#endif
+ {
+ if(_dispatcher != null)
+ {
+ try
+ {
+ _dispatcher(call, con);
+ }
+ catch(System.Exception ex)
+ {
+ if(_instance.initializationData().properties.getPropertyAsIntWithDefault(
+ "Ice.Warn.Dispatch", 1) > 1)
+ {
+ _instance.initializationData().logger.warning("dispatch exception:\n" + ex);
+ }
+ }
+ }
+ else
+ {
+ call();
+ }
+ }
+
+#if COMPACT
+ public void dispatch(Ice.VoidAction call, Ice.Connection con)
+#else
+ public void dispatch(System.Action call, Ice.Connection con)
+#endif
+ {
+ lock(this)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ _workItems.Enqueue(() =>
+ {
+ dispatchFromThisThread(call, con);
+ });
+ System.Threading.Monitor.Pulse(this);
+
+ //
+ // If this is a dynamic thread pool which can still grow and if all threads are
+ // currently busy dispatching or about to dispatch, we spawn a new thread to
+ // execute this new work item right away.
+ //
+ if(_threads.Count < _sizeMax &&
+ (_inUse + _workItems.Count) > _threads.Count &&
+ !_destroyed)
+ {
+ if(_instance.traceLevels().threadPool >= 1)
+ {
+ string s = "growing " + _prefix + ": Size = " + (_threads.Count + 1);
+ _instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s);
+ }
+
+ try
+ {
+ WorkerThread t = new WorkerThread(this, _threadPrefix + "-" + _threadIndex++);
+#if !SILVERLIGHT
+ if(_hasPriority)
+ {
+ t.start(_priority);
+ }
+ else
+ {
+ t.start(ThreadPriority.Normal);
+ }
+#else
+ t.start();
+#endif
+ _threads.Add(t);
+ }
+ catch(System.Exception ex)
+ {
+ string s = "cannot create thread for `" + _prefix + "':\n" + ex;
+ _instance.initializationData().logger.error(s);
+ }
+ }
+ }
+ }
+
+ public void executeNonBlocking(ThreadPoolWorkItem workItem)
+ {
+ lock(this)
+ {
+ Debug.Assert(!_destroyed);
+ _instance.asyncIOThread().queue(workItem);
+ }
+ }
+
+ public void joinWithAllThreads()
+ {
+ //
+ // _threads is immutable after destroy() has been called,
+ // therefore no synchronization is needed. (Synchronization
+ // wouldn't be possible here anyway, because otherwise the
+ // other threads would never terminate.)
+ //
+ Debug.Assert(_destroyed);
+ foreach(WorkerThread thread in _threads)
+ {
+ thread.join();
+ }
+ }
+
+ public string prefix()
+ {
+ return _prefix;
+ }
+
+ public bool serialize()
+ {
+ return _serialize;
+ }
+
+ private void run(WorkerThread thread)
+ {
+ ThreadPoolWorkItem workItem = null;
+ while(true)
+ {
+ lock(this)
+ {
+ if(workItem != null)
+ {
+ Debug.Assert(_inUse > 0);
+ --_inUse;
+ if(_workItems.Count == 0)
+ {
+ thread.setState(Ice.Instrumentation.ThreadState.ThreadStateIdle);
+ }
+ }
+
+ workItem = null;
+
+ while(_workItems.Count == 0)
+ {
+ if(_destroyed)
+ {
+ return;
+ }
+
+ if(_threadIdleTime > 0)
+ {
+ if(!System.Threading.Monitor.Wait(this, _threadIdleTime * 1000) && _workItems.Count == 0) // If timeout
+ {
+ if(_destroyed)
+ {
+ return;
+ }
+ else if(_serverIdleTime == 0 || _threads.Count > 1)
+ {
+ //
+ // If not the last thread or if server idle time isn't configured,
+ // we can exit. Unlike C++/Java, there's no need to have a thread
+ // always spawned in the thread pool because all the IO is done
+ // by the .NET thread pool threads. Instead, we'll just spawn a
+ // new thread when needed (i.e.: when a new work item is queued).
+ //
+ if(_instance.traceLevels().threadPool >= 1)
+ {
+ string s = "shrinking " + _prefix + ": Size=" + (_threads.Count - 1);
+ _instance.initializationData().logger.trace(
+ _instance.traceLevels().threadPoolCat, s);
+ }
+
+ _threads.Remove(thread);
+ _instance.asyncIOThread().queue(() =>
+ {
+ thread.join();
+ });
+ return;
+ }
+ else
+ {
+ Debug.Assert(_serverIdleTime > 0 && _inUse == 0 && _threads.Count == 1);
+ if(!System.Threading.Monitor.Wait(this, _serverIdleTime * 1000) &&
+ _workItems.Count == 0)
+ {
+ if(!_destroyed)
+ {
+ _workItems.Enqueue(() =>
+ {
+ try
+ {
+ _instance.objectAdapterFactory().shutdown();
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+ }
+
+ Debug.Assert(_workItems.Count > 0);
+ workItem = _workItems.Dequeue();
+
+ Debug.Assert(_inUse >= 0);
+ ++_inUse;
+
+ thread.setState(Ice.Instrumentation.ThreadState.ThreadStateInUseForUser);
+
+ if(_sizeMax > 1 && _inUse == _sizeWarn)
+ {
+ string s = "thread pool `" + _prefix + "' is running low on threads\n"
+ + "Size=" + _size + ", " + "SizeMax=" + _sizeMax + ", " + "SizeWarn=" + _sizeWarn;
+ _instance.initializationData().logger.warning(s);
+ }
+ }
+
+ try
+ {
+ workItem();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception in `" + _prefix + "' while calling on work item:\n" + ex + '\n';
+ _instance.initializationData().logger.error(s);
+ }
+ }
+ }
+
+ public bool startMessage(ref ThreadPoolCurrent current)
+ {
+ Debug.Assert((current._handler._pending & current.operation) != 0);
+
+ if((current._handler._started & current.operation) != 0)
+ {
+ Debug.Assert((current._handler._ready & current.operation) == 0);
+ current._handler._ready |= current.operation;
+ current._handler._started &= ~current.operation;
+ if(!current._handler.finishAsync(current.operation)) // Returns false if the handler is finished.
+ {
+ current._handler._pending &= ~current.operation;
+ if(current._handler._pending == 0 && current._handler._finish)
+ {
+ finish(current._handler);
+ }
+ return false;
+ }
+ }
+ else if((current._handler._ready & current.operation) == 0 &&
+ (current._handler._registered & current.operation) != 0)
+ {
+ Debug.Assert((current._handler._started & current.operation) == 0);
+ bool completed = false;
+ if(!current._handler.startAsync(current.operation, getCallback(current.operation), ref completed))
+ {
+ current._handler._pending &= ~current.operation;
+ if(current._handler._pending == 0 && current._handler._finish)
+ {
+ finish(current._handler);
+ }
+ return false;
+ }
+ else
+ {
+ current.completedSynchronously = completed;
+ current._handler._started |= current.operation;
+ return false;
+ }
+ }
+
+ if((current._handler._registered & current.operation) != 0)
+ {
+ Debug.Assert((current._handler._ready & current.operation) != 0);
+ current._handler._ready &= ~current.operation;
+ return true;
+ }
+ else
+ {
+ current._handler._pending &= ~current.operation;
+ if(current._handler._pending == 0 && current._handler._finish)
+ {
+ finish(current._handler);
+ }
+ return false;
+ }
+ }
+
+ public void finishMessage(ref ThreadPoolCurrent current, bool fromIOThread)
+ {
+ if((current._handler._registered & current.operation) != 0)
+ {
+ if(fromIOThread)
+ {
+ Debug.Assert((current._handler._ready & current.operation) == 0);
+ bool completed = false;
+ if(!current._handler.startAsync(current.operation, getCallback(current.operation), ref completed))
+ {
+ current._handler._pending &= ~current.operation;
+ }
+ else
+ {
+ Debug.Assert((current._handler._pending & current.operation) != 0);
+ current.completedSynchronously = completed;
+ current._handler._started |= current.operation;
+ }
+ }
+ else
+ {
+ ThreadPoolCurrent c = current;
+ executeNonBlocking(() =>
+ {
+ messageCallback(c);
+ });
+ }
+ }
+ else
+ {
+ current._handler._pending &= ~current.operation;
+ }
+
+ if(current._handler._pending == 0 && current._handler._finish)
+ {
+ // There are no more pending async operations, it's time to call finish.
+ finish(current._handler);
+ }
+ }
+
+ public void asyncReadCallback(object state)
+ {
+ messageCallback(new ThreadPoolCurrent(this, (EventHandler)state, SocketOperation.Read));
+ }
+
+ public void asyncWriteCallback(object state)
+ {
+ messageCallback(new ThreadPoolCurrent(this, (EventHandler)state, SocketOperation.Write));
+ }
+
+ public void messageCallback(ThreadPoolCurrent current)
+ {
+ try
+ {
+ do
+ {
+ current.completedSynchronously = false;
+ current._handler.message(ref current);
+ }
+ while(current.completedSynchronously);
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception in `" + _prefix + "':\n" + ex + "\nevent handler: " + current._handler.ToString();
+ _instance.initializationData().logger.error(s);
+ }
+ }
+
+ private AsyncCallback getCallback(int operation)
+ {
+ switch(operation)
+ {
+ case SocketOperation.Read:
+ return asyncReadCallback;
+ case SocketOperation.Write:
+ return asyncWriteCallback;
+ default:
+ Debug.Assert(false);
+ return null;
+ }
+ }
+
+ private Instance _instance;
+ private Ice.Dispatcher _dispatcher;
+ private bool _destroyed;
+ private readonly string _prefix;
+ private readonly string _threadPrefix;
+
+ private sealed class WorkerThread
+ {
+ private ThreadPool _threadPool;
+ private Ice.Instrumentation.ThreadObserver _observer;
+ private Ice.Instrumentation.ThreadState _state;
+
+ internal WorkerThread(ThreadPool threadPool, string name) : base()
+ {
+ _threadPool = threadPool;
+ _name = name;
+ _state = Ice.Instrumentation.ThreadState.ThreadStateIdle;
+ updateObserver();
+ }
+
+ public void updateObserver()
+ {
+ // Must be called with the thread pool mutex locked
+ Ice.Instrumentation.CommunicatorObserver obsv = _threadPool._instance.initializationData().observer;
+ if(obsv != null)
+ {
+ _observer = obsv.getThreadObserver(_threadPool._prefix, _name, _state, _observer);
+ if(_observer != null)
+ {
+ _observer.attach();
+ }
+ }
+ }
+
+ public void setState(Ice.Instrumentation.ThreadState s)
+ {
+ // Must be called with the thread pool mutex locked
+ if(_observer != null)
+ {
+ if(_state != s)
+ {
+ _observer.stateChanged(_state, s);
+ }
+ }
+ _state = s;
+ }
+
+ public void join()
+ {
+ _thread.Join();
+ }
+
+#if !SILVERLIGHT
+ public void start(ThreadPriority priority)
+ {
+ if(_threadPool._stackSize == 0)
+ {
+ _thread = new Thread(new ThreadStart(Run));
+ }
+ else
+ {
+ _thread = new Thread(new ThreadStart(Run), _threadPool._stackSize);
+ }
+ _thread.IsBackground = true;
+ _thread.Name = _name;
+ _thread.Priority = priority;
+ _thread.Start();
+ }
+#else
+ public void start()
+ {
+ _thread = new Thread(new ThreadStart(Run));
+ _thread.IsBackground = true;
+ _thread.Name = _name;
+ _thread.Start();
+ }
+#endif
+
+ public void Run()
+ {
+ if(_threadPool._instance.initializationData().threadHook != null)
+ {
+ try
+ {
+ _threadPool._instance.initializationData().threadHook.start();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "thread hook start() method raised an unexpected exception in `";
+ s += _threadPool._prefix + "' thread " + _thread.Name + ":\n" + ex;
+ _threadPool._instance.initializationData().logger.error(s);
+ }
+ }
+
+ try
+ {
+ _threadPool.run(this);
+ }
+ catch(System.Exception ex)
+ {
+ string s = "exception in `" + _threadPool._prefix + "' thread " + _thread.Name + ":\n" + ex;
+ _threadPool._instance.initializationData().logger.error(s);
+ }
+
+ if(_observer != null)
+ {
+ _observer.detach();
+ }
+
+ if(_threadPool._instance.initializationData().threadHook != null)
+ {
+ try
+ {
+ _threadPool._instance.initializationData().threadHook.stop();
+ }
+ catch(System.Exception ex)
+ {
+ string s = "thread hook stop() method raised an unexpected exception in `";
+ s += _threadPool._prefix + "' thread " + _thread.Name + ":\n" + ex;
+ _threadPool._instance.initializationData().logger.error(s);
+ }
+ }
+ }
+
+ private readonly string _name;
+ private Thread _thread;
+ }
+
+ private readonly int _size; // Number of threads that are pre-created.
+ private readonly int _sizeMax; // Maximum number of threads.
+ private readonly int _sizeWarn; // If _inUse reaches _sizeWarn, a "low on threads" warning will be printed.
+ private readonly bool _serialize; // True if requests need to be serialized over the connection.
+#if !SILVERLIGHT
+ private readonly ThreadPriority _priority;
+ private readonly bool _hasPriority = false;
+#endif
+ private readonly int _serverIdleTime;
+ private readonly int _threadIdleTime;
+ private readonly int _stackSize;
+
+ private List<WorkerThread> _threads; // All threads, running or not.
+ private int _threadIndex; // For assigning thread names.
+ private int _inUse; // Number of threads that are currently in use.
+
+ private Queue<ThreadPoolWorkItem> _workItems;
+ }
+
+}
diff --git a/csharp/src/Ice/TieBase.cs b/csharp/src/Ice/TieBase.cs
new file mode 100644
index 00000000000..a88b301a913
--- /dev/null
+++ b/csharp/src/Ice/TieBase.cs
@@ -0,0 +1,30 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ /// <summary>
+ /// Interface for servants using the tie mapping.
+ /// </summary>
+ public interface TieBase
+ {
+ /// <summary>
+ /// Returns the delegate for this tie.
+ /// </summary>
+ /// <returns>The delegate.</returns>
+ object ice_delegate();
+
+ /// <summary>
+ /// Returns the delegate for this tie.
+ /// </summary>
+ /// <param name="o">The delegate.</param>
+ void ice_delegate(object o);
+ }
+
+}
diff --git a/csharp/src/Ice/Time.cs b/csharp/src/Ice/Time.cs
new file mode 100644
index 00000000000..85f68b438f3
--- /dev/null
+++ b/csharp/src/Ice/Time.cs
@@ -0,0 +1,103 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+#if !SILVERLIGHT
+ using System.Diagnostics;
+
+ public sealed class Time
+ {
+ static Time()
+ {
+ _stopwatch.Start();
+ }
+
+ public static long currentMonotonicTimeMillis()
+ {
+ return _stopwatch.ElapsedMilliseconds;
+ }
+
+ private static Stopwatch _stopwatch = new Stopwatch();
+ }
+
+#else
+
+ public class Stopwatch
+ {
+ public void Start()
+ {
+ if(!_running)
+ {
+ _startTick = System.DateTime.Now.Ticks;
+ _running = true;
+ }
+ }
+
+ public void Stop()
+ {
+ if(_running)
+ {
+ _elapsedTicks += System.DateTime.Now.Ticks - _startTick;
+ _running = false;
+ }
+
+ }
+
+ public void Reset()
+ {
+ _startTick = 0;
+ _elapsedTicks = 0;
+ _running = false;
+ }
+
+ public long ElapsedTicks
+ {
+ get
+ {
+ if(!_running)
+ {
+ return _elapsedTicks;
+ }
+ else
+ {
+ return _elapsedTicks + (System.DateTime.Now.Ticks - _startTick);
+ }
+ }
+ }
+
+ public long Frequency
+ {
+ get
+ {
+ return System.TimeSpan.TicksPerMillisecond * 1000;
+ }
+ }
+
+ private long _startTick = 0;
+ private long _elapsedTicks = 0;
+ private bool _running = false;
+ }
+
+ public sealed class Time
+ {
+ static Time()
+ {
+ _begin = System.DateTime.Now.Ticks;
+ }
+
+ public static long currentMonotonicTimeMillis()
+ {
+ return (System.DateTime.Now.Ticks - _begin) / 10000;
+ }
+
+ private static long _begin;
+ }
+#endif
+}
diff --git a/csharp/src/Ice/Timer.cs b/csharp/src/Ice/Timer.cs
new file mode 100644
index 00000000000..9c13bb67b7f
--- /dev/null
+++ b/csharp/src/Ice/Timer.cs
@@ -0,0 +1,413 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+//
+// NOTE: We don't use C# timers, the API is quite a bit different from
+// the C++ & Java timers and it's not clear what is the cost of
+// scheduling and cancelling timers.
+//
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Threading;
+ using System.Collections;
+ using System.Collections.Generic;
+
+ public interface TimerTask
+ {
+ void runTimerTask();
+ }
+
+ public sealed class Timer
+ {
+ public void destroy()
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ return;
+ }
+
+ _instance = null;
+ System.Threading.Monitor.Pulse(this);
+
+ _tokens.Clear();
+ _tasks.Clear();
+ }
+
+ _thread.Join();
+ }
+
+ public void schedule(TimerTask task, long delay)
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Token token = new Token(Time.currentMonotonicTimeMillis() + delay, ++_tokenId, 0, task);
+
+ try
+ {
+ _tasks.Add(task, token);
+#if SILVERLIGHT
+ int index = _tokens.BinarySearch(token);
+ Debug.Assert(index < 0);
+ if(index < 0)
+ {
+ _tokens.Insert(~index, token);
+ }
+#else
+ _tokens.Add(token, null);
+#endif
+ }
+ catch(System.ArgumentException)
+ {
+ Debug.Assert(false);
+ }
+
+ if(token.scheduledTime < _wakeUpTime)
+ {
+ System.Threading.Monitor.Pulse(this);
+ }
+ }
+ }
+
+ public void scheduleRepeated(TimerTask task, long period)
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Token token = new Token(Time.currentMonotonicTimeMillis() + period, ++_tokenId, period, task);
+
+ try
+ {
+ _tasks.Add(task, token);
+#if SILVERLIGHT
+ int index = _tokens.BinarySearch(token);
+ Debug.Assert(index < 0);
+ if(index < 0)
+ {
+ _tokens.Insert(~index, token);
+ }
+#else
+ _tokens.Add(token, null);
+#endif
+ }
+ catch(System.ArgumentException)
+ {
+ Debug.Assert(false);
+ }
+
+ if(token.scheduledTime < _wakeUpTime)
+ {
+ System.Threading.Monitor.Pulse(this);
+ }
+ }
+ }
+
+ public bool cancel(TimerTask task)
+ {
+ lock(this)
+ {
+ if(_instance == null)
+ {
+ return false;
+ }
+
+ Token token;
+ if(!_tasks.TryGetValue(task, out token))
+ {
+ return false;
+ }
+ _tasks.Remove(task);
+ _tokens.Remove(token);
+ return true;
+ }
+ }
+
+ //
+ // Only for use by Instance.
+ //
+#if !SILVERLIGHT
+ internal Timer(IceInternal.Instance instance, ThreadPriority priority)
+ {
+ init(instance, priority, true);
+ }
+#endif
+
+ internal Timer(IceInternal.Instance instance)
+ {
+#if !SILVERLIGHT
+ init(instance, ThreadPriority.Normal, false);
+#else
+ init(instance);
+#endif
+ }
+
+#if !SILVERLIGHT
+ internal void init(IceInternal.Instance instance, ThreadPriority priority, bool hasPriority)
+#else
+ internal void init(IceInternal.Instance instance)
+#endif
+ {
+ _instance = instance;
+
+ string threadName = _instance.initializationData().properties.getProperty("Ice.ProgramName");
+ if(threadName.Length > 0)
+ {
+ threadName += "-";
+ }
+
+ _thread = new Thread(new ThreadStart(Run));
+ _thread.IsBackground = true;
+ _thread.Name = threadName + "Ice.Timer";
+#if !SILVERLIGHT
+ if(hasPriority)
+ {
+ _thread.Priority = priority;
+ }
+#endif
+ _thread.Start();
+ }
+
+ internal void updateObserver(Ice.Instrumentation.CommunicatorObserver obsv)
+ {
+ lock(this)
+ {
+ Debug.Assert(obsv != null);
+ _observer = obsv.getThreadObserver("Communicator",
+ _thread.Name,
+ Ice.Instrumentation.ThreadState.ThreadStateIdle,
+ _observer);
+ if(_observer != null)
+ {
+ _observer.attach();
+ }
+ }
+ }
+
+ public void Run()
+ {
+ Token token = null;
+ while(true)
+ {
+ lock(this)
+ {
+ if(_instance != null)
+ {
+ //
+ // If the task we just ran is a repeated task, schedule it
+ // again for execution if it wasn't canceled.
+ //
+ if(token != null && token.delay > 0)
+ {
+ if(_tasks.ContainsKey(token.task))
+ {
+ token.scheduledTime = Time.currentMonotonicTimeMillis() + token.delay;
+#if SILVERLIGHT
+ int index = _tokens.BinarySearch(token);
+ Debug.Assert(index < 0);
+ if(index < 0)
+ {
+ _tokens.Insert(~index, token);
+ }
+#else
+ _tokens.Add(token, null);
+#endif
+ }
+ }
+ }
+ token = null;
+
+ if(_instance == null)
+ {
+ break;
+ }
+
+ if(_tokens.Count == 0)
+ {
+ _wakeUpTime = System.Int64.MaxValue;
+ System.Threading.Monitor.Wait(this);
+ }
+
+ if(_instance == null)
+ {
+ break;
+ }
+
+ while(_tokens.Count > 0 && _instance != null)
+ {
+ long now = Time.currentMonotonicTimeMillis();
+
+ Token first = null;
+#if SILVERLIGHT
+ foreach(Token t in _tokens)
+#else
+ foreach(Token t in _tokens.Keys)
+#endif
+ {
+ first = t;
+ break;
+ }
+ Debug.Assert(first != null);
+
+ if(first.scheduledTime <= now)
+ {
+ _tokens.Remove(first);
+ token = first;
+ if(token.delay == 0)
+ {
+ _tasks.Remove(token.task);
+ }
+ break;
+ }
+
+ _wakeUpTime = first.scheduledTime;
+ System.Threading.Monitor.Wait(this, (int)(first.scheduledTime - now));
+ }
+
+ if(_instance == null)
+ {
+ break;
+ }
+ }
+
+ if(token != null)
+ {
+ try
+ {
+ Ice.Instrumentation.ThreadObserver threadObserver = _observer;
+ if(threadObserver != null)
+ {
+ threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle,
+ Ice.Instrumentation.ThreadState.ThreadStateInUseForOther);
+ try
+ {
+ token.task.runTimerTask();
+ }
+ finally
+ {
+ threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForOther,
+ Ice.Instrumentation.ThreadState.ThreadStateIdle);
+ }
+ }
+ else
+ {
+ token.task.runTimerTask();
+ }
+ }
+ catch(System.Exception ex)
+ {
+ lock(this)
+ {
+ if(_instance != null)
+ {
+ string s = "unexpected exception from task run method in timer thread:\n" + ex;
+ _instance.initializationData().logger.error(s);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private class Token : System.IComparable
+ {
+ public
+ Token(long scheduledTime, int id, long delay, TimerTask task)
+ {
+ this.scheduledTime = scheduledTime;
+ this.id = id;
+ this.delay = delay;
+ this.task = task;
+ }
+
+ public int CompareTo(object o)
+ {
+ //
+ // Token are sorted by scheduled time and token id.
+ //
+ Token r = (Token)o;
+ if(scheduledTime < r.scheduledTime)
+ {
+ return -1;
+ }
+ else if(scheduledTime > r.scheduledTime)
+ {
+ return 1;
+ }
+
+ if(id < r.id)
+ {
+ return -1;
+ }
+ else if(id > r.id)
+ {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ public override bool Equals(object o)
+ {
+ if(object.ReferenceEquals(this, o))
+ {
+ return true;
+ }
+ Token t = o as Token;
+ return t == null ? false : CompareTo(t) == 0;
+ }
+
+ public override int GetHashCode()
+ {
+ int h = 5381;
+ IceInternal.HashUtil.hashAdd(ref h, id);
+ IceInternal.HashUtil.hashAdd(ref h, scheduledTime);
+ return h;
+ }
+
+ public long scheduledTime;
+ public int id; // Since we can't compare references, we need to use another id.
+ public long delay;
+ public TimerTask task;
+ }
+
+#if COMPACT
+ private IDictionary<Token, object> _tokens = new SortedList<Token, object>();
+#elif SILVERLIGHT
+ private List<Token> _tokens = new List<Token>();
+#else
+ private IDictionary<Token, object> _tokens = new SortedDictionary<Token, object>();
+#endif
+ private IDictionary<TimerTask, Token> _tasks = new Dictionary<TimerTask, Token>();
+ private Instance _instance;
+ private long _wakeUpTime = System.Int64.MaxValue;
+ private int _tokenId = 0;
+ private Thread _thread;
+
+ //
+ // We use a volatile to avoid synchronization when reading
+ // _observer. Reference assignement is atomic in Java so it
+ // also doesn't need to be synchronized.
+ //
+ private volatile Ice.Instrumentation.ThreadObserver _observer;
+}
+
+}
diff --git a/csharp/src/Ice/TraceLevels.cs b/csharp/src/Ice/TraceLevels.cs
new file mode 100644
index 00000000000..dd6b606dc3b
--- /dev/null
+++ b/csharp/src/Ice/TraceLevels.cs
@@ -0,0 +1,48 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ public sealed class TraceLevels
+ {
+ internal TraceLevels(Ice.Properties properties)
+ {
+ networkCat = "Network";
+ protocolCat = "Protocol";
+ retryCat = "Retry";
+ locationCat = "Locator";
+ slicingCat = "Slicing";
+ threadPoolCat = "ThreadPool";
+
+ string keyBase = "Ice.Trace.";
+
+ network = properties.getPropertyAsInt(keyBase + networkCat);
+ protocol = properties.getPropertyAsInt(keyBase + protocolCat);
+ retry = properties.getPropertyAsInt(keyBase + retryCat);
+ location = properties.getPropertyAsInt(keyBase + locationCat);
+ slicing = properties.getPropertyAsInt(keyBase + slicingCat);
+ threadPool = properties.getPropertyAsInt(keyBase + threadPoolCat);
+ }
+
+ public readonly int network;
+ public readonly string networkCat;
+ public readonly int protocol;
+ public readonly string protocolCat;
+ public readonly int retry;
+ public readonly string retryCat;
+ public readonly int location;
+ public readonly string locationCat;
+ public readonly int slicing;
+ public readonly string slicingCat;
+ public readonly int threadPool;
+ public readonly string threadPoolCat;
+ }
+
+}
diff --git a/csharp/src/Ice/TraceUtil.cs b/csharp/src/Ice/TraceUtil.cs
new file mode 100644
index 00000000000..70ba169698e
--- /dev/null
+++ b/csharp/src/Ice/TraceUtil.cs
@@ -0,0 +1,504 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Globalization;
+
+ sealed class TraceUtil
+ {
+ internal static void traceSend(BasicStream str, Ice.Logger logger, TraceLevels tl)
+ {
+ if(tl.protocol >= 1)
+ {
+ int p = str.pos();
+ str.pos(0);
+
+ using(System.IO.StringWriter s = new System.IO.StringWriter(CultureInfo.CurrentCulture))
+ {
+ byte type = printMessage(s, str);
+
+ logger.trace(tl.protocolCat, "sending " + getMessageTypeAsString(type) + " " + s.ToString());
+ }
+ str.pos(p);
+ }
+ }
+
+ internal static void traceRecv(BasicStream str, Ice.Logger logger, TraceLevels tl)
+ {
+ if(tl.protocol >= 1)
+ {
+ int p = str.pos();
+ str.pos(0);
+
+ using(System.IO.StringWriter s = new System.IO.StringWriter(CultureInfo.CurrentCulture))
+ {
+ byte type = printMessage(s, str);
+
+ logger.trace(tl.protocolCat, "received " + getMessageTypeAsString(type) + " " + s.ToString());
+ }
+ str.pos(p);
+ }
+ }
+
+ internal static void trace(string heading, BasicStream str, Ice.Logger logger, TraceLevels tl)
+ {
+ if(tl.protocol >= 1)
+ {
+ int p = str.pos();
+ str.pos(0);
+
+ using(System.IO.StringWriter s = new System.IO.StringWriter(CultureInfo.CurrentCulture))
+ {
+ s.Write(heading);
+ printMessage(s, str);
+
+ logger.trace(tl.protocolCat, s.ToString());
+ }
+ str.pos(p);
+ }
+ }
+
+ private static HashSet<string> slicingIds = new HashSet<string>();
+
+ internal static void traceSlicing(string kind, string typeId, string slicingCat, Ice.Logger logger)
+ {
+ lock(typeof(IceInternal.TraceUtil))
+ {
+ if(slicingIds.Add(typeId))
+ {
+ using(System.IO.StringWriter s = new System.IO.StringWriter(CultureInfo.CurrentCulture))
+ {
+ s.Write("unknown " + kind + " type `" + typeId + "'");
+ logger.trace(slicingCat, s.ToString());
+ }
+ }
+ }
+ }
+
+ public static void dumpStream(BasicStream stream)
+ {
+ int pos = stream.pos();
+ stream.pos(0);
+
+ byte[] data = new byte[stream.size()];
+ stream.readBlob(data);
+ dumpOctets(data);
+
+ stream.pos(pos);
+ }
+
+ public static void dumpOctets(byte[] data)
+ {
+ const int inc = 8;
+
+ for(int i = 0; i < data.Length; i += inc)
+ {
+ for(int j = i; j - i < inc; j++)
+ {
+ if(j < data.Length)
+ {
+ int n = (int)data[j];
+ if(n < 0)
+ {
+ n += 256;
+ }
+ string s;
+ if(n < 10)
+ {
+ s = " " + n;
+ }
+ else if(n < 100)
+ {
+ s = " " + n;
+ }
+ else
+ {
+ s = "" + n;
+ }
+ System.Console.Out.Write(s + " ");
+ }
+ else
+ {
+ System.Console.Out.Write(" ");
+ }
+ }
+
+ System.Console.Out.Write('"');
+
+ for(int j = i; j < data.Length && j - i < inc; j++)
+ {
+ // TODO: this needs fixing
+ if(data[j] >= (byte)32 && data[j] < (byte)127)
+ {
+ System.Console.Out.Write((char) data[j]);
+ }
+ else
+ {
+ System.Console.Out.Write('.');
+ }
+ }
+
+ System.Console.Out.WriteLine('"');
+ }
+ }
+
+ private static void printIdentityFacetOperation(System.IO.StringWriter s, BasicStream str)
+ {
+ try
+ {
+ Ice.Identity identity = new Ice.Identity();
+ identity.read__(str);
+ s.Write("\nidentity = " + str.instance().identityToString(identity));
+
+ string[] facet = str.readStringSeq();
+ s.Write("\nfacet = ");
+ if(facet.Length > 0)
+ {
+ s.Write(IceUtilInternal.StringUtil.escapeString(facet[0], ""));
+ }
+
+ string operation = str.readString();
+ s.Write("\noperation = " + operation);
+ }
+ catch(System.IO.IOException)
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ private static void printRequest(System.IO.StringWriter s, BasicStream str)
+ {
+ int requestId = str.readInt();
+ s.Write("\nrequest id = " + requestId);
+ if(requestId == 0)
+ {
+ s.Write(" (oneway)");
+ }
+
+ printRequestHeader(s, str);
+ }
+
+ private static void printBatchRequest(System.IO.StringWriter s, BasicStream str)
+ {
+ int batchRequestNum = str.readInt();
+ s.Write("\nnumber of requests = " + batchRequestNum);
+
+ for(int i = 0; i < batchRequestNum; ++i)
+ {
+ s.Write("\nrequest #" + i + ':');
+ printRequestHeader(s, str);
+ }
+ }
+
+ private static void printReply(System.IO.StringWriter s, BasicStream str)
+ {
+ int requestId = str.readInt();
+ s.Write("\nrequest id = " + requestId);
+
+ byte replyStatus = str.readByte();
+ s.Write("\nreply status = " + (int)replyStatus + ' ');
+
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyOK:
+ {
+ s.Write("(ok)");
+ break;
+ }
+
+ case ReplyStatus.replyUserException:
+ {
+ s.Write("(user exception)");
+ break;
+ }
+
+ case ReplyStatus.replyObjectNotExist:
+ case ReplyStatus.replyFacetNotExist:
+ case ReplyStatus.replyOperationNotExist:
+ {
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyObjectNotExist:
+ {
+ s.Write("(object not exist)");
+ break;
+ }
+
+ case ReplyStatus.replyFacetNotExist:
+ {
+ s.Write("(facet not exist)");
+ break;
+ }
+
+ case ReplyStatus.replyOperationNotExist:
+ {
+ s.Write("(operation not exist)");
+ break;
+ }
+
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+
+ printIdentityFacetOperation(s, str);
+ break;
+ }
+
+ case ReplyStatus.replyUnknownException:
+ case ReplyStatus.replyUnknownLocalException:
+ case ReplyStatus.replyUnknownUserException:
+ {
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyUnknownException:
+ {
+ s.Write("(unknown exception)");
+ break;
+ }
+
+ case ReplyStatus.replyUnknownLocalException:
+ {
+ s.Write("(unknown local exception)");
+ break;
+ }
+
+ case ReplyStatus.replyUnknownUserException:
+ {
+ s.Write("(unknown user exception)");
+ break;
+ }
+
+ default:
+ {
+ Debug.Assert(false);
+ break;
+ }
+ }
+
+ string unknown = str.readString();
+ s.Write("\nunknown = " + unknown);
+ break;
+ }
+
+ default:
+ {
+ s.Write("(unknown)");
+ break;
+ }
+ }
+ }
+
+ private static void printRequestHeader(System.IO.StringWriter s, BasicStream str)
+ {
+ printIdentityFacetOperation(s, str);
+
+ try
+ {
+ byte mode = str.readByte();
+ s.Write("\nmode = " + (int)mode + ' ');
+ switch((Ice.OperationMode)mode)
+ {
+ case Ice.OperationMode.Normal:
+ {
+ s.Write("(normal)");
+ break;
+ }
+
+ case Ice.OperationMode.Nonmutating:
+ {
+ s.Write("(nonmutating)");
+ break;
+ }
+
+ case Ice.OperationMode.Idempotent:
+ {
+ s.Write("(idempotent)");
+ break;
+ }
+
+ default:
+ {
+ s.Write("(unknown)");
+ break;
+ }
+ }
+
+ int sz = str.readSize();
+ s.Write("\ncontext = ");
+ while(sz-- > 0)
+ {
+ string key = str.readString();
+ string val = str.readString();
+ s.Write(key + '/' + val);
+ if(sz > 0)
+ {
+ s.Write(", ");
+ }
+ }
+
+ Ice.EncodingVersion v = str.skipEncaps();
+ if(!v.Equals(Ice.Util.Encoding_1_0))
+ {
+ s.Write("\nencoding = ");
+ s.Write(Ice.Util.encodingVersionToString(v));
+ }
+ }
+ catch(System.IO.IOException)
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ private static byte printHeader(System.IO.StringWriter s, BasicStream str)
+ {
+ try
+ {
+ str.readByte(); // Don't bother printing the magic number
+ str.readByte();
+ str.readByte();
+ str.readByte();
+
+ /* byte pMajor = */ str.readByte();
+ /* byte pMinor = */ str.readByte();
+ //s.Write("\nprotocol version = " + (int)pMajor + "." + (int)pMinor);
+
+ /* byte eMajor = */ str.readByte();
+ /* byte eMinor = */ str.readByte();
+ //s.Write("\nencoding version = " + (int)eMajor + "." + (int)eMinor);
+
+ byte type = str.readByte();
+ s.Write("\nmessage type = " + (int)type + " (" + getMessageTypeAsString(type) + ')');
+
+ byte compress = str.readByte();
+ s.Write("\ncompression status = " + (int)compress + ' ');
+ switch(compress)
+ {
+ case (byte)0:
+ {
+ s.Write("(not compressed; do not compress response, if any)");
+ break;
+ }
+
+ case (byte)1:
+ {
+ s.Write("(not compressed; compress response, if any)");
+ break;
+ }
+
+ case (byte)2:
+ {
+ s.Write("(compressed; compress response, if any)");
+ break;
+ }
+
+ default:
+ {
+ s.Write("(unknown)");
+ break;
+ }
+ }
+
+ int size = str.readInt();
+ s.Write("\nmessage size = " + size);
+ return type;
+ }
+ catch(System.IO.IOException)
+ {
+ Debug.Assert(false);
+ return 0;
+ }
+ }
+
+ private static byte printMessage(System.IO.StringWriter s, BasicStream str)
+ {
+ byte type = printHeader(s, str);
+
+ switch(type)
+ {
+ case Protocol.closeConnectionMsg:
+ case Protocol.validateConnectionMsg:
+ {
+ // We're done.
+ break;
+ }
+
+ case Protocol.requestMsg:
+ {
+ printRequest(s, str);
+ break;
+ }
+
+ case Protocol.requestBatchMsg:
+ {
+ printBatchRequest(s, str);
+ break;
+ }
+
+ case Protocol.replyMsg:
+ {
+ printReply(s, str);
+ break;
+ }
+
+ default:
+ {
+ s.Write("(unknown)");
+ break;
+ }
+ }
+
+ return type;
+ }
+
+ internal static void traceHeader(string heading, BasicStream str, Ice.Logger logger, TraceLevels tl)
+ {
+ if(tl.protocol >= 1)
+ {
+ int p = str.pos();
+ str.pos(0);
+
+ using(System.IO.StringWriter s = new System.IO.StringWriter(CultureInfo.CurrentCulture))
+ {
+ s.Write(heading);
+ printHeader(s, str);
+
+ logger.trace(tl.protocolCat, s.ToString());
+ }
+ str.pos(p);
+ }
+ }
+
+ private static string getMessageTypeAsString(byte type)
+ {
+ switch(type)
+ {
+ case Protocol.requestMsg:
+ return "request";
+ case Protocol.requestBatchMsg:
+ return "batch request";
+ case Protocol.replyMsg:
+ return "reply";
+ case Protocol.closeConnectionMsg:
+ return "close connection";
+ case Protocol.validateConnectionMsg:
+ return "validate connection";
+ default:
+ return "unknown";
+ }
+ }
+ }
+
+}
diff --git a/csharp/src/Ice/Transceiver.cs b/csharp/src/Ice/Transceiver.cs
new file mode 100644
index 00000000000..4208c96dfc1
--- /dev/null
+++ b/csharp/src/Ice/Transceiver.cs
@@ -0,0 +1,59 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Net.Sockets;
+
+ public interface Transceiver
+ {
+ Socket fd();
+ int initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData);
+ int closing(bool initiator, Ice.LocalException ex);
+ void close();
+ void destroy();
+
+ EndpointI bind();
+ int write(Buffer buf);
+ int read(Buffer buf, ref bool hasMoreData);
+
+ //
+ // Read data asynchronously.
+ //
+ // The I/O request may complete synchronously, in which case finishRead
+ // will be invoked in the same thread as startRead. The caller must check
+ // the buffer after finishRead completes to determine whether all of the
+ // requested data has been read.
+ //
+ // The read request is canceled upon the termination of the thread that
+ // calls startRead, or when the socket is closed. In this case finishRead
+ // raises ReadAbortedException.
+ //
+ bool startRead(Buffer buf, AsyncCallback callback, object state);
+ void finishRead(Buffer buf);
+
+ //
+ // Write data asynchronously.
+ //
+ // The I/O request may complete synchronously, in which case finishWrite
+ // will be invoked in the same thread as startWrite. The request
+ // will be canceled upon the termination of the thread that calls startWrite.
+ //
+ bool startWrite(Buffer buf, AsyncCallback callback, object state, out bool completed);
+ void finishWrite(Buffer buf);
+
+ string protocol();
+ string toDetailedString();
+ Ice.ConnectionInfo getInfo();
+ void checkSendSize(Buffer buf);
+ void setBufferSize(int rcvSize, int sndSize);
+ }
+
+}
diff --git a/csharp/src/Ice/UdpConnector.cs b/csharp/src/Ice/UdpConnector.cs
new file mode 100644
index 00000000000..7899a40d396
--- /dev/null
+++ b/csharp/src/Ice/UdpConnector.cs
@@ -0,0 +1,107 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Net.Sockets;
+
+ sealed class UdpConnector : Connector
+ {
+ public Transceiver connect()
+ {
+ return new UdpTransceiver(_instance, _addr, _sourceAddr, _mcastInterface, _mcastTtl);
+ }
+
+ public short type()
+ {
+ return _instance.type();
+ }
+
+ //
+ // Only for use by UdpEndpointI
+ //
+ internal UdpConnector(ProtocolInstance instance, EndPoint addr, EndPoint sourceAddr, string mcastInterface,
+ int mcastTtl, string connectionId)
+ {
+ _instance = instance;
+ _addr = addr;
+ _sourceAddr = sourceAddr;
+ _mcastInterface = mcastInterface;
+ _mcastTtl = mcastTtl;
+ _connectionId = connectionId;
+
+ _hashCode = 5381;
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _addr);
+ if(sourceAddr != null)
+ {
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _sourceAddr);
+ }
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _mcastInterface);
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _mcastTtl);
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _connectionId);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(!(obj is UdpConnector))
+ {
+ return false;
+ }
+
+ if(this == obj)
+ {
+ return true;
+ }
+
+ UdpConnector p = (UdpConnector)obj;
+ if(!_connectionId.Equals(p._connectionId))
+ {
+ return false;
+ }
+
+ if(!_mcastInterface.Equals(p._mcastInterface))
+ {
+ return false;
+ }
+
+ if(_mcastTtl != p._mcastTtl)
+ {
+ return false;
+ }
+
+ if(!Network.addressEquals(_sourceAddr, p._sourceAddr))
+ {
+ return false;
+ }
+
+ return _addr.Equals(p._addr);
+ }
+
+ public override string ToString()
+ {
+ return Network.addrToString(_addr);
+ }
+
+ public override int GetHashCode()
+ {
+ return _hashCode;
+ }
+
+ private ProtocolInstance _instance;
+ private EndPoint _addr;
+ private EndPoint _sourceAddr;
+ private string _mcastInterface;
+ private int _mcastTtl;
+ private string _connectionId;
+ private int _hashCode;
+ }
+}
diff --git a/csharp/src/Ice/UdpEndpointI.cs b/csharp/src/Ice/UdpEndpointI.cs
new file mode 100644
index 00000000000..9d28b27c21b
--- /dev/null
+++ b/csharp/src/Ice/UdpEndpointI.cs
@@ -0,0 +1,449 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Diagnostics;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Net;
+ using System;
+ using System.Globalization;
+
+ sealed class UdpEndpointI : IPEndpointI
+ {
+ public UdpEndpointI(ProtocolInstance instance, string ho, int po, EndPoint sourceAddr, string mcastInterface,
+ int mttl, bool conn, string conId, bool co) :
+ base(instance, ho, po, sourceAddr, conId)
+ {
+ _mcastInterface = mcastInterface;
+ _mcastTtl = mttl;
+ _connect = conn;
+ _compress = co;
+ }
+
+ public UdpEndpointI(ProtocolInstance instance) :
+ base(instance)
+ {
+ _connect = false;
+ _compress = false;
+ }
+
+ public UdpEndpointI(ProtocolInstance instance, BasicStream s) :
+ base(instance, s)
+ {
+ if(s.getReadEncoding().Equals(Ice.Util.Encoding_1_0))
+ {
+ s.readByte();
+ s.readByte();
+ s.readByte();
+ s.readByte();
+ }
+ // Not transmitted.
+ //_connect = s.readBool();
+ _connect = false;
+ _compress = s.readBool();
+ }
+
+ private sealed class InfoI : Ice.UDPEndpointInfo
+ {
+ public InfoI(UdpEndpointI e)
+ {
+ _endpoint = e;
+ }
+
+ override public short type()
+ {
+ return _endpoint.type();
+ }
+
+ override public bool datagram()
+ {
+ return _endpoint.datagram();
+ }
+
+ override public bool secure()
+ {
+ return _endpoint.secure();
+ }
+
+ private UdpEndpointI _endpoint;
+ }
+
+ //
+ // Return the endpoint information.
+ //
+ public override Ice.EndpointInfo getInfo()
+ {
+ InfoI info = new InfoI(this);
+ fillEndpointInfo(info);
+ return info;
+ }
+
+ //
+ // Return the timeout for the endpoint in milliseconds. 0 means
+ // non-blocking, -1 means no timeout.
+ //
+ public override int timeout()
+ {
+ return -1;
+ }
+
+ //
+ // Return a new endpoint with a different timeout value, provided
+ // that timeouts are supported by the endpoint. Otherwise the same
+ // endpoint is returned.
+ //
+ public override EndpointI timeout(int timeout)
+ {
+ return this;
+ }
+
+ //
+ // Return true if the endpoints support bzip2 compress, or false
+ // otherwise.
+ //
+ public override bool compress()
+ {
+ return _compress;
+ }
+
+ //
+ // Return a new endpoint with a different compression value,
+ // provided that compression is supported by the
+ // endpoint. Otherwise the same endpoint is returned.
+ //
+ public override EndpointI compress(bool compress)
+ {
+ if(compress == _compress)
+ {
+ return this;
+ }
+ else
+ {
+ return new UdpEndpointI(instance_, host_, port_, sourceAddr_, _mcastInterface, _mcastTtl, _connect,
+ connectionId_, compress);
+ }
+ }
+
+ //
+ // Return true if the endpoint is datagram-based.
+ //
+ public override bool datagram()
+ {
+ return true;
+ }
+
+ //
+ // Return a server side transceiver for this endpoint, or null if a
+ // transceiver can only be created by an acceptor.
+ //
+ public override Transceiver transceiver()
+ {
+ return new UdpTransceiver(this, instance_, host_, port_, _mcastInterface, _connect);
+ }
+
+ //
+ // Return an acceptor for this endpoint, or null if no acceptors
+ // is available.
+ //
+ public override Acceptor acceptor(string adapterName)
+ {
+ return null;
+ }
+
+ public UdpEndpointI endpoint(UdpTransceiver transceiver)
+ {
+ return new UdpEndpointI(instance_, host_, transceiver.effectivePort(), sourceAddr_, _mcastInterface,
+ _mcastTtl, _connect, connectionId_, _compress);
+ }
+
+ public override string options()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ string s = base.options();
+
+ if(_mcastInterface.Length != 0)
+ {
+ s += " --interface " + _mcastInterface;
+ }
+
+ if(_mcastTtl != -1)
+ {
+ s += " --ttl " + _mcastTtl;
+ }
+
+ if(_connect)
+ {
+ s += " -c";
+ }
+
+ if(_compress)
+ {
+ s += " -z";
+ }
+
+ return s;
+ }
+
+ //
+ // Compare endpoints for sorting purposes
+ //
+ public override int CompareTo(EndpointI obj)
+ {
+ if(!(obj is UdpEndpointI))
+ {
+ return type() < obj.type() ? -1 : 1;
+ }
+
+ UdpEndpointI p = (UdpEndpointI)obj;
+ if(this == p)
+ {
+ return 0;
+ }
+
+ if(!_connect && p._connect)
+ {
+ return -1;
+ }
+ else if(!p._connect && _connect)
+ {
+ return 1;
+ }
+
+ if(!_compress && p._compress)
+ {
+ return -1;
+ }
+ else if(!p._compress && _compress)
+ {
+ return 1;
+ }
+
+ int rc = string.Compare(_mcastInterface, p._mcastInterface, StringComparison.Ordinal);
+ if(rc != 0)
+ {
+ return rc;
+ }
+
+ if(_mcastTtl < p._mcastTtl)
+ {
+ return -1;
+ }
+ else if(p._mcastTtl < _mcastTtl)
+ {
+ return 1;
+ }
+
+ return base.CompareTo(p);
+ }
+
+ //
+ // Marshal the endpoint
+ //
+ public override void streamWriteImpl(BasicStream s)
+ {
+ base.streamWriteImpl(s);
+ if(s.getWriteEncoding().Equals(Ice.Util.Encoding_1_0))
+ {
+ Ice.Util.Protocol_1_0.write__(s);
+ Ice.Util.Encoding_1_0.write__(s);
+ }
+ // Not transmitted.
+ //s.writeBool(_connect);
+ s.writeBool(_compress);
+ }
+
+ public override void hashInit(ref int h)
+ {
+ base.hashInit(ref h);
+ IceInternal.HashUtil.hashAdd(ref h, _mcastInterface);
+ IceInternal.HashUtil.hashAdd(ref h, _mcastTtl);
+ IceInternal.HashUtil.hashAdd(ref h, _connect);
+ IceInternal.HashUtil.hashAdd(ref h, _compress);
+ }
+
+ public override void fillEndpointInfo(Ice.IPEndpointInfo info)
+ {
+ base.fillEndpointInfo(info);
+ if(info is Ice.UDPEndpointInfo)
+ {
+ Ice.UDPEndpointInfo udpInfo = (Ice.UDPEndpointInfo)info;
+ udpInfo.timeout = -1;
+ udpInfo.compress = _compress;
+ udpInfo.mcastInterface = _mcastInterface;
+ udpInfo.mcastTtl = _mcastTtl;
+ }
+ }
+
+ protected override bool checkOption(string option, string argument, string endpoint)
+ {
+ if(base.checkOption(option, argument, endpoint))
+ {
+ return true;
+ }
+
+ if(option.Equals("-c"))
+ {
+ if(argument != null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -c option in " + endpoint;
+ throw e;
+ }
+
+ _connect = true;
+ }
+ else if(option.Equals("-z"))
+ {
+ if(argument != null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -z option in " + endpoint;
+ throw e;
+ }
+
+ _compress = true;
+ }
+ else if(option.Equals("-v") || option.Equals("-e"))
+ {
+ if(argument == null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "no argument provided for " + option + " option in endpoint " + endpoint;
+ throw e;
+ }
+
+ try
+ {
+ Ice.EncodingVersion v = Ice.Util.stringToEncodingVersion(argument);
+ if(v.major != 1 || v.minor != 0)
+ {
+ instance_.logger().warning("deprecated udp endpoint option: " + option);
+ }
+ }
+ catch(Ice.VersionParseException ex)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "invalid version `" + argument + "' in endpoint " + endpoint + ":\n" + ex.str;
+ throw e;
+ }
+ }
+ else if(option.Equals("--ttl"))
+ {
+ if(argument == null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "no argument provided for --ttl option in endpoint " + endpoint;
+ throw e;
+ }
+
+ try
+ {
+ _mcastTtl = System.Int32.Parse(argument, CultureInfo.InvariantCulture);
+ }
+ catch(System.FormatException ex)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException(ex);
+ e.str = "invalid TTL value `" + argument + "' in endpoint " + endpoint;
+ throw e;
+ }
+
+ if(_mcastTtl < 0)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "TTL value `" + argument + "' out of range in endpoint " + endpoint;
+ throw e;
+ }
+ }
+ else if(option.Equals("--interface"))
+ {
+ if(argument == null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "no argument provided for --interface option in endpoint " + endpoint;
+ throw e;
+ }
+ _mcastInterface = argument;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected override Connector createConnector(EndPoint addr, NetworkProxy proxy)
+ {
+ return new UdpConnector(instance_, addr, sourceAddr_, _mcastInterface, _mcastTtl, connectionId_);
+ }
+
+ protected override IPEndpointI createEndpoint(string host, int port, string connectionId)
+ {
+ return new UdpEndpointI(instance_, host, port, sourceAddr_, _mcastInterface, _mcastTtl, _connect,
+ connectionId, _compress);
+ }
+
+ private string _mcastInterface = "";
+ private int _mcastTtl = -1;
+ private bool _connect;
+ private bool _compress;
+ }
+
+ sealed class UdpEndpointFactory : EndpointFactory
+ {
+ internal UdpEndpointFactory(ProtocolInstance instance)
+ {
+ _instance = instance;
+ }
+
+ public short type()
+ {
+ return _instance.type();
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public EndpointI create(List<string> args, bool oaEndpoint)
+ {
+ IPEndpointI endpt = new UdpEndpointI(_instance);
+ endpt.initWithOptions(args, oaEndpoint);
+ return endpt;
+ }
+
+ public EndpointI read(BasicStream s)
+ {
+ return new UdpEndpointI(_instance, s);
+ }
+
+ public void destroy()
+ {
+ _instance = null;
+ }
+
+ public EndpointFactory clone(ProtocolInstance instance)
+ {
+ return new UdpEndpointFactory(instance);
+ }
+
+ private ProtocolInstance _instance;
+ }
+
+}
diff --git a/csharp/src/Ice/UdpTransceiver.cs b/csharp/src/Ice/UdpTransceiver.cs
new file mode 100644
index 00000000000..e9a7531340a
--- /dev/null
+++ b/csharp/src/Ice/UdpTransceiver.cs
@@ -0,0 +1,1120 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+//
+// .NET and Silverlight use the new socket asynchronous APIs whereas
+// the compact framework and mono still use the old Begin/End APIs.
+//
+#if !COMPACT && !__MonoCS__ && !UNITY
+#define ICE_SOCKET_ASYNC_API
+#endif
+
+namespace IceInternal
+{
+ using System;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Text;
+
+ sealed class UdpTransceiver : Transceiver
+ {
+ public Socket fd()
+ {
+ return _fd;
+ }
+
+ public int initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData)
+ {
+ if(_state == StateNeedConnect)
+ {
+ _state = StateConnectPending;
+#if ICE_SOCKET_ASYNC_API && !SILVERLIGHT
+ try
+ {
+ if(_sourceAddr != null)
+ {
+ _fd.Bind(_sourceAddr);
+ }
+ _fd.Connect(_addr);
+ }
+ catch(SocketException ex)
+ {
+ if(Network.wouldBlock(ex))
+ {
+ return SocketOperation.Connect;
+ }
+ throw new Ice.ConnectFailedException(ex);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.ConnectFailedException(ex);
+ }
+#else
+ return SocketOperation.Connect;
+#endif
+ }
+
+ if(_state <= StateConnectPending)
+ {
+#if !SILVERLIGHT
+ if(!AssemblyUtil.osx_)
+ {
+ //
+ // On Windows, we delay the join for the mcast group after the connection
+ // establishment succeeds. This is necessary for older Windows versions
+ // where joining the group fails if the socket isn't bound. See ICE-5113.
+ //
+ if(Network.isMulticast((IPEndPoint)_addr))
+ {
+ Network.setMcastGroup(_fd, ((IPEndPoint)_addr).Address, _mcastInterface);
+ if(_mcastTtl != -1)
+ {
+ Network.setMcastTtl(_fd, _mcastTtl, _addr.AddressFamily);
+ }
+ }
+ }
+#endif
+ _state = StateConnected;
+ }
+
+ Debug.Assert(_state >= StateConnected);
+ return SocketOperation.None;
+ }
+
+ public int closing(bool initiator, Ice.LocalException ex)
+ {
+ //
+ // Nothing to do.
+ //
+ return SocketOperation.None;
+ }
+
+ public void close()
+ {
+ if(_fd != null)
+ {
+ try
+ {
+ _fd.Close();
+ }
+ catch(System.IO.IOException)
+ {
+ }
+ _fd = null;
+ }
+ }
+
+ public EndpointI bind()
+ {
+#if !SILVERLIGHT
+ if(Network.isMulticast((IPEndPoint)_addr))
+ {
+ Network.setReuseAddress(_fd, true);
+ _mcastAddr = (IPEndPoint)_addr;
+ if(AssemblyUtil.platform_ == AssemblyUtil.Platform.Windows)
+ {
+ //
+ // Windows does not allow binding to the mcast address itself
+ // so we bind to INADDR_ANY (0.0.0.0) instead. As a result,
+ // bi-directional connection won't work because the source
+ // address won't the multicast address and the client will
+ // therefore reject the datagram.
+ //
+ if(_addr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ _addr = new IPEndPoint(IPAddress.Any, _port);
+ }
+ else
+ {
+ _addr = new IPEndPoint(IPAddress.IPv6Any, _port);
+ }
+ }
+ _addr = Network.doBind(_fd, _addr);
+ if(_port == 0)
+ {
+ _mcastAddr.Port = ((IPEndPoint)_addr).Port;
+ }
+ Network.setMcastGroup(_fd, _mcastAddr.Address, _mcastInterface);
+ }
+ else
+ {
+ if(AssemblyUtil.platform_ != AssemblyUtil.Platform.Windows)
+ {
+ //
+ // Enable SO_REUSEADDR on Unix platforms to allow re-using
+ // the socket even if it's in the TIME_WAIT state. On
+ // Windows, this doesn't appear to be necessary and
+ // enabling SO_REUSEADDR would actually not be a good
+ // thing since it allows a second process to bind to an
+ // address even it's already bound by another process.
+ //
+ // TODO: using SO_EXCLUSIVEADDRUSE on Windows would
+ // probably be better but it's only supported by recent
+ // Windows versions (XP SP2, Windows Server 2003).
+ //
+ Network.setReuseAddress(_fd, true);
+ }
+ _addr = Network.doBind(_fd, _addr);
+ }
+#endif
+ _bound = true;
+ _endpoint = _endpoint.endpoint(this);
+ return _endpoint;
+ }
+
+ public void destroy()
+ {
+#if ICE_SOCKET_ASYNC_API
+ _readEventArgs.Dispose();
+ _writeEventArgs.Dispose();
+#endif
+ }
+
+ public int write(Buffer buf)
+ {
+ if(!buf.b.hasRemaining())
+ {
+ return SocketOperation.None;
+ }
+#if COMPACT || SILVERLIGHT
+# if !ICE_SOCKET_ASYNC_API
+ if(_writeResult != null)
+ {
+ return SocketOperation.None;
+ }
+# endif
+ //
+ // Silverlight and the Compact .NET Framework don't support the use of synchronous socket
+ // operations on a non-blocking socket. Returning SocketOperation.Write here forces the
+ // caller to schedule an asynchronous operation.
+ //
+ return SocketOperation.Write;
+#else
+ Debug.Assert(buf.b.position() == 0);
+ Debug.Assert(_fd != null && _state >= StateConnected);
+
+ // The caller is supposed to check the send size before by calling checkSendSize
+ Debug.Assert(System.Math.Min(_maxPacketSize, _sndSize - _udpOverhead) >= buf.size());
+
+ int ret = 0;
+ while(true)
+ {
+ try
+ {
+ if(_state == StateConnected)
+ {
+ ret = _fd.Send(buf.b.rawBytes(), 0, buf.size(), SocketFlags.None);
+ }
+ else
+ {
+ if(_peerAddr == null)
+ {
+ throw new Ice.SocketException();
+ }
+ ret = _fd.SendTo(buf.b.rawBytes(), 0, buf.size(), SocketFlags.None, _peerAddr);
+ }
+ break;
+ }
+ catch(SocketException ex)
+ {
+ if(Network.interrupted(ex))
+ {
+ continue;
+ }
+
+ if(Network.wouldBlock(ex))
+ {
+ return SocketOperation.Write;
+ }
+
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ else
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+ catch(System.Exception e)
+ {
+ throw new Ice.SyscallException(e);
+ }
+ }
+
+ Debug.Assert(ret > 0);
+ Debug.Assert(ret == buf.b.limit());
+ buf.b.position(buf.b.limit());
+ return SocketOperation.None;
+#endif
+ }
+
+ public int read(Buffer buf, ref bool hasMoreData)
+ {
+ if(!buf.b.hasRemaining())
+ {
+ return SocketOperation.None;
+ }
+#if COMPACT || SILVERLIGHT
+ //
+ // Silverlight and the Compact .NET Framework don't support the use of synchronous socket
+ // operations on a non-blocking socket. Returning SocketOperation.Read here forces the
+ // caller to schedule an asynchronous operation.
+ //
+ return SocketOperation.Read;
+#else
+ Debug.Assert(buf.b.position() == 0);
+ Debug.Assert(_fd != null);
+
+ int packetSize = System.Math.Min(_maxPacketSize, _rcvSize - _udpOverhead);
+ buf.resize(packetSize, true);
+ buf.b.position(0);
+
+ int ret = 0;
+ while(true)
+ {
+ try
+ {
+ EndPoint peerAddr = _peerAddr;
+ if(peerAddr == null)
+ {
+ if(_addr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ peerAddr = new IPEndPoint(IPAddress.Any, 0);
+ }
+ else
+ {
+ Debug.Assert(_addr.AddressFamily == AddressFamily.InterNetworkV6);
+ peerAddr = new IPEndPoint(IPAddress.IPv6Any, 0);
+ }
+ }
+
+ if(_state == StateConnected)
+ {
+ ret = _fd.Receive(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None);
+ }
+ else
+ {
+ ret = _fd.ReceiveFrom(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None, ref peerAddr);
+ _peerAddr = (IPEndPoint)peerAddr;
+ }
+ break;
+ }
+ catch(SocketException e)
+ {
+ if(Network.recvTruncated(e))
+ {
+ // The message was truncated and the whole buffer is filled. We ignore
+ // this error here, it will be detected at the connection level when
+ // the Ice message size is checked against the buffer size.
+ ret = buf.size();
+ break;
+ }
+
+ if(Network.interrupted(e))
+ {
+ continue;
+ }
+
+ if(Network.wouldBlock(e))
+ {
+ return SocketOperation.Read;
+ }
+
+ if(Network.connectionLost(e))
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ else
+ {
+ throw new Ice.SocketException(e);
+ }
+ }
+ catch(System.Exception e)
+ {
+ throw new Ice.SyscallException(e);
+ }
+ }
+
+ if(ret == 0)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+
+ if(_state == StateNeedConnect)
+ {
+ Debug.Assert(_incoming);
+
+ //
+ // If we must connect, then we connect to the first peer that sends us a packet.
+ //
+ bool connected = Network.doConnect(_fd, _peerAddr, null);
+ Debug.Assert(connected);
+ _state = StateConnected; // We're connected now
+
+ if(_instance.traceLevel() >= 1)
+ {
+ string s = "connected " + protocol() + " socket\n" + ToString();
+ _instance.logger().trace(_instance.traceCategory(), s);
+ }
+ }
+
+ buf.resize(ret, true);
+ buf.b.position(ret);
+
+ return SocketOperation.None;
+#endif
+ }
+
+ public bool startRead(Buffer buf, AsyncCallback callback, object state)
+ {
+ Debug.Assert(buf.b.position() == 0);
+
+ int packetSize = System.Math.Min(_maxPacketSize, _rcvSize - _udpOverhead);
+ buf.resize(packetSize, true);
+ buf.b.position(0);
+
+ try
+ {
+ if(_state == StateConnected)
+ {
+ _readCallback = callback;
+#if ICE_SOCKET_ASYNC_API
+ _readEventArgs.UserToken = state;
+ _readEventArgs.SetBuffer(buf.b.rawBytes(), buf.b.position(), packetSize);
+ return !_fd.ReceiveAsync(_readEventArgs);
+#else
+ _readResult = _fd.BeginReceive(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None,
+ readCompleted, state);
+ return _readResult.CompletedSynchronously;
+#endif
+ }
+ else
+ {
+ Debug.Assert(_incoming);
+ _readCallback = callback;
+#if ICE_SOCKET_ASYNC_API
+ _readEventArgs.UserToken = state;
+ _readEventArgs.SetBuffer(buf.b.rawBytes(), 0, buf.b.limit());
+ return !_fd.ReceiveFromAsync(_readEventArgs);
+#else
+ EndPoint peerAddr = _peerAddr;
+ if(peerAddr == null)
+ {
+ if(_addr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ peerAddr = new IPEndPoint(IPAddress.Any, 0);
+ }
+ else
+ {
+ Debug.Assert(_addr.AddressFamily == AddressFamily.InterNetworkV6);
+ peerAddr = new IPEndPoint(IPAddress.IPv6Any, 0);
+ }
+ }
+ _readResult = _fd.BeginReceiveFrom(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None,
+ ref peerAddr, readCompleted, state);
+ return _readResult.CompletedSynchronously;
+#endif
+ }
+ }
+ catch(SocketException ex)
+ {
+ if(Network.recvTruncated(ex))
+ {
+ // Nothing todo
+ return true;
+ }
+ else
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ else
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+ }
+ }
+
+ public void finishRead(Buffer buf)
+ {
+ if(_fd == null)
+ {
+ return;
+ }
+
+ int ret;
+ try
+ {
+#if ICE_SOCKET_ASYNC_API
+ if(_readEventArgs.SocketError != SocketError.Success)
+ {
+ throw new SocketException((int)_readEventArgs.SocketError);
+ }
+ ret = _readEventArgs.BytesTransferred;
+ if(_state != StateConnected)
+ {
+ _peerAddr = _readEventArgs.RemoteEndPoint;
+ }
+#else
+ Debug.Assert(_readResult != null);
+ if(_state == StateConnected)
+ {
+ ret = _fd.EndReceive(_readResult);
+ }
+ else
+ {
+ EndPoint peerAddr = _peerAddr;
+ if(_addr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ peerAddr = new IPEndPoint(IPAddress.Any, 0);
+ }
+ else
+ {
+ Debug.Assert(_addr.AddressFamily == AddressFamily.InterNetworkV6);
+ peerAddr = new IPEndPoint(IPAddress.IPv6Any, 0);
+ }
+ ret = _fd.EndReceiveFrom(_readResult, ref peerAddr);
+ _peerAddr = (IPEndPoint)peerAddr;
+ }
+ _readResult = null;
+#endif
+ }
+ catch(SocketException ex)
+ {
+ if(Network.recvTruncated(ex))
+ {
+ // The message was truncated and the whole buffer is filled. We ignore
+ // this error here, it will be detected at the connection level when
+ // the Ice message size is checked against the buffer size.
+ ret = buf.size();
+ }
+ else
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+
+ if(Network.connectionRefused(ex))
+ {
+ throw new Ice.ConnectionRefusedException(ex);
+ }
+ else
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+ }
+
+ if(ret == 0)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+
+ Debug.Assert(ret > 0);
+
+ if(_state == StateNeedConnect)
+ {
+ Debug.Assert(_incoming);
+
+ //
+ // If we must connect, then we connect to the first peer that
+ // sends us a packet.
+ //
+#if ICE_SOCKET_ASYNC_API
+ bool connected = !_fd.ConnectAsync(_readEventArgs);
+#else
+ bool connected = Network.doConnect(_fd, _peerAddr, null);
+#endif
+ Debug.Assert(connected);
+ _state = StateConnected; // We're connected now
+
+ if(_instance.traceLevel() >= 1)
+ {
+ string s = "connected " + protocol() + " socket\n" + ToString();
+ _instance.logger().trace(_instance.traceCategory(), s);
+ }
+ }
+
+ buf.resize(ret, true);
+ buf.b.position(ret);
+ }
+
+ public bool startWrite(Buffer buf, AsyncCallback callback, object state, out bool completed)
+ {
+ if(!_incoming && _state < StateConnected)
+ {
+ Debug.Assert(_addr != null);
+ completed = false;
+#if ICE_SOCKET_ASYNC_API
+# if !SILVERLIGHT
+ if(_sourceAddr != null)
+ {
+ _fd.Bind(_sourceAddr);
+ }
+# endif
+ _writeEventArgs.UserToken = state;
+ return !_fd.ConnectAsync(_writeEventArgs);
+#else
+ _writeResult = Network.doConnectAsync(_fd, _addr, _sourceAddr, callback, state);
+ return _writeResult.CompletedSynchronously;
+#endif
+ }
+
+ Debug.Assert(_fd != null);
+
+ // The caller is supposed to check the send size before by calling checkSendSize
+ Debug.Assert(System.Math.Min(_maxPacketSize, _sndSize - _udpOverhead) >= buf.size());
+
+ Debug.Assert(buf.b.position() == 0);
+
+ bool completedSynchronously;
+ try
+ {
+ _writeCallback = callback;
+
+ if(_state == StateConnected)
+ {
+#if ICE_SOCKET_ASYNC_API
+ _writeEventArgs.UserToken = state;
+ _writeEventArgs.SetBuffer(buf.b.rawBytes(), 0, buf.b.limit());
+ completedSynchronously = !_fd.SendAsync(_writeEventArgs);
+#else
+ _writeResult = _fd.BeginSend(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None,
+ writeCompleted, state);
+ completedSynchronously = _writeResult.CompletedSynchronously;
+#endif
+ }
+ else
+ {
+ if(_peerAddr == null)
+ {
+ throw new Ice.SocketException();
+ }
+#if ICE_SOCKET_ASYNC_API
+ _writeEventArgs.RemoteEndPoint = _peerAddr;
+ _writeEventArgs.UserToken = state;
+ _writeEventArgs.SetBuffer(buf.b.rawBytes(), 0, buf.b.limit());
+ completedSynchronously = !_fd.SendToAsync(_writeEventArgs);
+#else
+ _writeResult = _fd.BeginSendTo(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None, _peerAddr,
+ writeCompleted, state);
+ completedSynchronously = _writeResult.CompletedSynchronously;
+#endif
+ }
+ }
+ catch(SocketException ex)
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ else
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ completed = true;
+ return completedSynchronously;
+ }
+
+ public void finishWrite(Buffer buf)
+ {
+ if(_fd == null)
+ {
+ buf.b.position(buf.size()); // Assume all the data was sent for at-most-once semantics.
+#if ICE_SOCKET_ASYNC_API
+ _writeEventArgs = null;
+#else
+ _writeResult = null;
+#endif
+ return;
+ }
+
+ if(!_incoming && _state < StateConnected)
+ {
+#if ICE_SOCKET_ASYNC_API
+ if(_writeEventArgs.SocketError != SocketError.Success)
+ {
+ SocketException ex = new SocketException((int)_writeEventArgs.SocketError);
+ if(Network.connectionRefused(ex))
+ {
+ throw new Ice.ConnectionRefusedException(ex);
+ }
+ else
+ {
+ throw new Ice.ConnectFailedException(ex);
+ }
+ }
+#else
+ Debug.Assert(_writeResult != null);
+ Network.doFinishConnectAsync(_fd, _writeResult);
+ _writeResult = null;
+#endif
+ return;
+ }
+
+ int ret;
+ try
+ {
+#if ICE_SOCKET_ASYNC_API
+ if(_writeEventArgs.SocketError != SocketError.Success)
+ {
+ throw new SocketException((int)_writeEventArgs.SocketError);
+ }
+ ret = _writeEventArgs.BytesTransferred;
+#else
+ if (_state == StateConnected)
+ {
+ ret = _fd.EndSend(_writeResult);
+ }
+ else
+ {
+ ret = _fd.EndSendTo(_writeResult);
+ }
+ _writeResult = null;
+#endif
+ }
+ catch(SocketException ex)
+ {
+ if(Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ else
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ if(ret == 0)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+
+ Debug.Assert(ret > 0);
+ Debug.Assert(ret == buf.b.limit());
+ buf.b.position(buf.b.position() + ret);
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public Ice.ConnectionInfo getInfo()
+ {
+ Ice.UDPConnectionInfo info = new Ice.UDPConnectionInfo();
+ if(_fd != null)
+ {
+ EndPoint localEndpoint = Network.getLocalAddress(_fd);
+ info.localAddress = Network.endpointAddressToString(localEndpoint);
+ info.localPort = Network.endpointPort(localEndpoint);
+ if(_state == StateNotConnected)
+ {
+ if(_peerAddr != null)
+ {
+ info.remoteAddress = Network.endpointAddressToString(_peerAddr);
+ info.remotePort = Network.endpointPort(_peerAddr);
+ }
+ }
+ else
+ {
+ EndPoint remoteEndpoint = Network.getRemoteAddress(_fd);
+ if(remoteEndpoint != null)
+ {
+ info.remoteAddress = Network.endpointAddressToString(remoteEndpoint);
+ info.remotePort = Network.endpointPort(remoteEndpoint);
+ }
+ }
+ }
+
+ info.rcvSize = Network.getRecvBufferSize(_fd);
+ info.sndSize = Network.getSendBufferSize(_fd);
+
+#if !SILVERLIGHT
+ if(_mcastAddr != null)
+ {
+ info.mcastAddress = Network.endpointAddressToString(_mcastAddr);
+ info.mcastPort = Network.endpointPort(_mcastAddr);
+ }
+#endif
+ return info;
+ }
+
+ public void checkSendSize(Buffer buf)
+ {
+ //
+ // The maximum packetSize is either the maximum allowable UDP packet size, or
+ // the UDP send buffer size (which ever is smaller).
+ //
+ int packetSize = System.Math.Min(_maxPacketSize, _sndSize - _udpOverhead);
+ if(packetSize < buf.size())
+ {
+ throw new Ice.DatagramLimitException();
+ }
+ }
+
+ public void setBufferSize(int rcvSize, int sndSize)
+ {
+ setBufSize(rcvSize, sndSize);
+ }
+
+ public override string ToString()
+ {
+ if(_fd == null)
+ {
+ return "<closed>";
+ }
+
+ string s;
+ if(_incoming && !_bound)
+ {
+ s = "local address = " + Network.addrToString(_addr);
+ }
+ else if(_state == StateNotConnected)
+ {
+ s = "local address = " + Network.localAddrToString(Network.getLocalAddress(_fd));
+ if(_peerAddr != null)
+ {
+ s += "\nremote address = " + Network.addrToString(_peerAddr);
+ }
+ }
+ else
+ {
+ s = Network.fdToString(_fd);
+ }
+
+#if !SILVERLIGHT
+ if(_mcastAddr != null)
+ {
+ s += "\nmulticast address = " + Network.addrToString(_mcastAddr);
+ }
+#endif
+ return s;
+ }
+
+ public string toDetailedString()
+ {
+ StringBuilder s = new StringBuilder(ToString());
+ List<string> intfs = Network.getHostsForEndpointExpand(
+ Network.endpointAddressToString(_addr), _instance.protocolSupport(), true);
+ if(intfs.Count != 0)
+ {
+ s.Append("\nlocal interfaces = ");
+ s.Append(String.Join(", ", intfs.ToArray()));
+ }
+ return s.ToString();
+ }
+
+ public int effectivePort()
+ {
+ return Network.endpointPort(_addr);
+ }
+
+ //
+ // Only for use by UdpConnector.
+ //
+ internal UdpTransceiver(ProtocolInstance instance, EndPoint addr, EndPoint sourceAddr, string mcastInterface,
+ int mcastTtl)
+ {
+ _instance = instance;
+ _addr = addr;
+ _sourceAddr = sourceAddr;
+
+#if ICE_SOCKET_ASYNC_API
+ _readEventArgs = new SocketAsyncEventArgs();
+ _readEventArgs.RemoteEndPoint = _addr;
+ _readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
+
+ _writeEventArgs = new SocketAsyncEventArgs();
+ _writeEventArgs.RemoteEndPoint = _addr;
+ _writeEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
+#if SILVERLIGHT
+ String policy = instance.properties().getProperty("Ice.ClientAccessPolicyProtocol");
+ if(policy.Equals("Http"))
+ {
+ _readEventArgs.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Http;
+ _writeEventArgs.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Http;
+ }
+ else if(!String.IsNullOrEmpty(policy))
+ {
+ _instance.logger().warning("Ignoring invalid Ice.ClientAccessPolicyProtocol value `" + policy + "'");
+ }
+#endif
+#endif
+
+ _mcastInterface = mcastInterface;
+ _mcastTtl = mcastTtl;
+ _state = StateNeedConnect;
+ _incoming = false;
+
+ try
+ {
+ _fd = Network.createSocket(true, _addr.AddressFamily);
+ setBufSize(-1, -1);
+#if !SILVERLIGHT
+ Network.setBlock(_fd, false);
+ if(AssemblyUtil.osx_)
+ {
+ //
+ // On Windows, we delay the join for the mcast group after the connection
+ // establishment succeeds. This is necessary for older Windows versions
+ // where joining the group fails if the socket isn't bound. See ICE-5113.
+ //
+ if(Network.isMulticast((IPEndPoint)_addr))
+ {
+ Network.setMcastGroup(_fd, ((IPEndPoint)_addr).Address, _mcastInterface);
+ if(_mcastTtl != -1)
+ {
+ Network.setMcastTtl(_fd, _mcastTtl, _addr.AddressFamily);
+ }
+ }
+ }
+#endif
+ }
+ catch(Ice.LocalException)
+ {
+ _fd = null;
+ throw;
+ }
+ }
+
+ //
+ // Only for use by UdpEndpoint.
+ //
+ internal UdpTransceiver(UdpEndpointI endpoint, ProtocolInstance instance, string host, int port,
+ string mcastInterface, bool connect)
+ {
+ _endpoint = endpoint;
+ _instance = instance;
+ _state = connect ? StateNeedConnect : StateNotConnected;
+ _mcastInterface = mcastInterface;
+ _incoming = true;
+ _port = port;
+
+ try
+ {
+ _addr = Network.getAddressForServer(host, port, instance.protocolSupport(), instance.preferIPv6());
+
+#if ICE_SOCKET_ASYNC_API
+ _readEventArgs = new SocketAsyncEventArgs();
+ _readEventArgs.RemoteEndPoint = _addr;
+ _readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
+
+ _writeEventArgs = new SocketAsyncEventArgs();
+ _writeEventArgs.RemoteEndPoint = _addr;
+ _writeEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
+#endif
+
+ _fd = Network.createServerSocket(true, _addr.AddressFamily, instance.protocolSupport());
+ setBufSize(-1, -1);
+#if !SILVERLIGHT
+ Network.setBlock(_fd, false);
+#endif
+ }
+ catch(Ice.LocalException)
+ {
+#if ICE_SOCKET_ASYNC_API
+ if(_readEventArgs != null)
+ {
+ _readEventArgs.Dispose();
+ }
+ if(_writeEventArgs != null)
+ {
+ _writeEventArgs.Dispose();
+ }
+#endif
+ _fd = null;
+ throw;
+ }
+ }
+
+ private void setBufSize(int rcvSize, int sndSize)
+ {
+ Debug.Assert(_fd != null);
+
+ for (int i = 0; i < 2; ++i)
+ {
+ bool isSnd;
+ string direction;
+ string prop;
+ int dfltSize;
+ int sizeRequested;
+ if(i == 0)
+ {
+ isSnd = false;
+ direction = "receive";
+ prop = "Ice.UDP.RcvSize";
+ dfltSize = Network.getRecvBufferSize(_fd);
+ sizeRequested = rcvSize;
+ _rcvSize = dfltSize;
+ }
+ else
+ {
+ isSnd = true;
+ direction = "send";
+ prop = "Ice.UDP.SndSize";
+ dfltSize = Network.getSendBufferSize(_fd);
+ sizeRequested = sndSize;
+ _sndSize = dfltSize;
+ }
+
+ //
+ // Get property for buffer size if size not passed in.
+ //
+ if(sizeRequested == -1)
+ {
+ sizeRequested = _instance.properties().getPropertyAsIntWithDefault(prop, dfltSize);
+ }
+ //
+ // Check for sanity.
+ //
+ if(sizeRequested < (_udpOverhead + IceInternal.Protocol.headerSize))
+ {
+ _instance.logger().warning("Invalid " + prop + " value of " + sizeRequested + " adjusted to " +
+ dfltSize);
+ sizeRequested = dfltSize;
+ }
+
+ if(sizeRequested != dfltSize)
+ {
+ //
+ // Try to set the buffer size. The kernel will silently adjust
+ // the size to an acceptable value. Then read the size back to
+ // get the size that was actually set.
+ //
+ int sizeSet;
+ if(i == 0)
+ {
+ Network.setRecvBufferSize(_fd, sizeRequested);
+ _rcvSize = Network.getRecvBufferSize(_fd);
+ sizeSet = _rcvSize;
+ }
+ else
+ {
+ Network.setSendBufferSize(_fd, sizeRequested);
+ _sndSize = Network.getSendBufferSize(_fd);
+ sizeSet = _sndSize;
+ }
+
+ //
+ // Warn if the size that was set is less than the requested size
+ // and we have not already warned
+ //
+ if(sizeSet < sizeRequested)
+ {
+ BufSizeWarnInfo winfo = _instance.getBufSizeWarn(Ice.UDPEndpointType.value);
+ if((isSnd && (!winfo.sndWarn || winfo.sndSize != sizeRequested)) ||
+ (!isSnd && (!winfo.rcvWarn || winfo.rcvSize != sizeRequested)))
+ {
+ _instance.logger().warning("UDP " + direction + " buffer size: requested size of " +
+ sizeRequested + " adjusted to " + sizeSet);
+
+ if(isSnd)
+ {
+ _instance.setSndBufSizeWarn(Ice.UDPEndpointType.value, sizeRequested);
+ }
+ else
+ {
+ _instance.setRcvBufSizeWarn(Ice.UDPEndpointType.value, sizeRequested);
+ }
+ }
+ }
+ }
+ }
+ }
+
+#if ICE_SOCKET_ASYNC_API
+ internal void ioCompleted(object sender, SocketAsyncEventArgs e)
+ {
+ switch (e.LastOperation)
+ {
+ case SocketAsyncOperation.Receive:
+#if !SILVERLIGHT
+ case SocketAsyncOperation.ReceiveFrom:
+#endif
+ _readCallback(e.UserToken);
+ break;
+ case SocketAsyncOperation.Send:
+ case SocketAsyncOperation.Connect:
+ _writeCallback(e.UserToken);
+ break;
+ default:
+ throw new ArgumentException("The last operation completed on the socket was not a receive or send");
+ }
+ }
+#else
+ internal void readCompleted(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ _readCallback(result.AsyncState);
+ }
+ }
+
+ internal void writeCompleted(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ _writeCallback(result.AsyncState);
+ }
+ }
+#endif
+
+ private UdpEndpointI _endpoint;
+ private ProtocolInstance _instance;
+ private int _state;
+ private bool _incoming;
+ private int _rcvSize;
+ private int _sndSize;
+ private Socket _fd;
+ private EndPoint _addr;
+ private EndPoint _sourceAddr;
+#if !SILVERLIGHT
+ private IPEndPoint _mcastAddr = null;
+#endif
+ private EndPoint _peerAddr = null;
+ private string _mcastInterface = null;
+ private int _mcastTtl = -1;
+
+ private int _port = 0;
+ private bool _bound = false;
+
+#if ICE_SOCKET_ASYNC_API
+ private SocketAsyncEventArgs _writeEventArgs;
+ private SocketAsyncEventArgs _readEventArgs;
+#else
+ private IAsyncResult _writeResult;
+ private IAsyncResult _readResult;
+#endif
+
+ AsyncCallback _writeCallback;
+ AsyncCallback _readCallback;
+
+ private const int StateNeedConnect = 0;
+ private const int StateConnectPending = 1;
+ private const int StateConnected = 2;
+ private const int StateNotConnected = 3;
+
+ //
+ // The maximum IP datagram size is 65535. Subtract 20 bytes for the IP header and 8 bytes for the UDP header
+ // to get the maximum payload.
+ //
+ private const int _udpOverhead = 20 + 8;
+ private const int _maxPacketSize = 65535 - _udpOverhead;
+ }
+}
diff --git a/csharp/src/Ice/UnknownSlicedObject.cs b/csharp/src/Ice/UnknownSlicedObject.cs
new file mode 100644
index 00000000000..dcdc098280c
--- /dev/null
+++ b/csharp/src/Ice/UnknownSlicedObject.cs
@@ -0,0 +1,50 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace Ice
+{
+ /// <summary>
+ /// Unknown sliced object holds an instance of unknown type.
+ /// </summary>
+ public sealed class UnknownSlicedObject : ObjectImpl
+ {
+ /// <summary>
+ /// Instantiates the class for an Ice object having the given Slice type.
+ /// </summary>
+ /// <param name="unknownTypeId">The Slice type ID of the unknown object.</param>
+ public UnknownSlicedObject(string unknownTypeId)
+ {
+ _unknownTypeId = unknownTypeId;
+ }
+
+ /// <summary>
+ /// Determine the Slice type ID associated with this object.
+ /// </summary>
+ /// <returns>The type ID.</returns>
+ public string getUnknownTypeId()
+ {
+ return _unknownTypeId;
+ }
+
+ public override void write__(IceInternal.BasicStream os__)
+ {
+ os__.startWriteObject(_slicedData);
+ os__.endWriteObject();
+ }
+
+ public override void read__(IceInternal.BasicStream is__)
+ {
+ is__.startReadObject();
+ _slicedData = is__.endReadObject(true);
+ }
+
+ private string _unknownTypeId;
+ private SlicedData _slicedData;
+ }
+}
diff --git a/csharp/src/Ice/UserExceptionFactory.cs b/csharp/src/Ice/UserExceptionFactory.cs
new file mode 100644
index 00000000000..e8426a904a2
--- /dev/null
+++ b/csharp/src/Ice/UserExceptionFactory.cs
@@ -0,0 +1,19 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ public interface UserExceptionFactory
+ {
+ void createAndThrow(string typeId);
+ void destroy();
+ }
+
+}
diff --git a/csharp/src/Ice/Util.cs b/csharp/src/Ice/Util.cs
new file mode 100644
index 00000000000..3f97251a2ee
--- /dev/null
+++ b/csharp/src/Ice/Util.cs
@@ -0,0 +1,816 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Threading;
+using System.Collections;
+using System.Text;
+using System.Globalization;
+
+namespace Ice
+{
+ /// <summary>
+ /// Interface for thread notification hooks. Applications can derive
+ /// a class tat implements the start and stop
+ /// methods to intercept creation and destruction of threads created
+ /// by the Ice run time.
+ /// </summary>
+ public interface ThreadNotification
+ {
+ /// <summary>
+ /// The Ice run time calls start for each new
+ /// thread it creates. The call is made by the newly-started thread.
+ /// </summary>
+ void start();
+
+ /// <summary>
+ /// The Ice run time calls stop before it destroys
+ /// a thread. The call is made by thread that is about to be
+ /// destroyed.
+ /// </summary>
+ void stop();
+ }
+
+#if COMPACT
+ /// <summary>
+ /// A delegate for an action taking no parameters.
+ /// </summary>
+ public delegate void VoidAction();
+#endif
+
+ /// <summary>
+ /// A delegate for the dispatcher. The dispatcher is called by the Ice
+ /// runtime to dispatch servant calls and AMI callbacks.
+ /// </summary>
+#if COMPACT
+ public delegate void Dispatcher(VoidAction call, Connection con);
+#else
+ public delegate void Dispatcher(System.Action call, Connection con);
+#endif
+
+ /// <summary>
+ /// Applications that make use of compact type IDs to conserve space
+ /// when marshaling class instances, and also use the streaming API to
+ /// extract such classes, can intercept the translation between compact
+ /// type IDs and their corresponding string type IDs by installing an
+ /// instance of CompactIdResolver in InitializationData.
+ /// </summary>
+ public delegate string CompactIdResolver(int id);
+
+ /// <summary>
+ /// A class that encpasulates data to initialize a communicator.
+ /// </summary>
+ public class InitializationData : ICloneable
+ {
+ /// <summary>
+ /// Creates and returns a copy of this object.
+ /// </summary>
+ public System.Object Clone()
+ {
+ //
+ // A member-wise copy is safe because the members are immutable.
+ //
+ return MemberwiseClone();
+ }
+
+ /// <summary>
+ /// The properties for the communicator.
+ /// </summary>
+ public Properties properties;
+
+ /// <summary>
+ /// The logger for the communicator.
+ /// </summary>
+ public Logger logger;
+
+ /// <summary>
+ /// The communicator observer used by the Ice run-time.
+ /// </summary>
+ public Ice.Instrumentation.CommunicatorObserver observer;
+
+ /// <summary>
+ /// The thread hook for the communicator.
+ /// </summary>
+ public ThreadNotification threadHook;
+
+ /// <summary>
+ /// The dispatcher for the communicator.
+ /// </summary>
+ public Dispatcher dispatcher;
+
+ /// <summary>
+ /// The compact type ID resolver.
+ /// </summary>
+ public CompactIdResolver compactIdResolver;
+
+ /// <summary>
+ /// The batch request interceptor.
+ /// </summary>
+ public BatchRequestInterceptor batchRequestInterceptor;
+ }
+
+ /// <summary>
+ /// Utility methods for the Ice run time.
+ /// </summary>
+ public sealed class Util
+ {
+ /// <summary>
+ /// Creates a new empty property set.
+ /// </summary>
+ /// <returns>A new empty property set.</returns>
+ public static Properties createProperties()
+ {
+ return new PropertiesI();
+ }
+
+ /// <summary>
+ /// Creates a property set initialized from an argument vector.
+ /// </summary>
+ /// <param name="args">A command-line argument vector, possibly containing
+ /// options to set properties. If the command-line options include
+ /// a --Ice.Config option, the corresponding configuration
+ /// files are parsed. If the same property is set in a configuration
+ /// file and in the argument vector, the argument vector takes precedence.
+ /// This method modifies the argument vector by removing any Ice-related options.</param>
+ /// <returns>A property set initialized with the property settings
+ /// that were removed from args.</returns>
+ public static Properties createProperties(ref string[] args)
+ {
+ return new PropertiesI(ref args, null);
+ }
+
+ /// <summary>
+ /// Creates a property set initialized from an argument vector.
+ /// </summary>
+ /// <param name="args">A command-line argument vector, possibly containing
+ /// options to set properties. If the command-line options include
+ /// a --Ice.Config option, the corresponding configuration
+ /// files are parsed. If the same property is set in a configuration
+ /// file and in the argument vector, the argument vector takes precedence.
+ /// This method modifies the argument vector by removing any Ice-related options.</param>
+ /// <param name="defaults">Default values for the property set. Settings in configuration
+ /// files and args override these defaults.</param>
+ /// <returns>A property set initialized with the property settings
+ /// that were removed from args.</returns>
+ public static Properties createProperties(ref string[] args, Properties defaults)
+ {
+ return new PropertiesI(ref args, defaults);
+ }
+
+ /// <summary>
+ /// Creates a communicator.
+ /// </summary>
+ /// <param name="args">A command-line argument vector. Any Ice-related options
+ /// in this vector are used to intialize the communicator.
+ /// This method modifies the argument vector by removing any Ice-related options.</param>
+ /// <returns>The initialized communicator.</returns>
+ public static Communicator initialize(ref string[] args)
+ {
+ return initialize(ref args, null);
+ }
+
+ /// <summary>
+ /// Creates a communicator.
+ /// </summary>
+ /// <param name="args">A command-line argument vector. Any Ice-related options
+ /// in this vector are used to intialize the communicator.
+ /// This method modifies the argument vector by removing any Ice-related options.</param>
+ /// <param name="initData">Additional intialization data. Property settings in args
+ /// override property settings in initData.</param>
+ /// <returns>The initialized communicator.</returns>
+ public static Communicator initialize(ref string[] args, InitializationData initData)
+ {
+ if(initData == null)
+ {
+ initData = new InitializationData();
+ }
+ else
+ {
+ initData = (InitializationData)initData.Clone();
+ }
+
+ initData.properties = createProperties(ref args, initData.properties);
+
+ CommunicatorI result = new CommunicatorI(initData);
+ result.finishSetup(ref args);
+ return result;
+ }
+
+ /// <summary>
+ /// Creates a communicator.
+ /// </summary>
+ /// <param name="initData">Additional intialization data.</param>
+ /// <returns>The initialized communicator.</returns>
+ public static Communicator initialize(InitializationData initData)
+ {
+ if(initData == null)
+ {
+ initData = new InitializationData();
+ }
+ else
+ {
+ initData = (InitializationData)initData.Clone();
+ }
+
+ CommunicatorI result = new CommunicatorI(initData);
+ string[] args = new string[0];
+ result.finishSetup(ref args);
+ return result;
+ }
+
+ /// <summary>
+ /// Creates a communicator using a default configuration.
+ /// </summary>
+ public static Communicator initialize()
+ {
+ return initialize(null);
+ }
+
+ /// <summary>
+ /// Converts a string to an object identity.
+ /// </summary>
+ /// <param name="s">The string to convert.</param>
+ /// <returns>The converted object identity.</returns>
+ public static Identity stringToIdentity(string s)
+ {
+ Identity ident = new Identity();
+
+ //
+ // Find unescaped separator; note that the string may contain an escaped
+ // backslash before the separator.
+ //
+ int slash = -1, pos = 0;
+ while((pos = s.IndexOf((System.Char) '/', pos)) != -1)
+ {
+ int escapes = 0;
+ while(pos - escapes > 0 && s[pos - escapes - 1] == '\\')
+ {
+ escapes++;
+ }
+
+ //
+ // We ignore escaped escapes
+ //
+ if(escapes % 2 == 0)
+ {
+ if(slash == -1)
+ {
+ slash = pos;
+ }
+ else
+ {
+ //
+ // Extra unescaped slash found.
+ //
+ IdentityParseException ex = new IdentityParseException();
+ ex.str = "unescaped backslash in identity `" + s + "'";
+ throw ex;
+ }
+ }
+ pos++;
+ }
+
+ if(slash == -1)
+ {
+ ident.category = "";
+ try
+ {
+ ident.name = IceUtilInternal.StringUtil.unescapeString(s, 0, s.Length);
+ }
+ catch(System.ArgumentException e)
+ {
+ IdentityParseException ex = new IdentityParseException();
+ ex.str = "invalid identity name `" + s + "': " + e.Message;
+ throw ex;
+ }
+ }
+ else
+ {
+ try
+ {
+ ident.category = IceUtilInternal.StringUtil.unescapeString(s, 0, slash);
+ }
+ catch(System.ArgumentException e)
+ {
+ IdentityParseException ex = new IdentityParseException();
+ ex.str = "invalid category in identity `" + s + "': " + e.Message;
+ throw ex;
+ }
+ if(slash + 1 < s.Length)
+ {
+ try
+ {
+ ident.name = IceUtilInternal.StringUtil.unescapeString(s, slash + 1, s.Length);
+ }
+ catch(System.ArgumentException e)
+ {
+ IdentityParseException ex = new IdentityParseException();
+ ex.str = "invalid name in identity `" + s + "': " + e.Message;
+ throw ex;
+ }
+ }
+ else
+ {
+ ident.name = "";
+ }
+ }
+
+ return ident;
+ }
+
+ /// <summary>
+ /// Converts an object identity to a string.
+ /// </summary>
+ /// <param name="ident">The object identity to convert.</param>
+ /// <returns>The string representation of the object identity.</returns>
+ public static string identityToString(Identity ident)
+ {
+ if(ident.category == null || ident.category.Length == 0)
+ {
+ return IceUtilInternal.StringUtil.escapeString(ident.name, "/");
+ }
+ else
+ {
+ return IceUtilInternal.StringUtil.escapeString(ident.category, "/") + '/' +
+ IceUtilInternal.StringUtil.escapeString(ident.name, "/");
+ }
+ }
+
+ /// <summary>
+ /// This method is deprecated. Use System.Guid instead.
+ /// </summary>
+ [Obsolete("This method is deprecated. Use System.Guid instead.")]
+ public static string generateUUID()
+ {
+ return Guid.NewGuid().ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture);
+ }
+
+ /// <summary>
+ /// Compares the object identities of two proxies.
+ /// </summary>
+ /// <param name="lhs">A proxy.</param>
+ /// <param name="rhs">A proxy.</param>
+ /// <returns>-1 if the identity in lhs compares
+ /// less than the identity in rhs; 0 if the identities
+ /// compare equal; 1, otherwise.</returns>
+ public static int proxyIdentityCompare(ObjectPrx lhs, ObjectPrx rhs)
+ {
+ if(lhs == null && rhs == null)
+ {
+ return 0;
+ }
+ else if(lhs == null && rhs != null)
+ {
+ return -1;
+ }
+ else if(lhs != null && rhs == null)
+ {
+ return 1;
+ }
+ else
+ {
+ Identity lhsIdentity = lhs.ice_getIdentity();
+ Identity rhsIdentity = rhs.ice_getIdentity();
+ int n;
+ n = string.CompareOrdinal(lhsIdentity.name, rhsIdentity.name);
+ if(n != 0)
+ {
+ return n;
+ }
+ return string.CompareOrdinal(lhsIdentity.category, rhsIdentity.category);
+ }
+ }
+
+ /// <summary>
+ /// Compares the object identities and facets of two proxies.
+ /// </summary>
+ /// <param name="lhs">A proxy.</param>
+ /// <param name="rhs">A proxy.</param>
+ /// <returns>-1 if the identity and facet in lhs compare
+ /// less than the identity and facet in rhs; 0 if the identities
+ /// and facets compare equal; 1, otherwise.</returns>
+ public static int proxyIdentityAndFacetCompare(ObjectPrx lhs, ObjectPrx rhs)
+ {
+ if(lhs == null && rhs == null)
+ {
+ return 0;
+ }
+ else if(lhs == null && rhs != null)
+ {
+ return -1;
+ }
+ else if(lhs != null && rhs == null)
+ {
+ return 1;
+ }
+ else
+ {
+ Identity lhsIdentity = lhs.ice_getIdentity();
+ Identity rhsIdentity = rhs.ice_getIdentity();
+ int n;
+ n = string.CompareOrdinal(lhsIdentity.name, rhsIdentity.name);
+ if(n != 0)
+ {
+ return n;
+ }
+ n = string.CompareOrdinal(lhsIdentity.category, rhsIdentity.category);
+ if(n != 0)
+ {
+ return n;
+ }
+
+ string lhsFacet = lhs.ice_getFacet();
+ string rhsFacet = rhs.ice_getFacet();
+ if(lhsFacet == null && rhsFacet == null)
+ {
+ return 0;
+ }
+ else if(lhsFacet == null)
+ {
+ return -1;
+ }
+ else if(rhsFacet == null)
+ {
+ return 1;
+ }
+ else
+ {
+ return string.CompareOrdinal(lhsFacet, rhsFacet);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Creates an input stream for dynamic invocation and dispatch. The stream uses
+ /// the communicator's default encoding version. The given data is copied.
+ /// </summary>
+ /// <param name="communicator">The communicator for the stream.</param>
+ /// <param name="bytes">An encoded request or reply.</param>
+ /// <returns>The input stream.</returns>
+ public static InputStream createInputStream(Communicator communicator, byte[] bytes)
+ {
+ return new InputStreamI(communicator, bytes, true);
+ }
+
+ /// <summary>
+ /// Creates an input stream for dynamic invocation and dispatch. The stream uses
+ /// the given encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator for the stream.</param>
+ /// <param name="bytes">An encoded request or reply.</param>
+ /// <param name="v">The desired encoding version.</param>
+ /// <returns>The input stream.</returns>
+ public static InputStream createInputStream(Communicator communicator, byte[] bytes, EncodingVersion v)
+ {
+ return new InputStreamI(communicator, bytes, v, true);
+ }
+
+ /// <summary>
+ /// Wraps encoded data with an input stream for dynamic invocation and dispatch.
+ /// The stream uses the communicator's default encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator for the stream.</param>
+ /// <param name="bytes">An encoded request or reply.</param>
+ /// <returns>The input stream.</returns>
+ public static InputStream wrapInputStream(Communicator communicator, byte[] bytes)
+ {
+ return new InputStreamI(communicator, bytes, false);
+ }
+
+ /// <summary>
+ /// Wraps encoded data with an input stream for dynamic invocation and dispatch.
+ /// The stream uses the given encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator for the stream.</param>
+ /// <param name="bytes">An encoded request or reply.</param>
+ /// <param name="v">The desired encoding version.</param>
+ /// <returns>The input stream.</returns>
+ public static InputStream wrapInputStream(Communicator communicator, byte[] bytes, EncodingVersion v)
+ {
+ return new InputStreamI(communicator, bytes, v, false);
+ }
+
+ /// <summary>
+ /// Creates an output stream for dynamic invocation and dispatch. The stream uses
+ /// the communicator's default encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator for the stream.</param>
+ /// <returns>The output stream.</returns>
+ public static OutputStream createOutputStream(Communicator communicator)
+ {
+ return new OutputStreamI(communicator);
+ }
+
+ /// <summary>
+ /// Creates an output stream for dynamic invocation and dispatch. The stream uses
+ /// the given encoding version.
+ /// </summary>
+ /// <param name="communicator">The communicator for the stream.</param>
+ /// <param name="v">The desired encoding version.</param>
+ /// <returns>The output stream.</returns>
+ public static OutputStream createOutputStream(Communicator communicator, EncodingVersion v)
+ {
+ return new OutputStreamI(communicator, v);
+ }
+
+ /// <summary>
+ /// Returns the process-wide logger.
+ /// </summary>
+ /// <returns>The process-wide logger.</returns>
+ public static Logger getProcessLogger()
+ {
+ lock(_processLoggerMutex)
+ {
+ if(_processLogger == null)
+ {
+ _processLogger = new ConsoleLoggerI(System.AppDomain.CurrentDomain.FriendlyName);
+ }
+ return _processLogger;
+ }
+ }
+
+ /// <summary>
+ /// Changes the process-wide logger.
+ /// </summary>
+ /// <param name="logger">The new process-wide logger.</param>
+ public static void setProcessLogger(Logger logger)
+ {
+ lock(_processLoggerMutex)
+ {
+ _processLogger = logger;
+ }
+ }
+
+ /// <summary>
+ /// Returns the Ice version in the form A.B.C, where A indicates the
+ /// major version, B indicates the minor version, and C indicates the
+ /// patch level.
+ /// </summary>
+ /// <returns>The Ice version.</returns>
+ public static string stringVersion()
+ {
+ return "3.6.0"; // "A.B.C", with A=major, B=minor, C=patch
+ }
+
+ /// <summary>
+ /// Returns the Ice version as an integer in the form A.BB.CC, where A
+ /// indicates the major version, BB indicates the minor version, and CC
+ /// indicates the patch level. For example, for Ice 3.3.1, the returned value is 30301.
+ /// </summary>
+ /// <returns>The Ice version.</returns>
+ public static int intVersion()
+ {
+ return 30600; // AABBCC, with AA=major, BB=minor, CC=patch
+ }
+
+ /// <summary>
+ /// Converts a string to a protocol version.
+ /// </summary>
+ /// <param name="version">The string to convert.</param>
+ /// <returns>The converted protocol version.</returns>
+ public static Ice.ProtocolVersion stringToProtocolVersion(string version)
+ {
+ byte major, minor;
+ stringToMajorMinor(version, out major, out minor);
+ return new Ice.ProtocolVersion(major, minor);
+ }
+
+ /// <summary>
+ /// Converts a string to an encoding version.
+ /// </summary>
+ /// <param name="version">The string to convert.</param>
+ /// <returns>The converted object identity.</returns>
+ public static Ice.EncodingVersion stringToEncodingVersion(string version)
+ {
+ byte major, minor;
+ stringToMajorMinor(version, out major, out minor);
+ return new Ice.EncodingVersion(major, minor);
+ }
+
+ /// <summary>
+ /// Converts a protocol version to a string.
+ /// </summary>
+ /// <param name="v">The protocol version to convert.</param>
+ /// <returns>The converted string.</returns>
+ public static string protocolVersionToString(Ice.ProtocolVersion v)
+ {
+ return majorMinorToString(v.major, v.minor);
+ }
+
+ /// <summary>
+ /// Converts an encoding version to a string.
+ /// </summary>
+ /// <param name="v">The encoding version to convert.</param>
+ /// <returns>The converted string.</returns>
+ public static string encodingVersionToString(Ice.EncodingVersion v)
+ {
+ return majorMinorToString(v.major, v.minor);
+ }
+
+ static private void stringToMajorMinor(string str, out byte major, out byte minor)
+ {
+ int pos = str.IndexOf((System.Char) '.');
+ if(pos == -1)
+ {
+ throw new Ice.VersionParseException("malformed version value `" + str + "'");
+ }
+
+ string majStr = str.Substring(0, (pos) - (0));
+ string minStr = str.Substring(pos + 1, (str.Length) - (pos + 1));
+ int majVersion;
+ int minVersion;
+ try
+ {
+ majVersion = System.Int32.Parse(majStr, CultureInfo.InvariantCulture);
+ minVersion = System.Int32.Parse(minStr, CultureInfo.InvariantCulture);
+ }
+ catch(System.FormatException)
+ {
+ throw new Ice.VersionParseException("invalid version value `" + str + "'");
+ }
+
+ if(majVersion < 1 || majVersion > 255 || minVersion < 0 || minVersion > 255)
+ {
+ throw new Ice.VersionParseException("range error in version `" + str + "'");
+ }
+
+ major = (byte)majVersion;
+ minor = (byte)minVersion;
+ }
+
+ static private String majorMinorToString(byte major, byte minor)
+ {
+ StringBuilder str = new StringBuilder();
+ str.Append(major < 0 ? (int)major + 255 : (int)major);
+ str.Append(".");
+ str.Append(minor < 0 ? (int)minor + 255 : (int)minor);
+ return str.ToString();
+ }
+
+ public static readonly ProtocolVersion currentProtocol =
+ new ProtocolVersion(IceInternal.Protocol.protocolMajor, IceInternal.Protocol.protocolMinor);
+
+ public static readonly EncodingVersion currentProtocolEncoding =
+ new EncodingVersion(IceInternal.Protocol.protocolEncodingMajor,
+ IceInternal.Protocol.protocolEncodingMinor);
+
+ public static readonly EncodingVersion currentEncoding =
+ new EncodingVersion(IceInternal.Protocol.encodingMajor, IceInternal.Protocol.encodingMinor);
+
+ public static readonly ProtocolVersion Protocol_1_0 = new ProtocolVersion(1, 0);
+
+ public static readonly EncodingVersion Encoding_1_0 = new EncodingVersion(1, 0);
+ public static readonly EncodingVersion Encoding_1_1 = new EncodingVersion(1, 1);
+
+ public static readonly NoneType None = new NoneType();
+
+ private static object _processLoggerMutex = new object();
+ private static Logger _processLogger = null;
+ }
+}
+
+namespace IceInternal
+{
+ public sealed class HashUtil
+ {
+ public static void hashAdd(ref int hashCode, bool value)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ value.GetHashCode());
+ }
+
+ public static void hashAdd(ref int hashCode, short value)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ (int)(2654435761 * value));
+ }
+
+ public static void hashAdd(ref int hashCode, byte value)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ (int)(2654435761 * value));
+ }
+
+ public static void hashAdd(ref int hashCode, int value)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ (int)(2654435761 * value));
+ }
+
+ public static void hashAdd(ref int hashCode, long value)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ value.GetHashCode());
+ }
+
+ public static void hashAdd(ref int hashCode, float value)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ value.GetHashCode());
+ }
+
+ public static void hashAdd(ref int hashCode, double value)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ value.GetHashCode());
+ }
+
+ public static void hashAdd(ref int hashCode, object value)
+ {
+ if(value != null)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ value.GetHashCode());
+ }
+ }
+
+ public static void hashAdd(ref int hashCode, object[] arr)
+ {
+ if(arr != null)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ IceUtilInternal.Arrays.GetHashCode(arr));
+ }
+ }
+
+ public static void hashAdd(ref int hashCode, Array arr)
+ {
+ if(arr != null)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ IceUtilInternal.Arrays.GetHashCode(arr));
+ }
+ }
+
+ public static void hashAdd(ref int hashCode, IEnumerable s)
+ {
+ if(s != null)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ IceUtilInternal.Collections.SequenceGetHashCode(s));
+ }
+ }
+
+ public static void hashAdd(ref int hashCode, IDictionary d)
+ {
+ if(d != null)
+ {
+ hashCode = unchecked(((hashCode << 5) + hashCode) ^ IceUtilInternal.Collections.DictionaryGetHashCode(d));
+ }
+ }
+ }
+
+ public sealed class Util
+ {
+ public static Instance getInstance(Ice.Communicator communicator)
+ {
+ Ice.CommunicatorI p = (Ice.CommunicatorI) communicator;
+ return p.getInstance();
+ }
+
+ public static ProtocolPluginFacade getProtocolPluginFacade(Ice.Communicator communicator)
+ {
+ return new ProtocolPluginFacadeI(communicator);
+ }
+
+#if !SILVERLIGHT
+ public static System.Threading.ThreadPriority stringToThreadPriority(string s)
+ {
+ if(String.IsNullOrEmpty(s))
+ {
+ return ThreadPriority.Normal;
+ }
+ if(s.StartsWith("ThreadPriority.", StringComparison.Ordinal))
+ {
+ s = s.Substring("ThreadPriority.".Length, s.Length);
+ }
+ if(s.Equals("Lowest"))
+ {
+ return ThreadPriority.Lowest;
+ }
+ else if(s.Equals("BelowNormal"))
+ {
+ return ThreadPriority.BelowNormal;
+ }
+ else if(s.Equals("Normal"))
+ {
+ return ThreadPriority.Normal;
+ }
+ else if(s.Equals("AboveNormal"))
+ {
+ return ThreadPriority.AboveNormal;
+ }
+ else if(s.Equals("Highest"))
+ {
+ return ThreadPriority.Highest;
+ }
+ return ThreadPriority.Normal;
+ }
+#endif
+ }
+}
+
+#if SILVERLIGHT
+namespace System
+{
+ public interface ICloneable
+ {
+ Object Clone();
+ }
+}
+#endif
diff --git a/csharp/src/Ice/ValueWriter.cs b/csharp/src/Ice/ValueWriter.cs
new file mode 100644
index 00000000000..5e8ecbaa1eb
--- /dev/null
+++ b/csharp/src/Ice/ValueWriter.cs
@@ -0,0 +1,154 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Reflection;
+ using IceUtilInternal;
+
+ public sealed class ValueWriter
+ {
+ public static void write(object obj, OutputBase output)
+ {
+ writeValue(null, obj, null, output);
+ }
+
+ private static void writeValue(string name, object val, Dictionary<Ice.Object, object> objectTable, OutputBase output)
+ {
+ if(val == null)
+ {
+ writeName(name, output);
+ output.print("(null)");
+ }
+ else
+ {
+ System.Type c = val.GetType();
+ if(c.Equals(typeof(byte)) || c.Equals(typeof(short)) || c.Equals(typeof(int)) ||
+ c.Equals(typeof(long)) || c.Equals(typeof(double)) || c.Equals(typeof(float)) ||
+ c.Equals(typeof(bool)))
+ {
+ writeName(name, output);
+ output.print(val.ToString());
+ }
+ else if(c.Equals(typeof(string)))
+ {
+ writeName(name, output);
+ output.print("\"");
+ output.print(val.ToString());
+ output.print("\"");
+ }
+ else if(val is IList)
+ {
+ int n = 0;
+ IEnumerator i = ((IList)val).GetEnumerator();
+ while(i.MoveNext())
+ {
+ string elem = (name != null ? name : "");
+ elem += "[" + n++ + "]";
+ writeValue(elem, i.Current, objectTable, output);
+ }
+ }
+ else if(val is IDictionary)
+ {
+ foreach(DictionaryEntry entry in (IDictionary)val)
+ {
+ string elem = name != null ? name + "." : "";
+ writeValue(elem + "key", entry.Key, objectTable, output);
+ writeValue(elem + "value", entry.Value, objectTable, output);
+ }
+ }
+ else if(val is Ice.ObjectPrxHelperBase)
+ {
+ writeName(name, output);
+ Ice.ObjectPrxHelperBase proxy = (Ice.ObjectPrxHelperBase)val;
+ output.print(proxy.reference__().ToString());
+ }
+ else if(val is Ice.Object)
+ {
+ //
+ // Check for recursion.
+ //
+ if(objectTable != null && objectTable.ContainsKey((Ice.Object)val))
+ {
+ writeName(name, output);
+ output.print("(recursive)");
+ }
+ else
+ {
+ if(objectTable == null)
+ {
+ objectTable = new Dictionary<Ice.Object, object>();
+ }
+ objectTable[(Ice.Object)val] = null;
+ writeFields(name, val, c, objectTable, output);
+ }
+ }
+ else if(c.IsEnum)
+ {
+ writeName(name, output);
+ output.print(val.ToString());
+ }
+ else
+ {
+ //
+ // Must be struct.
+ //
+ writeFields(name, val, c, objectTable, output);
+ }
+ }
+ }
+
+ private static void writeFields(string name, object obj, System.Type c, Dictionary<Ice.Object, object> objectTable,
+ OutputBase output)
+ {
+ if(!c.Equals(typeof(object)))
+ {
+ //
+ // Write the superclass first.
+ //
+ writeFields(name, obj, c.BaseType, objectTable, output);
+
+ //
+ // Write the declared fields of the given class.
+ //
+ FieldInfo[] fields =
+ c.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public);
+
+ for(int i = 0; i < fields.Length; i++)
+ {
+ string fieldName = (name != null ? name + '.' + fields[i].Name : fields[i].Name);
+
+ try
+ {
+ object val = fields[i].GetValue(obj);
+ writeValue(fieldName, val, objectTable, output);
+ }
+ catch(System.UnauthorizedAccessException)
+ {
+ Debug.Assert(false);
+ }
+ }
+ }
+ }
+
+ private static void writeName(string name, OutputBase output)
+ {
+ if(name != null)
+ {
+ output.nl();
+ output.print(name + " = ");
+ }
+ }
+ }
+
+}
diff --git a/csharp/src/Ice/WSAcceptor.cs b/csharp/src/Ice/WSAcceptor.cs
new file mode 100644
index 00000000000..68d2d526a9c
--- /dev/null
+++ b/csharp/src/Ice/WSAcceptor.cs
@@ -0,0 +1,73 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System.Diagnostics;
+
+ class WSAcceptor : Acceptor
+ {
+ public void close()
+ {
+ _delegate.close();
+ }
+
+ public EndpointI listen()
+ {
+ _endpoint = _endpoint.endpoint(_delegate.listen());
+ return _endpoint;
+ }
+
+ public bool startAccept(AsyncCallback callback, object state)
+ {
+ return _delegate.startAccept(callback, state);
+ }
+
+ public void finishAccept()
+ {
+ _delegate.finishAccept();
+ }
+
+ public Transceiver accept()
+ {
+ return new WSTransceiver(_instance, _delegate.accept());
+ }
+
+ public string protocol()
+ {
+ return _delegate.protocol();
+ }
+
+ public override string ToString()
+ {
+ return _delegate.ToString();
+ }
+
+ public string toDetailedString()
+ {
+ return _delegate.toDetailedString();
+ }
+
+ public Acceptor getDelegate()
+ {
+ return _delegate;
+ }
+
+ internal WSAcceptor(WSEndpoint endpoint, ProtocolInstance instance, Acceptor del)
+ {
+ _endpoint = endpoint;
+ _instance = instance;
+ _delegate = del;
+ }
+
+ private WSEndpoint _endpoint;
+ private ProtocolInstance _instance;
+ private Acceptor _delegate;
+ }
+}
diff --git a/csharp/src/Ice/WSConnector.cs b/csharp/src/Ice/WSConnector.cs
new file mode 100644
index 00000000000..0661ab6fbf0
--- /dev/null
+++ b/csharp/src/Ice/WSConnector.cs
@@ -0,0 +1,75 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ sealed class WSConnector : IceInternal.Connector
+ {
+ public IceInternal.Transceiver connect()
+ {
+ return new WSTransceiver(_instance, _delegate.connect(), _host, _port, _resource);
+ }
+
+ public short type()
+ {
+ return _delegate.type();
+ }
+
+ internal WSConnector(ProtocolInstance instance, IceInternal.Connector del, string host, int port, string resource)
+ {
+ _instance = instance;
+ _delegate = del;
+ _host = host;
+ _port = port;
+ _resource = resource;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(!(obj is WSConnector))
+ {
+ return false;
+ }
+
+ if(this == obj)
+ {
+ return true;
+ }
+
+ WSConnector p = (WSConnector)obj;
+ if(!_delegate.Equals(p._delegate))
+ {
+ return false;
+ }
+
+ if(!_resource.Equals(p._resource))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public override string ToString()
+ {
+ return _delegate.ToString();
+ }
+
+ public override int GetHashCode()
+ {
+ return _delegate.GetHashCode();
+ }
+
+ private ProtocolInstance _instance;
+ private IceInternal.Connector _delegate;
+ private string _host;
+ private int _port;
+ private string _resource;
+ }
+}
diff --git a/csharp/src/Ice/WSEndpoint.cs b/csharp/src/Ice/WSEndpoint.cs
new file mode 100644
index 00000000000..27f7816d5e9
--- /dev/null
+++ b/csharp/src/Ice/WSEndpoint.cs
@@ -0,0 +1,372 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Collections.Generic;
+ using System.Globalization;
+
+ sealed class WSEndpoint : EndpointI
+ {
+ internal WSEndpoint(ProtocolInstance instance, EndpointI del, string res)
+ {
+ _instance = instance;
+ _delegate = (IPEndpointI)del;
+ _resource = res;
+ }
+
+ internal WSEndpoint(ProtocolInstance instance, EndpointI del, List<string> args)
+ {
+ _instance = instance;
+ _delegate = (IPEndpointI)del;
+
+ initWithOptions(args);
+
+ if(_resource == null)
+ {
+ _resource = "/";
+ }
+ }
+
+ internal WSEndpoint(ProtocolInstance instance, EndpointI del, BasicStream s)
+ {
+ _instance = instance;
+ _delegate = (IPEndpointI)del;
+
+ _resource = s.readString();
+ }
+
+ private sealed class InfoI : Ice.WSEndpointInfo
+ {
+ public InfoI(EndpointI e)
+ {
+ _endpoint = e;
+ }
+
+ override public short type()
+ {
+ return _endpoint.type();
+ }
+
+ override public bool datagram()
+ {
+ return _endpoint.datagram();
+ }
+
+ override public bool secure()
+ {
+ return _endpoint.secure();
+ }
+
+ private EndpointI _endpoint;
+ }
+
+ public override Ice.EndpointInfo getInfo()
+ {
+ InfoI info = new InfoI(this);
+ _delegate.fillEndpointInfo(info);
+ info.resource = _resource;
+ return info;
+ }
+
+ public override short type()
+ {
+ return _delegate.type();
+ }
+
+ public override string protocol()
+ {
+ return _delegate.protocol();
+ }
+
+ public override void streamWrite(BasicStream s)
+ {
+ s.startWriteEncaps();
+ _delegate.streamWriteImpl(s);
+ s.writeString(_resource);
+ s.endWriteEncaps();
+ }
+
+ public override int timeout()
+ {
+ return _delegate.timeout();
+ }
+
+ public override EndpointI timeout(int timeout)
+ {
+ if(timeout == _delegate.timeout())
+ {
+ return this;
+ }
+ else
+ {
+ return new WSEndpoint(_instance, _delegate.timeout(timeout), _resource);
+ }
+ }
+
+ public override string connectionId()
+ {
+ return _delegate.connectionId();
+ }
+
+ public override EndpointI connectionId(string connectionId)
+ {
+ if(connectionId.Equals(_delegate.connectionId()))
+ {
+ return this;
+ }
+ else
+ {
+ return new WSEndpoint(_instance, _delegate.connectionId(connectionId), _resource);
+ }
+ }
+
+ public override bool compress()
+ {
+ return _delegate.compress();
+ }
+
+ public override EndpointI compress(bool compress)
+ {
+ if(compress == _delegate.compress())
+ {
+ return this;
+ }
+ else
+ {
+ return new WSEndpoint(_instance, _delegate.compress(compress), _resource);
+ }
+ }
+
+ public override bool datagram()
+ {
+ return _delegate.datagram();
+ }
+
+ public override bool secure()
+ {
+ return _delegate.secure();
+ }
+
+ public override Transceiver transceiver()
+ {
+ return null;
+ }
+
+ private sealed class EndpointI_connectorsI : EndpointI_connectors
+ {
+ public EndpointI_connectorsI(ProtocolInstance instance, string host, int port, string resource,
+ EndpointI_connectors cb)
+ {
+ _instance = instance;
+ _host = host;
+ _port = port;
+ _resource = resource;
+ _callback = cb;
+ }
+
+ public void connectors(List<Connector> connectors)
+ {
+ List<Connector> l = new List<Connector>();
+ foreach(Connector c in connectors)
+ {
+ l.Add(new WSConnector(_instance, c, _host, _port, _resource));
+ }
+ _callback.connectors(l);
+ }
+
+ public void exception(Ice.LocalException ex)
+ {
+ _callback.exception(ex);
+ }
+
+ private ProtocolInstance _instance;
+ private string _host;
+ private int _port;
+ private string _resource;
+ private EndpointI_connectors _callback;
+ }
+
+ public override void connectors_async(Ice.EndpointSelectionType selType,
+ EndpointI_connectors callback)
+ {
+ EndpointI_connectorsI cb =
+ new EndpointI_connectorsI(_instance, _delegate.host(), _delegate.port(), _resource, callback);
+ _delegate.connectors_async(selType, cb);
+ }
+
+ public override Acceptor acceptor(string adapterName)
+ {
+ Acceptor delAcc = _delegate.acceptor(adapterName);
+ return new WSAcceptor(this, _instance, delAcc);
+ }
+
+ public WSEndpoint endpoint(EndpointI delEndp)
+ {
+ return new WSEndpoint(_instance, delEndp, _resource);
+ }
+
+ public override List<EndpointI> expand()
+ {
+ List<EndpointI> endps = _delegate.expand();
+ List<EndpointI> l = new List<EndpointI>();
+ foreach(EndpointI e in endps)
+ {
+ l.Add(e == _delegate ? this : new WSEndpoint(_instance, e, _resource));
+ }
+ return l;
+ }
+
+ public override bool equivalent(EndpointI endpoint)
+ {
+ if(!(endpoint is WSEndpoint))
+ {
+ return false;
+ }
+ WSEndpoint wsEndpointI = (WSEndpoint)endpoint;
+ return _delegate.equivalent(wsEndpointI._delegate);
+ }
+
+ public override string options()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ string s = _delegate.options();
+
+ if(_resource != null && _resource.Length > 0)
+ {
+ s += " -r ";
+ bool addQuote = _resource.IndexOf(':') != -1;
+ if(addQuote)
+ {
+ s += "\"";
+ }
+ s += _resource;
+ if(addQuote)
+ {
+ s += "\"";
+ }
+ }
+
+ return s;
+ }
+
+ public override int GetHashCode()
+ {
+ int h = _delegate.GetHashCode();
+ HashUtil.hashAdd(ref h, _resource);
+ return h;
+ }
+
+ public override int CompareTo(EndpointI obj)
+ {
+ if(!(obj is EndpointI))
+ {
+ return type() < obj.type() ? -1 : 1;
+ }
+
+ WSEndpoint p = (WSEndpoint)obj;
+ if(this == p)
+ {
+ return 0;
+ }
+
+ int v = string.Compare(_resource, p._resource, StringComparison.Ordinal);
+ if(v != 0)
+ {
+ return v;
+ }
+
+ return _delegate.CompareTo(p._delegate);
+ }
+
+ public EndpointI getDelegate()
+ {
+ return _delegate;
+ }
+
+ protected override bool checkOption(string option, string argument, string endpoint)
+ {
+ switch(option[1])
+ {
+ case 'r':
+ {
+ if(argument == null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "no argument provided for -r option in endpoint " + endpoint + _delegate.options();
+ throw e;
+ }
+ _resource = argument;
+ return true;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
+ private ProtocolInstance _instance;
+ private IPEndpointI _delegate;
+ private string _resource;
+ }
+
+ public class WSEndpointFactory : EndpointFactory
+ {
+ public WSEndpointFactory(ProtocolInstance instance, EndpointFactory del)
+ {
+ _instance = instance;
+ _delegate = del;
+ }
+
+ public short type()
+ {
+ return _instance.type();
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public EndpointI create(List<string> args, bool oaEndpoint)
+ {
+ return new WSEndpoint(_instance, _delegate.create(args, oaEndpoint), args);
+ }
+
+ public EndpointI read(BasicStream s)
+ {
+ return new WSEndpoint(_instance, _delegate.read(s), s);
+ }
+
+ public void destroy()
+ {
+ _delegate.destroy();
+ _instance = null;
+ }
+
+ public EndpointFactory clone(ProtocolInstance instance)
+ {
+ Debug.Assert(false); // We don't support cloning this transport.
+ return null;
+ }
+
+ private ProtocolInstance _instance;
+ private EndpointFactory _delegate;
+ }
+}
diff --git a/csharp/src/Ice/WSTransceiver.cs b/csharp/src/Ice/WSTransceiver.cs
new file mode 100644
index 00000000000..7218027bdc2
--- /dev/null
+++ b/csharp/src/Ice/WSTransceiver.cs
@@ -0,0 +1,1693 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceInternal
+{
+ using System;
+ using System.Diagnostics;
+ using System.Collections.Generic;
+ using System.Net.Sockets;
+ using System.Security.Cryptography;
+ using System.Text;
+
+ sealed class WSTransceiver : Transceiver
+ {
+ public Socket fd()
+ {
+ return _delegate.fd();
+ }
+
+ public int initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData)
+ {
+ //
+ // Delegate logs exceptions that occur during initialize(), so there's no need to trap them here.
+ //
+ if(_state == StateInitializeDelegate)
+ {
+ int op = _delegate.initialize(readBuffer, writeBuffer, ref hasMoreData);
+ if(op != 0)
+ {
+ return op;
+ }
+ _state = StateConnected;
+ }
+
+ try
+ {
+ if(_state == StateConnected)
+ {
+ //
+ // We don't know how much we'll need to read.
+ //
+ _readBuffer.resize(1024, true);
+ _readBuffer.b.position(0);
+ _readBufferPos = 0;
+
+ //
+ // The server waits for the client's upgrade request, the
+ // client sends the upgrade request.
+ //
+ _state = StateUpgradeRequestPending;
+ if(!_incoming)
+ {
+ //
+ // Compose the upgrade request.
+ //
+ StringBuilder @out = new StringBuilder();
+ @out.Append("GET " + _resource + " HTTP/1.1\r\n");
+ @out.Append("Host: " + _host + ":");
+ @out.Append(_port);
+ @out.Append("\r\n");
+ @out.Append("Upgrade: websocket\r\n");
+ @out.Append("Connection: Upgrade\r\n");
+ @out.Append("Sec-WebSocket-Protocol: " + _iceProtocol + "\r\n");
+ @out.Append("Sec-WebSocket-Version: 13\r\n");
+ @out.Append("Sec-WebSocket-Key: ");
+
+ //
+ // The value for Sec-WebSocket-Key is a 16-byte random number,
+ // encoded with Base64.
+ //
+ byte[] key = new byte[16];
+ _rand.NextBytes(key);
+ _key = IceUtilInternal.Base64.encode(key);
+ @out.Append(_key + "\r\n\r\n"); // EOM
+
+ byte[] bytes = _utf8.GetBytes(@out.ToString());
+ _writeBuffer.resize(bytes.Length, false);
+ _writeBuffer.b.position(0);
+ _writeBuffer.b.put(bytes);
+ _writeBuffer.b.flip();
+ }
+ }
+
+ //
+ // Try to write the client's upgrade request.
+ //
+ if(_state == StateUpgradeRequestPending && !_incoming)
+ {
+ if(_writeBuffer.b.hasRemaining())
+ {
+ int s = _delegate.write(_writeBuffer);
+ if(s != 0)
+ {
+ return s;
+ }
+ }
+ Debug.Assert(!_writeBuffer.b.hasRemaining());
+ _state = StateUpgradeResponsePending;
+ }
+
+ while(true)
+ {
+ if(_readBuffer.b.hasRemaining())
+ {
+ int s = _delegate.read(_readBuffer, ref hasMoreData);
+ if(s == SocketOperation.Write || _readBuffer.b.position() == 0)
+ {
+ return s;
+ }
+ }
+
+ //
+ // Try to read the client's upgrade request or the server's response.
+ //
+ if((_state == StateUpgradeRequestPending && _incoming) ||
+ (_state == StateUpgradeResponsePending && !_incoming))
+ {
+ //
+ // Check if we have enough data for a complete message.
+ //
+ int p = _parser.isCompleteMessage(_readBuffer.b, 0, _readBuffer.b.position());
+ if(p == -1)
+ {
+ if(_readBuffer.b.hasRemaining())
+ {
+ return SocketOperation.Read;
+ }
+
+ //
+ // Enlarge the buffer and try to read more.
+ //
+ int oldSize = _readBuffer.b.position();
+ if(oldSize + 1024 > _instance.messageSizeMax())
+ {
+ throw new Ice.MemoryLimitException();
+ }
+ _readBuffer.resize(oldSize + 1024, true);
+ _readBuffer.b.position(oldSize);
+ continue; // Try again to read the response/request
+ }
+
+ //
+ // Set _readBufferPos at the end of the response/request message.
+ //
+ _readBufferPos = p;
+ }
+
+ //
+ // We're done, the client's upgrade request or server's response is read.
+ //
+ break;
+ }
+
+ try
+ {
+ //
+ // Parse the client's upgrade request.
+ //
+ if(_state == StateUpgradeRequestPending && _incoming)
+ {
+ if(_parser.parse(_readBuffer.b, 0, _readBufferPos))
+ {
+ handleRequest(_writeBuffer);
+ _state = StateUpgradeResponsePending;
+ }
+ else
+ {
+ throw new Ice.ProtocolException("incomplete request message");
+ }
+ }
+
+ if(_state == StateUpgradeResponsePending)
+ {
+ if(_incoming)
+ {
+ if(_writeBuffer.b.hasRemaining())
+ {
+ int s = _delegate.write(_writeBuffer);
+ if(s != 0)
+ {
+ return s;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Parse the server's response
+ //
+ if(_parser.parse(_readBuffer.b, 0, _readBufferPos))
+ {
+ handleResponse();
+ }
+ else
+ {
+ throw new Ice.ProtocolException("incomplete response message");
+ }
+ }
+ }
+ }
+ catch(WebSocketException ex)
+ {
+ throw new Ice.ProtocolException(ex.Message);
+ }
+
+ _state = StateOpened;
+ _nextState = StateOpened;
+
+ hasMoreData = _readBufferPos < _readBuffer.b.position();
+ }
+ catch(Ice.LocalException ex)
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ protocol() + " connection HTTP upgrade request failed\n" + ToString() + "\n" + ex);
+ }
+ throw;
+ }
+
+ if(_instance.traceLevel() >= 1)
+ {
+ if(_incoming)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "accepted " + protocol() + " connection HTTP upgrade request\n" + ToString());
+ }
+ else
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ protocol() + " connection HTTP upgrade request accepted\n" + ToString());
+ }
+ }
+
+ return SocketOperation.None;
+ }
+
+ public int closing(bool initiator, Ice.LocalException reason)
+ {
+ if(_instance.traceLevel() >= 1)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "gracefully closing " + protocol() + " connection\n" + ToString());
+ }
+
+ int s = _nextState == StateOpened ? _state : _nextState;
+
+ if(s == StateClosingRequestPending && _closingInitiator)
+ {
+ //
+ // If we initiated a close connection but also received a
+ // close connection, we assume we didn't initiated the
+ // connection and we send the close frame now. This is to
+ // ensure that if both peers close the connection at the same
+ // time we don't hang having both peer waiting for the close
+ // frame of the other.
+ //
+ Debug.Assert(!initiator);
+ _closingInitiator = false;
+ return SocketOperation.Write;
+ }
+ else if(s >= StateClosingRequestPending)
+ {
+ return SocketOperation.None;
+ }
+
+ _closingInitiator = initiator;
+ if(reason is Ice.CloseConnectionException)
+ {
+ _closingReason = CLOSURE_NORMAL;
+ }
+ else if(reason is Ice.ObjectAdapterDeactivatedException ||
+ reason is Ice.CommunicatorDestroyedException)
+ {
+ _closingReason = CLOSURE_SHUTDOWN;
+ }
+ else if(reason is Ice.ProtocolException)
+ {
+ _closingReason = CLOSURE_PROTOCOL_ERROR;
+ }
+ else if(reason is Ice.MemoryLimitException)
+ {
+ _closingReason = CLOSURE_TOO_BIG;
+ }
+
+ if(_state == StateOpened)
+ {
+ _state = StateClosingRequestPending;
+ return initiator ? SocketOperation.Read : SocketOperation.Write;
+ }
+ else
+ {
+ _nextState = StateClosingRequestPending;
+ return SocketOperation.None;
+ }
+ }
+
+ public void close()
+ {
+ _delegate.close();
+ _state = StateClosed;
+ }
+
+ public EndpointI bind()
+ {
+ Debug.Assert(false);
+ return null;
+ }
+
+ public void destroy()
+ {
+ _delegate.destroy();
+ }
+
+ public int write(Buffer buf)
+ {
+ if(_writePending)
+ {
+ return SocketOperation.Write;
+ }
+
+ if(_state < StateOpened)
+ {
+ if(_state < StateConnected)
+ {
+ return _delegate.write(buf);
+ }
+ else
+ {
+ return _delegate.write(_writeBuffer);
+ }
+ }
+
+ int s = SocketOperation.None;
+ do
+ {
+ if(preWrite(buf))
+ {
+ if(_writeState == WriteStateFlush)
+ {
+ //
+ // Invoke write() even though there's nothing to write.
+ //
+ Debug.Assert(!buf.b.hasRemaining());
+ s = _delegate.write(buf);
+ }
+
+ if(s == SocketOperation.None && _writeBuffer.b.hasRemaining())
+ {
+ s = _delegate.write(_writeBuffer);
+ }
+ else if(s == SocketOperation.None && _incoming && !buf.empty() && _writeState == WriteStatePayload)
+ {
+ s = _delegate.write(buf);
+ }
+ }
+ }
+ while(postWrite(buf, s));
+
+ if(s != SocketOperation.None)
+ {
+ return s;
+ }
+ if(_state == StateClosingResponsePending && !_closingInitiator)
+ {
+ return SocketOperation.Read;
+ }
+ return SocketOperation.None;
+ }
+
+ public int read(Buffer buf, ref bool hasMoreData)
+ {
+ if(_readPending)
+ {
+ return SocketOperation.Read;
+ }
+
+ if(_state < StateOpened)
+ {
+ if(_state < StateConnected)
+ {
+ return _delegate.read(buf, ref hasMoreData);
+ }
+ else
+ {
+ if(_delegate.read(_readBuffer, ref hasMoreData) == SocketOperation.Write)
+ {
+ return SocketOperation.Write;
+ }
+ else
+ {
+ return SocketOperation.None;
+ }
+ }
+ }
+
+ if(!buf.b.hasRemaining())
+ {
+ hasMoreData |= _readBufferPos < _readBuffer.b.position();
+ return SocketOperation.None;
+ }
+
+ int s = SocketOperation.None;
+ do
+ {
+ if(preRead(buf))
+ {
+ if(_readState == ReadStatePayload)
+ {
+ //
+ // If the payload length is smaller than what remains to be read, we read
+ // no more than the payload length. The remaining of the buffer will be
+ // sent over in another frame.
+ //
+ int readSz = _readPayloadLength - (buf.b.position() - _readStart);
+ if(buf.b.remaining() > readSz)
+ {
+ int size = buf.size();
+ buf.resize(buf.b.position() + readSz, true);
+ s = _delegate.read(buf, ref hasMoreData);
+ buf.resize(size, true);
+ }
+ else
+ {
+ s = _delegate.read(buf, ref hasMoreData);
+ }
+ }
+ else
+ {
+ s = _delegate.read(_readBuffer, ref hasMoreData);
+ }
+
+ if(s == SocketOperation.Write)
+ {
+ postRead(buf);
+ return s;
+ }
+ }
+ }
+ while(postRead(buf));
+
+ if(!buf.b.hasRemaining())
+ {
+ hasMoreData |= _readBufferPos < _readBuffer.b.position();
+ s = SocketOperation.None;
+ }
+ else
+ {
+ hasMoreData = false;
+ s = SocketOperation.Read;
+ }
+
+ if(((_state == StateClosingRequestPending && !_closingInitiator) ||
+ (_state == StateClosingResponsePending && _closingInitiator) ||
+ _state == StatePingPending ||
+ _state == StatePongPending) &&
+ _writeState == WriteStateHeader)
+ {
+ // We have things to write, ask to be notified when writes are ready.
+ s |= SocketOperation.Write;
+ }
+
+ return s;
+ }
+
+ public bool startRead(Buffer buf, AsyncCallback callback, object state)
+ {
+ _readPending = true;
+ if(_state < StateOpened)
+ {
+ _finishRead = true;
+ if(_state < StateConnected)
+ {
+ return _delegate.startRead(buf, callback, state);
+ }
+ else
+ {
+ return _delegate.startRead(_readBuffer, callback, state);
+ }
+ }
+
+ if(preRead(buf))
+ {
+ _finishRead = true;
+ if(_readState == ReadStatePayload)
+ {
+ //
+ // If the payload length is smaller than what remains to be read, we read
+ // no more than the payload length. The remaining of the buffer will be
+ // sent over in another frame.
+ //
+ int readSz = _readPayloadLength - (buf.b.position() - _readStart);
+ if(buf.b.remaining() > readSz)
+ {
+ int size = buf.size();
+ buf.resize(buf.b.position() + readSz, true);
+ bool completedSynchronously = _delegate.startRead(buf, callback, state);
+ buf.resize(size, true);
+ return completedSynchronously;
+ }
+ else
+ {
+ return _delegate.startRead(buf, callback, state);
+ }
+ }
+ else
+ {
+ return _delegate.startRead(_readBuffer, callback, state);
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ public void finishRead(Buffer buf)
+ {
+ Debug.Assert(_readPending);
+ _readPending = false;
+ if(_state < StateOpened)
+ {
+ Debug.Assert(_finishRead);
+ _finishRead = false;
+ if(_state < StateConnected)
+ {
+ _delegate.finishRead(buf);
+ }
+ else
+ {
+ _delegate.finishRead(_readBuffer);
+ }
+ return;
+ }
+
+ if(!_finishRead)
+ {
+ // Nothing to do.
+ }
+ else if(_readState == ReadStatePayload)
+ {
+ Debug.Assert(_finishRead);
+ _finishRead = false;
+ _delegate.finishRead(buf);
+ }
+ else
+ {
+ Debug.Assert(_finishRead);
+ _finishRead = false;
+ _delegate.finishRead(_readBuffer);
+ }
+ postRead(buf);
+ }
+
+ public bool startWrite(Buffer buf, AsyncCallback callback, object state,
+ out bool completed)
+ {
+ _writePending = true;
+ if(_state < StateOpened)
+ {
+ if(_state < StateConnected)
+ {
+ return _delegate.startWrite(buf, callback, state, out completed);
+ }
+ else
+ {
+ return _delegate.startWrite(_writeBuffer, callback, state, out completed);
+ }
+ }
+
+ if(preWrite(buf))
+ {
+ if(_writeBuffer.b.hasRemaining())
+ {
+ return _delegate.startWrite(_writeBuffer, callback, state, out completed);
+ }
+ else
+ {
+ Debug.Assert(_incoming);
+ return _delegate.startWrite(buf, callback, state, out completed);
+ }
+ }
+ else
+ {
+ completed = true;
+ return false;
+ }
+ }
+
+ public void finishWrite(Buffer buf)
+ {
+ _writePending = false;
+ if(_state < StateOpened)
+ {
+ if(_state < StateConnected)
+ {
+ _delegate.finishWrite(buf);
+ }
+ else
+ {
+ _delegate.finishWrite(_writeBuffer);
+ }
+ return;
+ }
+
+ if(_writeBuffer.b.hasRemaining())
+ {
+ _delegate.finishWrite(_writeBuffer);
+ }
+ else if(!buf.empty() && buf.b.hasRemaining())
+ {
+ Debug.Assert(_incoming);
+ _delegate.finishWrite(buf);
+ }
+
+ postWrite(buf, SocketOperation.None);
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public Ice.ConnectionInfo getInfo()
+ {
+ Ice.IPConnectionInfo di = (Ice.IPConnectionInfo)_delegate.getInfo();
+ Ice.WSConnectionInfo info = new Ice.WSConnectionInfo();
+ info.localAddress = di.localAddress;
+ info.localPort = di.localPort;
+ info.remoteAddress = di.remoteAddress;
+ info.remotePort = di.remotePort;
+ info.rcvSize = di.rcvSize;
+ info.sndSize = di.sndSize;
+ info.headers = _parser.getHeaders();
+ return info;
+ }
+
+ public void checkSendSize(Buffer buf)
+ {
+ _delegate.checkSendSize(buf);
+ }
+
+ public void setBufferSize(int rcvSize, int sndSize)
+ {
+ _delegate.setBufferSize(rcvSize, sndSize);
+ }
+
+ public override string ToString()
+ {
+ return _delegate.ToString();
+ }
+
+ public string toDetailedString()
+ {
+ return _delegate.toDetailedString();
+ }
+
+ internal
+ WSTransceiver(ProtocolInstance instance, Transceiver del, string host, int port, string resource)
+ {
+ init(instance, del);
+ _host = host;
+ _port = port;
+ _resource = resource;
+ _incoming = false;
+
+ //
+ // Use a 16KB write buffer size. We use 16KB for the write
+ // buffer size because all the data needs to be copied to the
+ // write buffer for the purpose of masking. A 16KB buffer
+ // appears to be a good compromise to reduce the number of
+ // socket write calls and not consume too much memory.
+ //
+ _writeBufferSize = 16 * 1024;
+
+ //
+ // Write and read buffer size must be large enough to hold the frame header!
+ //
+ Debug.Assert(_writeBufferSize > 256);
+ Debug.Assert(_readBufferSize > 256);
+ }
+
+ internal WSTransceiver(ProtocolInstance instance, Transceiver del)
+ {
+ init(instance, del);
+ _host = "";
+ _port = -1;
+ _resource = "";
+ _incoming = true;
+
+ //
+ // Write and read buffer size must be large enough to hold the frame header!
+ //
+ Debug.Assert(_writeBufferSize > 256);
+ Debug.Assert(_readBufferSize > 256);
+ }
+
+ private void init(ProtocolInstance instance, Transceiver del)
+ {
+ _instance = instance;
+ _delegate = del;
+ _state = StateInitializeDelegate;
+ _parser = new HttpParser();
+ _readState = ReadStateOpcode;
+ _readBuffer = new Buffer(ByteBuffer.ByteOrder.BIG_ENDIAN); // Network byte order
+ _readBufferSize = 1024;
+ _readLastFrame = true;
+ _readOpCode = 0;
+ _readHeaderLength = 0;
+ _readPayloadLength = 0;
+ _writeState = WriteStateHeader;
+ _writeBuffer = new Buffer(ByteBuffer.ByteOrder.BIG_ENDIAN); // Network byte order
+ _writeBufferSize = 1024;
+ _readPending = false;
+ _finishRead = false;
+ _writePending = false;
+ _readMask = new byte[4];
+ _writeMask = new byte[4];
+ _key = "";
+ _pingPayload = new byte[0];
+ _rand = new Random();
+ }
+
+ private void handleRequest(Buffer responseBuffer)
+ {
+ //
+ // HTTP/1.1
+ //
+ if(_parser.versionMajor() != 1 || _parser.versionMinor() != 1)
+ {
+ throw new WebSocketException("unsupported HTTP version");
+ }
+
+ //
+ // "An |Upgrade| header field containing the value 'websocket',
+ // treated as an ASCII case-insensitive value."
+ //
+ string val = _parser.getHeader("Upgrade", true);
+ if(val == null)
+ {
+ throw new WebSocketException("missing value for Upgrade field");
+ }
+ else if(!val.Equals("websocket"))
+ {
+ throw new WebSocketException("invalid value `" + val + "' for Upgrade field");
+ }
+
+ //
+ // "A |Connection| header field that includes the token 'Upgrade',
+ // treated as an ASCII case-insensitive value.
+ //
+ val = _parser.getHeader("Connection", true);
+ if(val == null)
+ {
+ throw new WebSocketException("missing value for Connection field");
+ }
+ else if(val.IndexOf("upgrade") == -1)
+ {
+ throw new WebSocketException("invalid value `" + val + "' for Connection field");
+ }
+
+ //
+ // "A |Sec-WebSocket-Version| header field, with a value of 13."
+ //
+ val = _parser.getHeader("Sec-WebSocket-Version", false);
+ if(val == null)
+ {
+ throw new WebSocketException("missing value for WebSocket version");
+ }
+ else if(!val.Equals("13"))
+ {
+ throw new WebSocketException("unsupported WebSocket version `" + val + "'");
+ }
+
+ //
+ // "Optionally, a |Sec-WebSocket-Protocol| header field, with a list
+ // of values indicating which protocols the client would like to
+ // speak, ordered by preference."
+ //
+ bool addProtocol = false;
+ val = _parser.getHeader("Sec-WebSocket-Protocol", true);
+ if(val != null)
+ {
+ string[] protocols = IceUtilInternal.StringUtil.splitString(val, ",");
+ if(protocols == null)
+ {
+ throw new WebSocketException("invalid value `" + val + "' for WebSocket protocol");
+ }
+ foreach(string p in protocols)
+ {
+ if(!p.Trim().Equals(_iceProtocol))
+ {
+ throw new WebSocketException("unknown value `" + p + "' for WebSocket protocol");
+ }
+ addProtocol = true;
+ }
+ }
+
+ //
+ // "A |Sec-WebSocket-Key| header field with a base64-encoded
+ // value that, when decoded, is 16 bytes in length."
+ //
+ string key = _parser.getHeader("Sec-WebSocket-Key", false);
+ if(key == null)
+ {
+ throw new WebSocketException("missing value for WebSocket key");
+ }
+
+ byte[] decodedKey = IceUtilInternal.Base64.decode(key);
+ if(decodedKey.Length != 16)
+ {
+ throw new WebSocketException("invalid value `" + key + "' for WebSocket key");
+ }
+
+ //
+ // Retain the target resource.
+ //
+ _resource = _parser.uri();
+
+ //
+ // Compose the response.
+ //
+ StringBuilder @out = new StringBuilder();
+ @out.Append("HTTP/1.1 101 Switching Protocols\r\n");
+ @out.Append("Upgrade: websocket\r\n");
+ @out.Append("Connection: Upgrade\r\n");
+ if(addProtocol)
+ {
+ @out.Append("Sec-WebSocket-Protocol: " + _iceProtocol + "\r\n");
+ }
+
+ //
+ // The response includes:
+ //
+ // "A |Sec-WebSocket-Accept| header field. The value of this
+ // header field is constructed by concatenating /key/, defined
+ // above in step 4 in Section 4.2.2, with the string "258EAFA5-
+ // E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this
+ // concatenated value to obtain a 20-byte value and base64-
+ // encoding (see Section 4 of [RFC4648]) this 20-byte hash.
+ //
+ @out.Append("Sec-WebSocket-Accept: ");
+ string input = key + _wsUUID;
+#if SILVERLIGHT
+ SHA1Managed sha1 = new SHA1Managed();
+ byte[] hash = sha1.ComputeHash(_utf8.GetBytes(input));
+#else
+ byte[] hash = SHA1.Create().ComputeHash(_utf8.GetBytes(input));
+#endif
+ @out.Append(IceUtilInternal.Base64.encode(hash) + "\r\n" + "\r\n"); // EOM
+
+ byte[] bytes = _utf8.GetBytes(@out.ToString());
+ Debug.Assert(bytes.Length == @out.Length);
+ responseBuffer.resize(bytes.Length, false);
+ responseBuffer.b.position(0);
+ responseBuffer.b.put(bytes);
+ responseBuffer.b.flip();
+ }
+
+ private void handleResponse()
+ {
+ string val;
+
+ //
+ // HTTP/1.1
+ //
+ if(_parser.versionMajor() != 1 || _parser.versionMinor() != 1)
+ {
+ throw new WebSocketException("unsupported HTTP version");
+ }
+
+ //
+ // "If the status code received from the server is not 101, the
+ // client handles the response per HTTP [RFC2616] procedures. In
+ // particular, the client might perform authentication if it
+ // receives a 401 status code; the server might redirect the client
+ // using a 3xx status code (but clients are not required to follow
+ // them), etc."
+ //
+ if(_parser.status() != 101)
+ {
+ StringBuilder @out = new StringBuilder("unexpected status value " + _parser.status());
+ if(_parser.reason().Length > 0)
+ {
+ @out.Append(":\n" + _parser.reason());
+ }
+ throw new WebSocketException(@out.ToString());
+ }
+
+ //
+ // "If the response lacks an |Upgrade| header field or the |Upgrade|
+ // header field contains a value that is not an ASCII case-
+ // insensitive match for the value "websocket", the client MUST
+ // _Fail the WebSocket Connection_."
+ //
+ val = _parser.getHeader("Upgrade", true);
+ if(val == null)
+ {
+ throw new WebSocketException("missing value for Upgrade field");
+ }
+ else if(!val.Equals("websocket"))
+ {
+ throw new WebSocketException("invalid value `" + val + "' for Upgrade field");
+ }
+
+ //
+ // "If the response lacks a |Connection| header field or the
+ // |Connection| header field doesn't contain a token that is an
+ // ASCII case-insensitive match for the value "Upgrade", the client
+ // MUST _Fail the WebSocket Connection_."
+ //
+ val = _parser.getHeader("Connection", true);
+ if(val == null)
+ {
+ throw new WebSocketException("missing value for Connection field");
+ }
+ else if(val.IndexOf("upgrade") == -1)
+ {
+ throw new WebSocketException("invalid value `" + val + "' for Connection field");
+ }
+
+ //
+ // "If the response includes a |Sec-WebSocket-Protocol| header field
+ // and this header field indicates the use of a subprotocol that was
+ // not present in the client's handshake (the server has indicated a
+ // subprotocol not requested by the client), the client MUST _Fail
+ // the WebSocket Connection_."
+ //
+ val = _parser.getHeader("Sec-WebSocket-Protocol", true);
+ if(val != null && !val.Equals(_iceProtocol))
+ {
+ throw new WebSocketException("invalid value `" + val + "' for WebSocket protocol");
+ }
+
+ //
+ // "If the response lacks a |Sec-WebSocket-Accept| header field or
+ // the |Sec-WebSocket-Accept| contains a value other than the
+ // base64-encoded SHA-1 of the concatenation of the |Sec-WebSocket-
+ // Key| (as a string, not base64-decoded) with the string "258EAFA5-
+ // E914-47DA-95CA-C5AB0DC85B11" but ignoring any leading and
+ // trailing whitespace, the client MUST _Fail the WebSocket
+ // Connection_."
+ //
+ val = _parser.getHeader("Sec-WebSocket-Accept", false);
+ if(val == null)
+ {
+ throw new WebSocketException("missing value for Sec-WebSocket-Accept");
+ }
+
+ string input = _key + _wsUUID;
+#if SILVERLIGHT
+ SHA1Managed sha1 = new SHA1Managed();
+ byte[] hash = sha1.ComputeHash(_utf8.GetBytes(input));
+#else
+ byte[] hash = SHA1.Create().ComputeHash(_utf8.GetBytes(input));
+#endif
+ if(!val.Equals(IceUtilInternal.Base64.encode(hash)))
+ {
+ throw new WebSocketException("invalid value `" + val + "' for Sec-WebSocket-Accept");
+ }
+ }
+
+ private bool preRead(Buffer buf)
+ {
+ while(true)
+ {
+ if(_readState == ReadStateOpcode)
+ {
+ //
+ // Is there enough data available to read the opcode?
+ //
+ if(!readBuffered(2))
+ {
+ return true;
+ }
+
+ //
+ // Most-significant bit indicates whether this is the
+ // last frame. Least-significant four bits hold the
+ // opcode.
+ //
+ int ch = _readBuffer.b.get(_readBufferPos++);
+ _readOpCode = ch & 0xf;
+
+ //
+ // Remember if last frame if we're going to read a data or
+ // continuation frame, this is only for protocol
+ // correctness checking purpose.
+ //
+ if(_readOpCode == OP_DATA)
+ {
+ if(!_readLastFrame)
+ {
+ throw new Ice.ProtocolException("invalid data frame, no FIN on previous frame");
+ }
+ _readLastFrame = (ch & FLAG_FINAL) == FLAG_FINAL;
+ }
+ else if(_readOpCode == OP_CONT)
+ {
+ if(_readLastFrame)
+ {
+ throw new Ice.ProtocolException("invalid continuation frame, previous frame FIN set");
+ }
+ _readLastFrame = (ch & FLAG_FINAL) == FLAG_FINAL;
+ }
+
+ ch = _readBuffer.b.get(_readBufferPos++);
+
+ //
+ // Check the MASK bit. Messages sent by a client must be masked;
+ // messages sent by a server must not be masked.
+ //
+ bool masked = (ch & FLAG_MASKED) == FLAG_MASKED;
+ if(masked != _incoming)
+ {
+ throw new Ice.ProtocolException("invalid masking");
+ }
+
+ //
+ // Extract the payload length, which can have the following values:
+ //
+ // 0-125: The payload length
+ // 126: The subsequent two bytes contain the payload length
+ // 127: The subsequent eight bytes contain the payload length
+ //
+ _readPayloadLength = (ch & 0x7f);
+ if(_readPayloadLength < 126)
+ {
+ _readHeaderLength = 0;
+ }
+ else if(_readPayloadLength == 126)
+ {
+ _readHeaderLength = 2; // Need to read a 16-bit payload length.
+ }
+ else
+ {
+ _readHeaderLength = 8; // Need to read a 64-bit payload length.
+ }
+ if(masked)
+ {
+ _readHeaderLength += 4; // Need to read a 32-bit mask.
+ }
+
+ _readState = ReadStateHeader;
+ }
+
+ if(_readState == ReadStateHeader)
+ {
+ //
+ // Is there enough data available to read the header?
+ //
+ if(_readHeaderLength > 0 && !readBuffered(_readHeaderLength))
+ {
+ return true;
+ }
+
+ if(_readPayloadLength == 126)
+ {
+ _readPayloadLength = _readBuffer.b.getShort(_readBufferPos); // Uses network byte order.
+ if(_readPayloadLength < 0)
+ {
+ _readPayloadLength += 65536;
+ }
+ _readBufferPos += 2;
+ }
+ else if(_readPayloadLength == 127)
+ {
+ long l = _readBuffer.b.getLong(_readBufferPos); // Uses network byte order.
+ _readBufferPos += 8;
+ if(l < 0 || l > Int32.MaxValue)
+ {
+ throw new Ice.ProtocolException("invalid WebSocket payload length: " + l);
+ }
+ _readPayloadLength = (int)l;
+ }
+
+ //
+ // Read the mask if this is an incoming connection.
+ //
+ if(_incoming)
+ {
+ //
+ // We must have needed to read the mask.
+ //
+ Debug.Assert(_readBuffer.b.position() - _readBufferPos >= 4);
+ for(int i = 0; i < 4; ++i)
+ {
+ _readMask[i] = _readBuffer.b.get(_readBufferPos++); // Copy the mask.
+ }
+ }
+
+ switch(_readOpCode)
+ {
+ case OP_TEXT: // Text frame
+ {
+ throw new Ice.ProtocolException("text frames not supported");
+ }
+ case OP_DATA: // Data frame
+ case OP_CONT: // Continuation frame
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(), "received " + protocol() +
+ (_readOpCode == OP_DATA ? " data" : " continuation") +
+ " frame with payload length of " + _readPayloadLength +
+ " bytes\n" + ToString());
+ }
+
+ if(_readPayloadLength <= 0)
+ {
+ throw new Ice.ProtocolException("payload length is 0");
+ }
+ _readState = ReadStatePayload;
+ Debug.Assert(buf.b.hasRemaining());
+ _readFrameStart = buf.b.position();
+ break;
+ }
+ case OP_CLOSE: // Connection close
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "received " + protocol() + " connection close frame\n" + ToString());
+ }
+
+ _readState = ReadStateControlFrame;
+ int s = _nextState == StateOpened ? _state : _nextState;
+ if(s == StateClosingRequestPending)
+ {
+ //
+ // If we receive a close frame while we were actually
+ // waiting to send one, change the role and send a
+ // close frame response.
+ //
+ if(!_closingInitiator)
+ {
+ _closingInitiator = true;
+ }
+ if(_state == StateClosingRequestPending)
+ {
+ _state = StateClosingResponsePending;
+ }
+ else
+ {
+ _nextState = StateClosingResponsePending;
+ }
+ return false; // No longer interested in reading
+ }
+ else
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ }
+ case OP_PING:
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "received " + protocol() + " connection ping frame\n" + ToString());
+ }
+ _readState = ReadStateControlFrame;
+ break;
+ }
+ case OP_PONG: // Pong
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "received " + protocol() + " connection pong frame\n" + ToString());
+ }
+ _readState = ReadStateControlFrame;
+ break;
+ }
+ default:
+ {
+ throw new Ice.ProtocolException("unsupported opcode: " + _readOpCode);
+ }
+ }
+ }
+
+ if(_readState == ReadStateControlFrame)
+ {
+ if(_readPayloadLength > 0 && !readBuffered(_readPayloadLength))
+ {
+ return true;
+ }
+
+ if(_readPayloadLength > 0 && _readOpCode == OP_PING)
+ {
+ _pingPayload = new byte[_readPayloadLength];
+ System.Buffer.BlockCopy(_readBuffer.b.rawBytes(), _readBufferPos, _pingPayload, 0,
+ _readPayloadLength);
+ }
+
+ _readBufferPos += _readPayloadLength;
+ _readPayloadLength = 0;
+
+ if(_readOpCode == OP_PING)
+ {
+ if(_state == StateOpened)
+ {
+ _state = StatePongPending; // Send pong frame now
+ }
+ else if(_nextState < StatePongPending)
+ {
+ _nextState = StatePongPending; // Send pong frame next
+ }
+ }
+
+ //
+ // We've read the payload of the PING/PONG frame, we're ready
+ // to read a new frame.
+ //
+ _readState = ReadStateOpcode;
+ }
+
+ if(_readState == ReadStatePayload)
+ {
+ //
+ // This must be assigned before the check for the buffer. If the buffer is empty
+ // or already read, postRead will return false.
+ //
+ _readStart = buf.b.position();
+
+ if(buf.empty() || !buf.b.hasRemaining())
+ {
+ return false;
+ }
+
+ if(_readBufferPos < _readBuffer.b.position())
+ {
+ int n = Math.Min(_readBuffer.b.position() - _readBufferPos, buf.b.remaining());
+ System.Buffer.BlockCopy(_readBuffer.b.rawBytes(), _readBufferPos, buf.b.rawBytes(),
+ buf.b.position(), n);
+ buf.b.position(buf.b.position() + n);
+ _readBufferPos += n;
+ }
+
+ //
+ // Continue reading if we didn't read the full message, otherwise give back
+ // the control to the connection
+ //
+ return buf.b.hasRemaining();
+ }
+ }
+ }
+
+ private bool postRead(Buffer buf)
+ {
+ if(_readState != ReadStatePayload)
+ {
+ return _readStart < _readBuffer.b.position(); // Returns true if data was read.
+ }
+
+ if(_readStart == buf.b.position())
+ {
+ return false; // Nothing was read or nothing to read.
+ }
+ Debug.Assert(_readStart < buf.b.position());
+
+ if(_incoming)
+ {
+ //
+ // Unmask the data we just read.
+ //
+ int pos = buf.b.position();
+ byte[] arr = buf.b.rawBytes();
+ for(int n = _readStart; n < pos; ++n)
+ {
+ arr[n] = (byte)(arr[n] ^ _readMask[(n - _readFrameStart) % 4]);
+ }
+ }
+
+ _readPayloadLength -= buf.b.position() - _readStart;
+ _readStart = buf.b.position();
+ if(_readPayloadLength == 0)
+ {
+ //
+ // We've read the complete payload, we're ready to read a new frame.
+ //
+ _readState = ReadStateOpcode;
+ }
+ return buf.b.hasRemaining();
+ }
+
+ private bool preWrite(Buffer buf)
+ {
+ if(_writeState == WriteStateHeader)
+ {
+ if(_state == StateOpened)
+ {
+ if(buf.empty() || !buf.b.hasRemaining())
+ {
+ return false;
+ }
+
+ Debug.Assert(buf.b.position() == 0);
+ prepareWriteHeader((byte)OP_DATA, buf.size());
+
+ _writeState = WriteStatePayload;
+ }
+ else if(_state == StatePingPending)
+ {
+ prepareWriteHeader((byte)OP_PING, 0); // Don't send any payload
+
+ _writeState = WriteStateControlFrame;
+ _writeBuffer.b.flip();
+ }
+ else if(_state == StatePongPending)
+ {
+ prepareWriteHeader((byte)OP_PONG, _pingPayload.Length);
+ if(_pingPayload.Length > _writeBuffer.b.remaining())
+ {
+ int pos = _writeBuffer.b.position();
+ _writeBuffer.resize(pos + _pingPayload.Length, false);
+ _writeBuffer.b.position(pos);
+ }
+ _writeBuffer.b.put(_pingPayload);
+ _pingPayload = new byte[0];
+
+ _writeState = WriteStateControlFrame;
+ _writeBuffer.b.flip();
+ }
+ else if((_state == StateClosingRequestPending && !_closingInitiator) ||
+ (_state == StateClosingResponsePending && _closingInitiator))
+ {
+ prepareWriteHeader((byte)OP_CLOSE, 2);
+
+ // Write closing reason
+ _writeBuffer.b.putShort((short)_closingReason);
+
+ if(!_incoming)
+ {
+ byte b;
+ int pos = _writeBuffer.b.position() - 2;
+ b = (byte)(_writeBuffer.b.get(pos) ^ _writeMask[0]);
+ _writeBuffer.b.put(pos, b);
+ pos++;
+ b = (byte)(_writeBuffer.b.get(pos) ^ _writeMask[1]);
+ _writeBuffer.b.put(pos, b);
+ }
+
+ _writeState = WriteStateControlFrame;
+ _writeBuffer.b.flip();
+ }
+ else
+ {
+ Debug.Assert(_state != StateClosed);
+ return false; // Nothing to write in this state
+ }
+
+ _writePayloadLength = 0;
+ }
+
+ if(_writeState == WriteStatePayload)
+ {
+ //
+ // For an outgoing connection, each message must be masked with a random
+ // 32-bit value, so we copy the entire message into the internal buffer
+ // for writing. For incoming connections, we just copy the start of the
+ // message in the internal buffer after the hedaer. If the message is
+ // larger, the reminder is sent directly from the message buffer to avoid
+ // copying.
+ //
+ if(!_incoming && (_writePayloadLength == 0 || !_writeBuffer.b.hasRemaining()))
+ {
+ if(!_writeBuffer.b.hasRemaining())
+ {
+ _writeBuffer.b.position(0);
+ }
+
+ int n = buf.b.position();
+ int sz = buf.size();
+ int pos = _writeBuffer.b.position();
+ int count = Math.Min(sz - n, _writeBuffer.b.remaining());
+ byte[] src = buf.b.rawBytes();
+ byte[] dest = _writeBuffer.b.rawBytes();
+ for(int i = 0; i < count; ++i, ++n, ++pos)
+ {
+ dest[pos] = (byte)(src[n] ^ _writeMask[n % 4]);
+ }
+ _writeBuffer.b.position(pos);
+ _writePayloadLength = n;
+
+ _writeBuffer.b.flip();
+ }
+ else if(_writePayloadLength == 0)
+ {
+ Debug.Assert(_incoming);
+ if(_writeBuffer.b.hasRemaining())
+ {
+ Debug.Assert(buf.b.position() == 0);
+ int n = Math.Min(_writeBuffer.b.remaining(), buf.b.remaining());
+ int pos = _writeBuffer.b.position();
+ System.Buffer.BlockCopy(buf.b.rawBytes(), 0, _writeBuffer.b.rawBytes(), pos, n);
+ _writeBuffer.b.position(pos + n);
+ _writePayloadLength = n;
+ }
+ _writeBuffer.b.flip();
+ }
+ return true;
+ }
+ else if(_writeState == WriteStateControlFrame)
+ {
+ return _writeBuffer.b.hasRemaining();
+ }
+ else
+ {
+ Debug.Assert(_writeState == WriteStateFlush);
+ return true;
+ }
+ }
+
+ private bool postWrite(Buffer buf, int status)
+ {
+ if(_state > StateOpened && _writeState == WriteStateControlFrame)
+ {
+ if(!_writeBuffer.b.hasRemaining())
+ {
+ if(_state == StatePingPending)
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "sent " + protocol() + " connection ping frame\n" + ToString());
+ }
+ }
+ else if(_state == StatePongPending)
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "sent " + protocol() + " connection pong frame\n" + ToString());
+ }
+ }
+ else if((_state == StateClosingRequestPending && !_closingInitiator) ||
+ (_state == StateClosingResponsePending && _closingInitiator))
+ {
+ if(_instance.traceLevel() >= 2)
+ {
+ _instance.logger().trace(_instance.traceCategory(),
+ "sent " + protocol() + " connection close frame\n" + ToString());
+ }
+
+ if(_state == StateClosingRequestPending && !_closingInitiator)
+ {
+ _writeState = WriteStateHeader;
+ _state = StateClosingResponsePending;
+ return false;
+ }
+ else
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ }
+ else if(_state == StateClosed)
+ {
+ return false;
+ }
+
+ _state = _nextState;
+ _nextState = StateOpened;
+ _writeState = WriteStateHeader;
+ }
+ else
+ {
+ return status == SocketOperation.None;
+ }
+ }
+
+ if((!_incoming || buf.b.position() == 0) && _writePayloadLength > 0)
+ {
+ if(!_writeBuffer.b.hasRemaining())
+ {
+ buf.b.position(_writePayloadLength);
+ }
+ }
+
+ if(status == SocketOperation.Write && !buf.b.hasRemaining() && !_writeBuffer.b.hasRemaining())
+ {
+ //
+ // Our buffers are empty but the delegate needs another call to write().
+ //
+ _writeState = WriteStateFlush;
+ return false;
+ }
+ else if(!buf.b.hasRemaining())
+ {
+ _writeState = WriteStateHeader;
+ if(_state == StatePingPending ||
+ _state == StatePongPending ||
+ (_state == StateClosingRequestPending && !_closingInitiator) ||
+ (_state == StateClosingResponsePending && _closingInitiator))
+ {
+ return true;
+ }
+ }
+ else if(_state == StateOpened)
+ {
+ return status == SocketOperation.None;
+ }
+
+ return false;
+ }
+
+ private bool readBuffered(int sz)
+ {
+ if(_readBufferPos == _readBuffer.b.position())
+ {
+ _readBuffer.resize(_readBufferSize, true);
+ _readBufferPos = 0;
+ _readBuffer.b.position(0);
+ }
+ else
+ {
+ int available = _readBuffer.b.position() - _readBufferPos;
+ if(available < sz)
+ {
+ if(_readBufferPos > 0)
+ {
+ _readBuffer.b.limit(_readBuffer.b.position());
+ _readBuffer.b.position(_readBufferPos);
+ _readBuffer.b.compact();
+ Debug.Assert(_readBuffer.b.position() == available);
+ }
+ _readBuffer.resize(Math.Max(_readBufferSize, sz), true);
+ _readBufferPos = 0;
+ _readBuffer.b.position(available);
+ }
+ }
+
+ _readStart = _readBuffer.b.position();
+ if(_readBufferPos + sz > _readBuffer.b.position())
+ {
+ return false; // Not enough read.
+ }
+ Debug.Assert(_readBuffer.b.position() > _readBufferPos);
+ return true;
+ }
+
+ private void prepareWriteHeader(byte opCode, int payloadLength)
+ {
+ //
+ // We need to prepare the frame header.
+ //
+ _writeBuffer.resize(_writeBufferSize, false);
+ _writeBuffer.b.limit(_writeBufferSize);
+ _writeBuffer.b.position(0);
+
+ //
+ // Set the opcode - this is the one and only data frame.
+ //
+ _writeBuffer.b.put((byte)(opCode | FLAG_FINAL));
+
+ //
+ // Set the payload length.
+ //
+ if(payloadLength <= 125)
+ {
+ _writeBuffer.b.put((byte)payloadLength);
+ }
+ else if(payloadLength > 125 && payloadLength <= 65535)
+ {
+ //
+ // Use an extra 16 bits to encode the payload length.
+ //
+ _writeBuffer.b.put((byte)126);
+ _writeBuffer.b.putShort((short)payloadLength);
+ }
+ else if(payloadLength > 65535)
+ {
+ //
+ // Use an extra 64 bits to encode the payload length.
+ //
+ _writeBuffer.b.put((byte)127);
+ _writeBuffer.b.putLong(payloadLength);
+ }
+
+ if(!_incoming)
+ {
+ //
+ // Add a random 32-bit mask to every outgoing frame, copy the payload data,
+ // and apply the mask.
+ //
+ _writeBuffer.b.put(1, (byte)(_writeBuffer.b.get(1) | FLAG_MASKED));
+ _rand.NextBytes(_writeMask);
+ _writeBuffer.b.put(_writeMask);
+ }
+ }
+
+ private ProtocolInstance _instance;
+ private Transceiver _delegate;
+ private string _host;
+ private int _port;
+ private string _resource;
+ private bool _incoming;
+
+ private const int StateInitializeDelegate = 0;
+ private const int StateConnected = 1;
+ private const int StateUpgradeRequestPending = 2;
+ private const int StateUpgradeResponsePending = 3;
+ private const int StateOpened = 4;
+ private const int StatePingPending = 5;
+ private const int StatePongPending = 6;
+ private const int StateClosingRequestPending = 7;
+ private const int StateClosingResponsePending = 8;
+ private const int StateClosed = 9;
+
+ private int _state;
+ private int _nextState;
+
+ private HttpParser _parser;
+ private string _key;
+
+ private const int ReadStateOpcode = 0;
+ private const int ReadStateHeader = 1;
+ private const int ReadStateControlFrame = 2;
+ private const int ReadStatePayload = 3;
+
+ private int _readState;
+ private Buffer _readBuffer;
+ private int _readBufferPos;
+ private int _readBufferSize;
+
+ private bool _readLastFrame;
+ private int _readOpCode;
+ private int _readHeaderLength;
+ private int _readPayloadLength;
+ private int _readStart;
+ private int _readFrameStart;
+ private byte[] _readMask;
+
+ private const int WriteStateHeader = 0;
+ private const int WriteStatePayload = 1;
+ private const int WriteStateControlFrame = 2;
+ private const int WriteStateFlush = 3;
+
+ private int _writeState;
+ private Buffer _writeBuffer;
+ private int _writeBufferSize;
+ private byte[] _writeMask;
+ private int _writePayloadLength;
+
+ private bool _closingInitiator;
+ private int _closingReason;
+
+ private bool _readPending;
+ private bool _finishRead;
+ private bool _writePending;
+
+ private byte[] _pingPayload;
+
+ private Random _rand;
+
+ //
+ // WebSocket opcodes
+ //
+ private const int OP_CONT = 0x0; // Continuation frame
+ private const int OP_TEXT = 0x1; // Text frame
+ private const int OP_DATA = 0x2; // Data frame
+ private const int OP_RES_0x3 = 0x3; // Reserved
+ private const int OP_RES_0x4 = 0x4; // Reserved
+ private const int OP_RES_0x5 = 0x5; // Reserved
+ private const int OP_RES_0x6 = 0x6; // Reserved
+ private const int OP_RES_0x7 = 0x7; // Reserved
+ private const int OP_CLOSE = 0x8; // Connection close
+ private const int OP_PING = 0x9; // Ping
+ private const int OP_PONG = 0xA; // Pong
+ private const int OP_RES_0xB = 0xB; // Reserved
+ private const int OP_RES_0xC = 0xC; // Reserved
+ private const int OP_RES_0xD = 0xD; // Reserved
+ private const int OP_RES_0xE = 0xE; // Reserved
+ private const int OP_RES_0xF = 0xF; // Reserved
+ private const int FLAG_FINAL = 0x80; // Last frame
+ private const int FLAG_MASKED = 0x80; // Payload is masked
+
+ private const int CLOSURE_NORMAL = 1000;
+ private const int CLOSURE_SHUTDOWN = 1001;
+ private const int CLOSURE_PROTOCOL_ERROR = 1002;
+ private const int CLOSURE_TOO_BIG = 1009;
+
+ private const string _iceProtocol = "ice.zeroc.com";
+ private const string _wsUUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+ private static System.Text.UTF8Encoding _utf8 = new System.Text.UTF8Encoding(false, true);
+ }
+}
diff --git a/csharp/src/Ice/generated/.gitignore b/csharp/src/Ice/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/Ice/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/IceBox/.depend.mak b/csharp/src/IceBox/.depend.mak
new file mode 100644
index 00000000000..bf680c6be59
--- /dev/null
+++ b/csharp/src/IceBox/.depend.mak
@@ -0,0 +1,7 @@
+
+IceBox.cs: \
+ "$(slicedir)\IceBox\IceBox.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/CommunicatorF.ice" \
+ "$(slicedir)/Ice/PropertiesF.ice" \
+ "$(slicedir)/Ice/SliceChecksumDict.ice"
diff --git a/csharp/src/IceBox/AssemblyInfo.cs b/csharp/src/IceBox/AssemblyInfo.cs
new file mode 100644
index 00000000000..8c3d6231872
--- /dev/null
+++ b/csharp/src/IceBox/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IceBox")]
+[assembly: AssemblyDescription("IceBox run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IceBox for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IceBox/AssemblyInfoExe.cs b/csharp/src/IceBox/AssemblyInfoExe.cs
new file mode 100644
index 00000000000..2cf942e95f3
--- /dev/null
+++ b/csharp/src/IceBox/AssemblyInfoExe.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IceBox")]
+[assembly: AssemblyDescription("IceBox")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IceBox for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IceBox/Makefile b/csharp/src/IceBox/Makefile
new file mode 100644
index 00000000000..23413be5626
--- /dev/null
+++ b/csharp/src/IceBox/Makefile
@@ -0,0 +1,58 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = IceBox
+LIBNAME = $(PKG).dll
+ICEBOXNET = $(bindir)/iceboxnet.exe
+TARGETS = $(ICEBOXNET) $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+L_SRCS = AssemblyInfo.cs
+I_SRCS = AssemblyInfoExe.cs Server.cs ServiceManagerI.cs
+
+SLICE_SRCS = $(SDIR)/IceBox.ice
+
+SDIR = $(slicedir)/IceBox
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+EXE_MCSFLAGS := $(MCSFLAGS) -target:exe
+
+LIB_MCSFLAGS := $(MCSFLAGS) -target:library -out:$(assembliesdir)/$(LIBNAME)
+LIB_MCSFLAGS := $(LIB_MCSFLAGS) -keyfile:$(KEYFILE)
+LIB_MCSFLAGS := $(LIB_MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) --checksum --ice -I. -I$(slicedir)
+
+$(ICEBOXNET): $(I_SRCS) $(assembliesdir)/$(LIBNAME)
+ $(MCS) $(EXE_MCSFLAGS) -out:$@ $(call ref,$(PKG)) $(call ref,Ice) $(I_SRCS)
+
+$(assembliesdir)/$(LIBNAME): $(L_SRCS) $(GEN_SRCS)
+ $(MCS) $(LIB_MCSFLAGS) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+install:: all
+ $(call installprogram,$(ICEBOXNET),$(DESTDIR)$(install_bindir))
+ $(call installdata,$(top_srcdir)/../man/man1/iceboxnet.1,$(DESTDIR)$(install_mandir))
+ $(call installmdb,$(ICEBOXNET).mdb)
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/IceBox/Makefile.mak b/csharp/src/IceBox/Makefile.mak
new file mode 100644
index 00000000000..6633c7bdbf0
--- /dev/null
+++ b/csharp/src/IceBox/Makefile.mak
@@ -0,0 +1,117 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = IceBox
+LIBNAME = $(assembliesdir)\$(PKG).dll
+ICEBOXNET = $(bindir)\iceboxnet.exe
+TARGETS = $(LIBNAME) $(ICEBOXNET)
+POLICY_TARGET = $(POLICY).dll
+
+L_SRCS = AssemblyInfo.cs
+I_SRCS = AssemblyInfoExe.cs Server.cs ServiceManagerI.cs
+
+GEN_SRCS = $(GDIR)\IceBox.cs
+
+SDIR = $(slicedir)\IceBox
+GDIR = generated
+
+
+!include $(top_srcdir)/config/Make.rules.mak.cs
+
+all:: $(ICEBOXNET).config
+
+EXE_MCSFLAGS = $(MCSFLAGS) -target:exe
+
+LIB_MCSFLAGS = $(MCSFLAGS) -target:library -out:$(LIBNAME)
+LIB_MCSFLAGS = $(LIB_MCSFLAGS) -keyfile:"$(KEYFILE)"
+LIB_MCSFLAGS = $(LIB_MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) --checksum --ice -I. -I$(slicedir)
+
+$(ICEBOXNET): $(I_SRCS) $(LIBNAME)
+ $(MCS) $(EXE_MCSFLAGS) -out:$@ -r:$(LIBNAME) -r:$(refdir)\Ice.dll $(I_SRCS)
+
+$(LIBNAME): $(L_SRCS) $(GEN_SRCS)
+ $(MCS) /baseaddress:0x25000000 $(LIB_MCSFLAGS) -r:$(refdir)\Ice.dll $(L_SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+ del /q $(bindir)\iceboxnet.pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+!if "$(PUBLIC_KEY_TOKEN)" == ""
+$(ICEBOXNET).config:
+ @sn -q -T $(assembliesdir)\Ice.dll > tmp.publicKeyToken && \
+ set /P TMP_TOKEN= < tmp.publicKeyToken && \
+ cmd /c "set PUBLIC_KEY_TOKEN=%TMP_TOKEN:~-16% && \
+ del tmp.publicKeyToken && \
+ nmake /nologo /f Makefile.mak iceboxnetconfig"
+!endif
+
+publicKeyToken = $(PUBLIC_KEY_TOKEN: =)
+
+!if "$(COMPACT)" == "yes"
+assembliesRelativeDir = ..\..\Assemblies\cf
+!else
+assembliesRelativeDir = ..\Assemblies
+!endif
+
+iceboxnetconfig:
+ echo <<$(ICEBOXNET).config
+<?xml version="1.0"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="Ice" culture="neutral" publicKeyToken="$(publicKeyToken)"/>
+ <codeBase version="3.6.0.0" href="$(assembliesRelativeDir)\Ice.dll"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="IceBox" culture="neutral" publicKeyToken="$(publicKeyToken)"/>
+ <codeBase version="3.6.0.0" href="$(assembliesRelativeDir)\IceBox.dll"/>
+ </dependentAssembly>
+ <!--
+ This allows iceboxnet to load the IceSSL plug-in using a strong name. We omit the
+ optional attributes culture and publicKeyToken so they can be also omitted in the
+ IceSSL entry point.
+ -->
+ <dependentAssembly>
+ <assemblyIdentity name="IceSSL"/>
+ <codeBase version="3.6.0.0" href="$(assembliesRelativeDir)\IceSSL.dll"/>
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration>
+<<KEEP
+
+install:: all
+ copy $(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
+
+install:: all
+ copy $(ICEBOXNET) "$(install_bindir)"
+ copy $(ICEBOXNET).config "$(install_bindir)"
+!if "$(DEBUG)" == "yes"
+ copy $(bindir)\iceboxnet.pdb "$(install_bindir)"
+!endif
+
+clean::
+ del /q $(ICEBOXNET).config
diff --git a/csharp/src/IceBox/Server.cs b/csharp/src/IceBox/Server.cs
new file mode 100644
index 00000000000..bdd9d048bf5
--- /dev/null
+++ b/csharp/src/IceBox/Server.cs
@@ -0,0 +1,77 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections.Generic;
+
+namespace IceBox
+{
+
+public class Server
+{
+ public class App : Ice.Application
+ {
+ private static void usage()
+ {
+ Console.Error.WriteLine("Usage: iceboxnet [options] --Ice.Config=<file>\n");
+ Console.Error.WriteLine(
+ "Options:\n" +
+ "-h, --help Show this message.\n"
+ );
+ }
+
+ public override int run(string[] args)
+ {
+ List<String> argSeq = new List<String>(args);
+ const String prefix = "IceBox.Service.";
+ Ice.Properties properties = communicator().getProperties();
+ Dictionary<string, string> services = properties.getPropertiesForPrefix(prefix);
+ foreach(KeyValuePair<string, string> pair in services)
+ {
+ String name = pair.Key.Substring(prefix.Length);
+ for(int i = 0; i < argSeq.Count; ++i)
+ {
+ if(argSeq[i].StartsWith("--" + name, StringComparison.CurrentCulture))
+ {
+ argSeq.RemoveAt(i);
+ i--;
+ }
+ }
+ }
+
+ foreach(String s in argSeq)
+ {
+ if(s.Equals("-h") || s.Equals("--help"))
+ {
+ usage();
+ return 0;
+ }
+ else
+ {
+ Console.Error.WriteLine("Server: unknown option `" + s + "'");
+ usage();
+ return 1;
+ }
+ }
+
+ ServiceManagerI serviceManagerImpl = new ServiceManagerI(communicator(), args);
+ return serviceManagerImpl.run();
+ }
+ }
+
+ public static int Main(string[] args)
+ {
+ Ice.InitializationData initData = new Ice.InitializationData();
+ initData.properties = Ice.Util.createProperties();
+ initData.properties.setProperty("Ice.Admin.DelayCreation", "1");
+ App server = new App();
+ return server.main(args, initData);
+ }
+}
+}
diff --git a/csharp/src/IceBox/ServiceManagerI.cs b/csharp/src/IceBox/ServiceManagerI.cs
new file mode 100644
index 00000000000..658a0284b07
--- /dev/null
+++ b/csharp/src/IceBox/ServiceManagerI.cs
@@ -0,0 +1,1072 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using System.Diagnostics;
+
+namespace IceBox
+{
+
+//
+// NOTE: the class isn't final on purpose to allow users to eventually
+// extend it.
+//
+class ServiceManagerI : ServiceManagerDisp_
+{
+ public ServiceManagerI(Ice.Communicator communicator, string[] args)
+ {
+ _communicator = communicator;
+ _logger = _communicator.getLogger();
+
+ Ice.Properties props = _communicator.getProperties();
+
+ if(props.getProperty("Ice.Admin.Enabled").Length == 0)
+ {
+ _adminEnabled = props.getProperty("Ice.Admin.Endpoints").Length > 0;
+ }
+ else
+ {
+ _adminEnabled = props.getPropertyAsInt("Ice.Admin.Enabled") > 0;
+ }
+
+ if(_adminEnabled)
+ {
+ string[] facetFilter = props.getPropertyAsList("Ice.Admin.Facets");
+ if(facetFilter.Length > 0)
+ {
+ _adminFacetFilter = new HashSet<string>(facetFilter);
+ }
+ else
+ {
+ _adminFacetFilter = new HashSet<string>();
+ }
+ }
+
+ _argv = args;
+ _traceServiceObserver = _communicator.getProperties().getPropertyAsInt("IceBox.Trace.ServiceObserver");
+ }
+
+ public override Dictionary<string, string> getSliceChecksums(Ice.Current current)
+ {
+ return Ice.SliceChecksums.checksums;
+ }
+
+ public override void startService(string name, Ice.Current current)
+ {
+ ServiceInfo info = new ServiceInfo();
+ lock(this)
+ {
+ //
+ // Search would be more efficient if services were contained in
+ // a map, but order is required for shutdown.
+ //
+ int i;
+ for(i = 0; i < _services.Count; ++i)
+ {
+ info = _services[i];
+ if(info.name.Equals(name))
+ {
+ if(_services[i].status != ServiceStatus.Stopped)
+ {
+ throw new AlreadyStartedException();
+ }
+ info.status = ServiceStatus.Starting;
+ _services[i] = info;
+ break;
+ }
+ }
+ if(i == _services.Count)
+ {
+ throw new NoSuchServiceException();
+ }
+ _pendingStatusChanges = true;
+ }
+
+ bool started = false;
+ try
+ {
+ info.service.start(info.name, info.communicator == null ? _sharedCommunicator : info.communicator,
+ info.args);
+ started = true;
+ }
+ catch(Exception e)
+ {
+ _logger.warning("ServiceManager: exception while starting service " + info.name + ":\n" + e.ToString());
+ }
+
+ lock(this)
+ {
+ int i;
+ for(i = 0; i < _services.Count; ++i)
+ {
+ info = _services[i];
+ if(info.name.Equals(name))
+ {
+ if(started)
+ {
+ info.status = ServiceStatus.Started;
+
+ List<string> services = new List<string>();
+ services.Add(name);
+ servicesStarted(services, _observers.Keys);
+ }
+ else
+ {
+ info.status = ServiceStatus.Stopped;
+ }
+ _services[i] = info;
+ break;
+ }
+ }
+ _pendingStatusChanges = false;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public override void stopService(string name, Ice.Current current)
+ {
+ ServiceInfo info = new ServiceInfo();
+ lock(this)
+ {
+ //
+ // Search would be more efficient if services were contained in
+ // a map, but order is required for shutdown.
+ //
+ int i;
+ for(i = 0; i < _services.Count; ++i)
+ {
+ info = _services[i];
+ if(info.name.Equals(name))
+ {
+ if(info.status != ServiceStatus.Started)
+ {
+ throw new AlreadyStoppedException();
+ }
+ info.status = ServiceStatus.Stopping;
+ _services[i] = info;
+ break;
+ }
+ }
+ if(i == _services.Count)
+ {
+ throw new NoSuchServiceException();
+ }
+ _pendingStatusChanges = true;
+ }
+
+ bool stopped = false;
+ try
+ {
+ info.service.stop();
+ stopped = true;
+ }
+ catch(Exception e)
+ {
+ _logger.warning("ServiceManager: exception while stopping service " + info.name + "\n" + e.ToString());
+ }
+
+ lock(this)
+ {
+ int i;
+ for(i = 0; i < _services.Count; ++i)
+ {
+ info = _services[i];
+ if(info.name.Equals(name))
+ {
+ if(stopped)
+ {
+ info.status = ServiceStatus.Stopped;
+
+ List<string> services = new List<string>();
+ services.Add(name);
+ servicesStopped(services, _observers.Keys);
+ }
+ else
+ {
+ info.status = ServiceStatus.Started;
+ }
+ _services[i] = info;
+ break;
+ }
+ }
+ _pendingStatusChanges = false;
+ System.Threading.Monitor.PulseAll(this);
+ }
+ }
+
+ public override void addObserver(ServiceObserverPrx observer, Ice.Current current)
+ {
+ List<string> activeServices = new List<string>();
+
+ //
+ // Null observers and duplicate registrations are ignored
+ //
+
+ lock(this)
+ {
+ if(observer != null)
+ {
+ try
+ {
+ _observers.Add(observer, true);
+ }
+ catch(ArgumentException)
+ {
+ return;
+ }
+
+ if(_traceServiceObserver >= 1)
+ {
+ _logger.trace("IceBox.ServiceObserver",
+ "Added service observer " + _communicator.proxyToString(observer));
+ }
+
+ foreach(ServiceInfo info in _services)
+ {
+ if(info.status == ServiceStatus.Started)
+ {
+ activeServices.Add(info.name);
+ }
+ }
+ }
+ }
+
+ if(activeServices.Count > 0)
+ {
+ observer.begin_servicesStarted(activeServices.ToArray(), this.observerCompleted, null);
+ }
+ }
+
+ public override void shutdown(Ice.Current current)
+ {
+ _communicator.shutdown();
+ }
+
+ public int run()
+ {
+ try
+ {
+ Ice.Properties properties = _communicator.getProperties();
+
+ //
+ // Create an object adapter. Services probably should NOT share
+ // this object adapter, as the endpoint(s) for this object adapter
+ // will most likely need to be firewalled for security reasons.
+ //
+ Ice.ObjectAdapter adapter = null;
+ if(properties.getProperty("IceBox.ServiceManager.Endpoints").Length != 0)
+ {
+ adapter = _communicator.createObjectAdapter("IceBox.ServiceManager");
+
+ Ice.Identity identity = new Ice.Identity();
+ identity.category = properties.getPropertyWithDefault("IceBox.InstanceName", "IceBox");
+ identity.name = "ServiceManager";
+ adapter.add(this, identity);
+ }
+
+ //
+ // Parse the property set with the prefix "IceBox.Service.". These
+ // properties should have the following format:
+ //
+ // IceBox.Service.Foo=<assembly>:Package.Foo [args]
+ //
+ // We parse the service properties specified in IceBox.LoadOrder
+ // first, then the ones from remaining services.
+ //
+ string prefix = "IceBox.Service.";
+ Dictionary<string, string> services = properties.getPropertiesForPrefix(prefix);
+ string[] loadOrder = properties.getPropertyAsList("IceBox.LoadOrder");
+ List<StartServiceInfo> servicesInfo = new List<StartServiceInfo>();
+ for(int i = 0; i < loadOrder.Length; ++i)
+ {
+ if(loadOrder[i].Length > 0)
+ {
+ string key = prefix + loadOrder[i];
+ string value = services[key];
+ if(value == null)
+ {
+ FailureException ex = new FailureException();
+ ex.reason = "ServiceManager: no service definition for `" + loadOrder[i] + "'";
+ throw ex;
+ }
+ servicesInfo.Add(new StartServiceInfo(loadOrder[i], value, _argv));
+ services.Remove(key);
+ }
+ }
+ foreach(KeyValuePair<string, string> entry in services)
+ {
+ string name = entry.Key.Substring(prefix.Length);
+ string value = entry.Value;
+ servicesInfo.Add(new StartServiceInfo(name, value, _argv));
+ }
+
+ //
+ // Check if some services are using the shared communicator in which
+ // case we create the shared communicator now with a property set that
+ // is the union of all the service properties (from services that use
+ // the shared communicator).
+ //
+ if(properties.getPropertiesForPrefix("IceBox.UseSharedCommunicator.").Count > 0)
+ {
+ Ice.InitializationData initData = new Ice.InitializationData();
+ initData.properties = createServiceProperties("SharedCommunicator");
+ foreach(StartServiceInfo service in servicesInfo)
+ {
+ if(properties.getPropertyAsInt("IceBox.UseSharedCommunicator." + service.name) <= 0)
+ {
+ continue;
+ }
+
+ //
+ // Load the service properties using the shared communicator properties as
+ // the default properties.
+ //
+ Ice.Properties svcProperties = Ice.Util.createProperties(ref service.args, initData.properties);
+
+ //
+ // Remove properties from the shared property set that a service explicitly clears.
+ //
+ Dictionary<string, string> allProps = initData.properties.getPropertiesForPrefix("");
+ foreach(string key in allProps.Keys)
+ {
+ if(svcProperties.getProperty(key).Length == 0)
+ {
+ initData.properties.setProperty(key, "");
+ }
+ }
+
+ //
+ // Add the service properties to the shared communicator properties.
+ //
+ foreach(KeyValuePair<string, string> entry in svcProperties.getPropertiesForPrefix(""))
+ {
+ initData.properties.setProperty(entry.Key, entry.Value);
+ }
+
+ //
+ // Parse <service>.* command line options (the Ice command line options
+ // were parsed by the call to createProperties above).
+ //
+ service.args = initData.properties.parseCommandLineOptions(service.name, service.args);
+ }
+
+ string facetNamePrefix = "IceBox.SharedCommunicator.";
+ bool addFacets = configureAdmin(initData.properties, facetNamePrefix);
+
+ _sharedCommunicator = Ice.Util.initialize(initData);
+
+ if(addFacets)
+ {
+ // Add all facets created on shared communicator to the IceBox communicator
+ // but renamed <prefix>.<facet-name>, except for the Process facet which is
+ // never added.
+ foreach(KeyValuePair<string, Ice.Object> p in _sharedCommunicator.findAllAdminFacets())
+ {
+ if(!p.Key.Equals("Process"))
+ {
+ _communicator.addAdminFacet(p.Value, facetNamePrefix + p.Key);
+ }
+ }
+ }
+ }
+
+ foreach(StartServiceInfo s in servicesInfo)
+ {
+ startService(s.name, s.entryPoint, s.args);
+ }
+
+ //
+ // We may want to notify external scripts that the services
+ // have started. This is done by defining the property:
+ //
+ // PrintServicesReady=bundleName
+ //
+ // Where bundleName is whatever you choose to call this set of
+ // services. It will be echoed back as "bundleName ready".
+ //
+ // This must be done after start() has been invoked on the
+ // services.
+ //
+ string bundleName = properties.getProperty("IceBox.PrintServicesReady");
+ if(bundleName.Length > 0)
+ {
+ Console.Out.WriteLine(bundleName + " ready");
+ }
+
+ //
+ // Don't move after the adapter activation. This allows
+ // applications to wait for the service manager to be
+ // reachable before sending a signal to shutdown the
+ //
+ //
+ Ice.Application.shutdownOnInterrupt();
+
+ //
+ // Register "this" as a facet to the Admin object and create Admin object
+ //
+ try
+ {
+ _communicator.addAdminFacet(this, "IceBox.ServiceManager");
+ _communicator.getAdmin();
+ }
+ catch(Ice.ObjectAdapterDeactivatedException)
+ {
+ //
+ // Expected if the communicator has been shutdown.
+ //
+ }
+
+ //
+ // Start request dispatching after we've started the services.
+ //
+ if(adapter != null)
+ {
+ try
+ {
+ adapter.activate();
+ }
+ catch(Ice.ObjectAdapterDeactivatedException)
+ {
+ //
+ // Expected if the communicator has been shutdown.
+ //
+ }
+ }
+
+ _communicator.waitForShutdown();
+ }
+ catch(FailureException ex)
+ {
+ _logger.error(ex.ToString());
+ return 1;
+ }
+ catch(Exception ex)
+ {
+ _logger.error("ServiceManager: caught exception:\n" + ex.ToString());
+ return 1;
+ }
+ finally
+ {
+ //
+ // Invoke stop() on the services.
+ //
+ stopAll();
+ }
+
+ return 0;
+ }
+
+ private void startService(string service, string entryPoint, string[] args)
+ {
+ lock(this)
+ {
+ //
+ // Extract the assembly name and the class name.
+ //
+ string err = "ServiceManager: unable to load service '" + entryPoint + "': ";
+ int sepPos = entryPoint.IndexOf(':');
+ if(sepPos != -1 && IceInternal.AssemblyUtil.platform_ == IceInternal.AssemblyUtil.Platform.Windows)
+ {
+ const string driveLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if(entryPoint.Length > 3 &&
+ sepPos == 1 &&
+ driveLetters.IndexOf(entryPoint[0]) != -1 &&
+ (entryPoint[2] == '\\' || entryPoint[2] == '/'))
+ {
+ sepPos = entryPoint.IndexOf(':', 3);
+ }
+ }
+ if(sepPos == -1)
+ {
+ FailureException e = new FailureException();
+ e.reason = err + "invalid entry point format";
+ throw e;
+ }
+
+ System.Reflection.Assembly serviceAssembly = null;
+ string assemblyName = entryPoint.Substring(0, sepPos);
+ string className = entryPoint.Substring(sepPos + 1);
+
+ try
+ {
+ //
+ // First try to load the assembly using Assembly.Load, which will succeed
+ // if a fully-qualified name is provided or if a partial name has been qualified
+ // in configuration. If that fails, try Assembly.LoadFrom(), which will succeed
+ // if a file name is configured or a partial name is configured and DEVPATH is used.
+ //
+ try
+ {
+ serviceAssembly = System.Reflection.Assembly.Load(assemblyName);
+ }
+ catch(System.IO.IOException ex)
+ {
+ try
+ {
+ serviceAssembly = System.Reflection.Assembly.LoadFrom(assemblyName);
+ }
+ catch(System.IO.IOException)
+ {
+ throw ex;
+ }
+ }
+ }
+ catch(System.Exception ex)
+ {
+ FailureException e = new FailureException(ex);
+ e.reason = err + "unable to load assembly: " + assemblyName;
+ throw e;
+ }
+
+ //
+ // Instantiate the class.
+ //
+ System.Type c = null;
+ try
+ {
+ c = serviceAssembly.GetType(className, true);
+ }
+ catch(System.Exception ex)
+ {
+ FailureException e = new FailureException(ex);
+ e.reason = err + "GetType failed for '" + className + "'";
+ throw e;
+ }
+
+ ServiceInfo info = new ServiceInfo();
+ info.name = service;
+ info.status = ServiceStatus.Stopped;
+ info.args = args;
+
+ //
+ // If IceBox.UseSharedCommunicator.<name> is defined, create a
+ // communicator for the service. The communicator inherits
+ // from the shared communicator properties. If it's not
+ // defined, add the service properties to the shared
+ // commnunicator property set.
+ //
+ Ice.Communicator communicator;
+ if(_communicator.getProperties().getPropertyAsInt("IceBox.UseSharedCommunicator." + service) > 0)
+ {
+ Debug.Assert(_sharedCommunicator != null);
+ communicator = _sharedCommunicator;
+ }
+ else
+ {
+ //
+ // Create the service properties. We use the communicator properties as the default
+ // properties if IceBox.InheritProperties is set.
+ //
+ Ice.InitializationData initData = new Ice.InitializationData();
+ initData.properties = createServiceProperties(service);
+ if(info.args.Length > 0)
+ {
+ //
+ // Create the service properties with the given service arguments. This should
+ // read the service config file if it's specified with --Ice.Config.
+ //
+ initData.properties = Ice.Util.createProperties(ref info.args, initData.properties);
+
+ //
+ // Next, parse the service "<service>.*" command line options (the Ice command
+ // line options were parsed by the createProperties above)
+ //
+ info.args = initData.properties.parseCommandLineOptions(service, info.args);
+ }
+
+ //
+ // Clone the logger to assign a new prefix. If one of the built-in loggers is configured
+ // don't set any logger.
+ //
+ if(initData.properties.getProperty("Ice.LogFile").Length == 0 &&
+ (initData.properties.getPropertyAsInt("Ice.UseSyslog") <= 0 ||
+ IceInternal.AssemblyUtil.platform_ == IceInternal.AssemblyUtil.Platform.Windows))
+ {
+ initData.logger = _logger.cloneWithPrefix(initData.properties.getProperty("Ice.ProgramName"));
+ }
+
+ //
+ // If Admin is enabled on the IceBox communicator, for each service that does not set
+ // Ice.Admin.Enabled, we set Ice.Admin.Enabled=1 to have this service create facets; then
+ // we add these facets to the IceBox Admin object as IceBox.Service.<service>.<facet>.
+ //
+ string serviceFacetNamePrefix = "IceBox.Service." + service + ".";
+ bool addFacets = configureAdmin(initData.properties, serviceFacetNamePrefix);
+
+ //
+ // Remaining command line options are passed to the communicator. This is
+ // necessary for Ice plug-in properties (e.g.: IceSSL).
+ //
+ info.communicator = Ice.Util.initialize(ref info.args, initData);
+ communicator = info.communicator;
+
+ if(addFacets)
+ {
+ // Add all facets created on the service communicator to the IceBox communicator
+ // but renamed IceBox.Service.<service>.<facet-name>, except for the Process facet
+ // which is never added
+ foreach(KeyValuePair<string, Ice.Object> p in communicator.findAllAdminFacets())
+ {
+ if(!p.Key.Equals("Process"))
+ {
+ _communicator.addAdminFacet(p.Value, serviceFacetNamePrefix + p.Key);
+ }
+ }
+ }
+ }
+
+ try
+ {
+ //
+ // Instantiate the service.
+ //
+ try
+ {
+ //
+ // If the service class provides a constructor that accepts an Ice.Communicator argument,
+ // use that in preference to the default constructor.
+ //
+ Type[] parameterTypes = new Type[1];
+ parameterTypes[0] = typeof(Ice.Communicator);
+ System.Reflection.ConstructorInfo ci = c.GetConstructor(parameterTypes);
+ if(ci != null)
+ {
+ try
+ {
+ Object[] parameters = new Object[1];
+ parameters[0] = _communicator;
+ info.service = (Service)ci.Invoke(parameters);
+ }
+ catch(System.MethodAccessException ex)
+ {
+ FailureException e = new FailureException(ex);
+ e.reason = err + "unable to access service constructor " + className + "(Ice.Communicator)";
+ throw e;
+ }
+ }
+ else
+ {
+ //
+ // Fall back to the default constructor.
+ //
+ try
+ {
+ info.service = (Service)IceInternal.AssemblyUtil.createInstance(c);
+ if(info.service == null)
+ {
+ FailureException e = new FailureException();
+ e.reason = err + "no default constructor for '" + className + "'";
+ throw e;
+ }
+ }
+ catch(System.UnauthorizedAccessException ex)
+ {
+ FailureException e = new FailureException(ex);
+ e.reason = err + "unauthorized access to default service constructor for " + className;
+ throw e;
+ }
+ }
+ }
+ catch(FailureException)
+ {
+ throw;
+ }
+ catch(System.InvalidCastException ex)
+ {
+ FailureException e = new FailureException(ex);
+ e.reason = err + "service does not implement IceBox.Service";
+ throw e;
+ }
+ catch(System.Reflection.TargetInvocationException ex)
+ {
+ if(ex.InnerException is IceBox.FailureException)
+ {
+ throw ex.InnerException;
+ }
+ else
+ {
+ FailureException e = new FailureException(ex.InnerException);
+ e.reason = err + "exception in service constructor for " + className;
+ throw e;
+ }
+ }
+ catch(System.Exception ex)
+ {
+ FailureException e = new FailureException(ex);
+ e.reason = err + "exception in service constructor " + className;
+ throw e;
+ }
+
+
+ try
+ {
+ info.service.start(service, communicator, info.args);
+ }
+ catch(FailureException)
+ {
+ throw;
+ }
+ catch(System.Exception ex)
+ {
+ FailureException e = new FailureException(ex);
+ e.reason = "exception while starting service " + service;
+ throw e;
+ }
+
+ info.status = ServiceStatus.Started;
+ _services.Add(info);
+ }
+ catch(System.Exception ex)
+ {
+ if(info.communicator != null)
+ {
+ destroyServiceCommunicator(service, info.communicator);
+ }
+
+ throw ex;
+ }
+
+ }
+ }
+
+ private void stopAll()
+ {
+ lock(this)
+ {
+ //
+ // First wait for any active startService/stopService calls to complete.
+ //
+ while(_pendingStatusChanges)
+ {
+ System.Threading.Monitor.Wait(this);
+ }
+
+ //
+ // For each service, we call stop on the service and flush its database environment to
+ // the disk. Services are stopped in the reverse order of the order they were started.
+ //
+ _services.Reverse();
+ List<string> stoppedServices = new List<string>();
+ foreach(ServiceInfo info in _services)
+ {
+ if(info.status == ServiceStatus.Started)
+ {
+ try
+ {
+ info.service.stop();
+ stoppedServices.Add(info.name);
+ }
+ catch(System.Exception e)
+ {
+ _logger.warning("IceBox.ServiceManager: exception while stopping service " + info.name + ":\n" +
+ e.ToString());
+ }
+ }
+
+ if(info.communicator != null)
+ {
+ destroyServiceCommunicator(info.name, info.communicator);
+ }
+ }
+
+ if(_sharedCommunicator != null)
+ {
+ removeAdminFacets("IceBox.SharedCommunicator.");
+
+ try
+ {
+ _sharedCommunicator.destroy();
+ }
+ catch(System.Exception e)
+ {
+ _logger.warning("ServiceManager: exception while destroying shared communicator:\n" + e.ToString());
+ }
+ _sharedCommunicator = null;
+ }
+
+ _services.Clear();
+ servicesStopped(stoppedServices, _observers.Keys);
+ }
+ }
+
+ private void servicesStarted(List<String> services, Dictionary<ServiceObserverPrx, bool>.KeyCollection observers)
+ {
+ //
+ // Must be called with 'this' unlocked
+ //
+
+ if(services.Count > 0)
+ {
+ string[] servicesArray = services.ToArray();
+
+ foreach(ServiceObserverPrx observer in observers)
+ {
+ observer.begin_servicesStarted(servicesArray, this.observerCompleted, null);
+ }
+ }
+ }
+
+ private void servicesStopped(List<string> services, Dictionary<ServiceObserverPrx, bool>.KeyCollection observers)
+ {
+ //
+ // Must be called with 'this' unlocked
+ //
+
+ if(services.Count > 0)
+ {
+ string[] servicesArray = services.ToArray();
+
+ foreach(ServiceObserverPrx observer in observers)
+ {
+ observer.begin_servicesStopped(servicesArray, this.observerCompleted, null);
+ }
+ }
+ }
+
+ private void
+ observerCompleted(Ice.AsyncResult result)
+ {
+ try
+ {
+ result.throwLocalException();
+ }
+ catch(Ice.LocalException ex)
+ {
+ lock(this)
+ {
+ ServiceObserverPrx observer = ServiceObserverPrxHelper.uncheckedCast(result.getProxy());
+ if(_observers.Remove(observer))
+ {
+ observerRemoved(observer, ex);
+ }
+ }
+ }
+ }
+
+ private void observerRemoved(ServiceObserverPrx observer, System.Exception ex)
+ {
+ if(_traceServiceObserver >= 1)
+ {
+ //
+ // CommunicatorDestroyedException may occur during shutdown. The observer notification has
+ // been sent, but the communicator was destroyed before the reply was received. We do not
+ // log a message for this exception.
+ //
+ if(!(ex is Ice.CommunicatorDestroyedException))
+ {
+ _logger.trace("IceBox.ServiceObserver",
+ "Removed service observer " + _communicator.proxyToString(observer)
+ + "\nafter catching " + ex.ToString());
+ }
+ }
+ }
+
+ private enum ServiceStatus
+ {
+ Stopping,
+ Stopped,
+ Starting,
+ Started
+ }
+
+ struct ServiceInfo
+ {
+ public string name;
+ public Service service;
+ public Ice.Communicator communicator;
+ public ServiceStatus status;
+ public string[] args;
+ }
+
+ class StartServiceInfo
+ {
+ public StartServiceInfo(string service, string value, string[] serverArgs)
+ {
+ //
+ // Separate the entry point from the arguments.
+ //
+ name = service;
+
+ try
+ {
+ args = IceUtilInternal.Options.split(value);
+ }
+ catch(IceUtilInternal.Options.BadQuote ex)
+ {
+ FailureException e = new FailureException();
+ e.reason = "ServiceManager: invalid arguments for service `" + name + "':\n" + ex.Message;
+ throw e;
+ }
+
+ Debug.Assert(args.Length > 0);
+
+ entryPoint = args[0];
+
+ //
+ // Shift the arguments.
+ //
+ string[] tmp = new string[args.Length - 1];
+ Array.Copy(args, 1, tmp, 0, args.Length - 1);
+ args = tmp;
+
+ if(serverArgs.Length > 0)
+ {
+ ArrayList l = new ArrayList();
+ for(int j = 0; j < args.Length; j++)
+ {
+ l.Add(args[j]);
+ }
+ for(int j = 0; j < serverArgs.Length; j++)
+ {
+ if(serverArgs[j].StartsWith("--" + service + ".", StringComparison.Ordinal))
+ {
+ l.Add(serverArgs[j]);
+ }
+ }
+ args = (string[])l.ToArray(typeof(string));
+ }
+ }
+
+ public string name;
+ public string entryPoint;
+ public string[] args;
+ }
+
+ private Ice.Properties createServiceProperties(String service)
+ {
+ Ice.Properties properties;
+ Ice.Properties communicatorProperties = _communicator.getProperties();
+ if(communicatorProperties.getPropertyAsInt("IceBox.InheritProperties") > 0)
+ {
+ properties = communicatorProperties.ice_clone_();
+ // Inherit all except Ice.Admin.xxx properties
+ foreach(string p in properties.getPropertiesForPrefix("Ice.Admin.").Keys)
+ {
+ properties.setProperty(p, "");
+ }
+ }
+ else
+ {
+ properties = Ice.Util.createProperties();
+ }
+
+ String programName = communicatorProperties.getProperty("Ice.ProgramName");
+ if(programName.Length == 0)
+ {
+ properties.setProperty("Ice.ProgramName", service);
+ }
+ else
+ {
+ properties.setProperty("Ice.ProgramName", programName + "-" + service);
+ }
+ return properties;
+ }
+
+ private void destroyServiceCommunicator(string service, Ice.Communicator communicator)
+ {
+ if(communicator != null)
+ {
+ try
+ {
+ communicator.shutdown();
+ communicator.waitForShutdown();
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ //
+ // Ignore, the service might have already destroyed
+ // the communicator for its own reasons.
+ //
+ }
+ catch(System.Exception e)
+ {
+ _logger.warning("ServiceManager: exception while shutting down communicator for service "
+ + service + "\n" + e.ToString());
+ }
+
+ removeAdminFacets("IceBox.Service." + service + ".");
+
+ try
+ {
+ communicator.destroy();
+ }
+ catch(System.Exception e)
+ {
+ _logger.warning("ServiceManager: exception while destroying communicator for service "
+ + service + "\n" + e.ToString());
+ }
+ }
+ }
+
+ private bool configureAdmin(Ice.Properties properties, string prefix)
+ {
+ if(_adminEnabled && properties.getProperty("Ice.Admin.Enabled").Length == 0)
+ {
+ List<string> facetNames = new List<string>();
+ foreach(string p in _adminFacetFilter)
+ {
+ if(p.StartsWith(prefix))
+ {
+ facetNames.Add(p.Substring(prefix.Length));
+ }
+ }
+
+ if(_adminFacetFilter.Count == 0 || facetNames.Count > 0)
+ {
+ properties.setProperty("Ice.Admin.Enabled", "1");
+
+ if(facetNames.Count > 0)
+ {
+ // TODO: need String.Join with escape!
+ properties.setProperty("Ice.Admin.Facets", String.Join(" ", facetNames.ToArray()));
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void removeAdminFacets(string prefix)
+ {
+ try
+ {
+ foreach(string p in _communicator.findAllAdminFacets().Keys)
+ {
+ if(p.StartsWith(prefix))
+ {
+ _communicator.removeAdminFacet(p);
+ }
+ }
+ }
+ catch(Ice.CommunicatorDestroyedException)
+ {
+ // Ignored
+ }
+ catch(Ice.ObjectAdapterDeactivatedException)
+ {
+ // Ignored
+ }
+ }
+
+ private Ice.Communicator _communicator;
+ private bool _adminEnabled = false;
+ private HashSet<string> _adminFacetFilter = null;
+ private Ice.Communicator _sharedCommunicator = null;
+ private Ice.Logger _logger;
+ private string[] _argv; // Filtered server argument vector
+ private List<ServiceInfo> _services = new List<ServiceInfo>();
+ private bool _pendingStatusChanges = false;
+ private Dictionary<ServiceObserverPrx, bool> _observers = new Dictionary<ServiceObserverPrx, bool>();
+ private int _traceServiceObserver = 0;
+}
+
+}
diff --git a/csharp/src/IceBox/generated/.gitignore b/csharp/src/IceBox/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/IceBox/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/IceDiscovery/.depend.mak b/csharp/src/IceDiscovery/.depend.mak
new file mode 100644
index 00000000000..0f34b397f12
--- /dev/null
+++ b/csharp/src/IceDiscovery/.depend.mak
@@ -0,0 +1,4 @@
+
+IceDiscovery.cs: \
+ "$(slicedir)\IceDiscovery\IceDiscovery.ice" \
+ "$(slicedir)/Ice/Identity.ice"
diff --git a/csharp/src/IceDiscovery/AssemblyInfo.cs b/csharp/src/IceDiscovery/AssemblyInfo.cs
new file mode 100644
index 00000000000..9fc80df085a
--- /dev/null
+++ b/csharp/src/IceDiscovery/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IceDiscovery")]
+[assembly: AssemblyDescription("IceDiscovery core run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IceDiscovery for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IceDiscovery/LocatorI.cs b/csharp/src/IceDiscovery/LocatorI.cs
new file mode 100644
index 00000000000..b0adf04ce90
--- /dev/null
+++ b/csharp/src/IceDiscovery/LocatorI.cs
@@ -0,0 +1,210 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceDiscovery
+{
+ using System;
+ using System.Collections.Generic;
+
+ class LocatorRegistryI : Ice.LocatorRegistryDisp_
+ {
+ public
+ LocatorRegistryI(Ice.Communicator com)
+ {
+ _wellKnownProxy = com.stringToProxy("p").ice_locator(null).ice_router(null).ice_collocationOptimized(true);
+ }
+
+ public override void
+ setAdapterDirectProxy_async(Ice.AMD_LocatorRegistry_setAdapterDirectProxy cb,
+ string adapterId,
+ Ice.ObjectPrx proxy,
+ Ice.Current current)
+ {
+ lock(this)
+ {
+ if(proxy != null)
+ {
+ _adapters.Add(adapterId, proxy);
+ }
+ else
+ {
+ _adapters.Remove(adapterId);
+ }
+ cb.ice_response();
+ }
+ }
+
+ public override void
+ setReplicatedAdapterDirectProxy_async(Ice.AMD_LocatorRegistry_setReplicatedAdapterDirectProxy cb,
+ string adapterId,
+ string replicaGroupId,
+ Ice.ObjectPrx proxy,
+ Ice.Current current)
+ {
+ lock(this)
+ {
+ if(proxy != null)
+ {
+ _adapters.Add(adapterId, proxy);
+ HashSet<string> adapterIds;
+ if(!_replicaGroups.TryGetValue(replicaGroupId, out adapterIds))
+ {
+ adapterIds = new HashSet<string>();
+ _replicaGroups.Add(replicaGroupId, adapterIds);
+ }
+ adapterIds.Add(adapterId);
+ }
+ else
+ {
+ _adapters.Remove(adapterId);
+ HashSet<string> adapterIds;
+ if(_replicaGroups.TryGetValue(replicaGroupId, out adapterIds))
+ {
+ adapterIds.Remove(adapterId);
+ if(adapterIds.Count == 0)
+ {
+ _replicaGroups.Remove(replicaGroupId);
+ }
+ }
+ }
+ }
+ cb.ice_response();
+ }
+
+ public override void
+ setServerProcessProxy_async(Ice.AMD_LocatorRegistry_setServerProcessProxy cb,
+ string id,
+ Ice.ProcessPrx process,
+ Ice.Current current)
+ {
+ cb.ice_response();
+ }
+
+ internal Ice.ObjectPrx findObject(Ice.Identity id)
+ {
+ lock(this)
+ {
+ if(id.name.Length == 0)
+ {
+ return null;
+ }
+
+ Ice.ObjectPrx prx = _wellKnownProxy.ice_identity(id);
+
+ List<string> adapterIds = new List<string>();
+ foreach(KeyValuePair<string, HashSet<string>> entry in _replicaGroups)
+ {
+ try
+ {
+ prx.ice_adapterId(entry.Key).ice_ping();
+ adapterIds.Add(entry.Key);
+ }
+ catch(Ice.Exception)
+ {
+ }
+ }
+ if(adapterIds.Count == 0)
+ {
+ foreach(KeyValuePair<string, Ice.ObjectPrx> entry in _adapters)
+ {
+ try
+ {
+ prx.ice_adapterId(entry.Key).ice_ping();
+ adapterIds.Add(entry.Key);
+ }
+ catch(Ice.Exception)
+ {
+ }
+ }
+ }
+
+ if(adapterIds.Count == 0)
+ {
+ return null;
+ }
+ //adapterIds.Suffle();
+ return prx.ice_adapterId(adapterIds[0]);
+ }
+ }
+
+ internal Ice.ObjectPrx findAdapter(string adapterId, out bool isReplicaGroup)
+ {
+ lock(this)
+ {
+ Ice.ObjectPrx result = null;
+ if(_adapters.TryGetValue(adapterId, out result))
+ {
+ isReplicaGroup = false;
+ return result;
+ }
+
+ HashSet<string> adapterIds;
+ if(_replicaGroups.TryGetValue(adapterId, out adapterIds))
+ {
+ List<Ice.Endpoint> endpoints = new List<Ice.Endpoint>();
+ foreach(string a in adapterIds)
+ {
+ Ice.ObjectPrx proxy;
+ if(!_adapters.TryGetValue(a, out proxy))
+ {
+ continue; // TODO: Inconsistency
+ }
+
+ if(result == null)
+ {
+ result = proxy;
+ }
+
+ endpoints.AddRange(proxy.ice_getEndpoints());
+ }
+
+ if(result != null)
+ {
+ isReplicaGroup = true;
+ return result.ice_endpoints(endpoints.ToArray());
+ }
+ }
+
+ isReplicaGroup = false;
+ return null;
+ }
+ }
+
+ private readonly Ice.ObjectPrx _wellKnownProxy;
+ private Dictionary<string, Ice.ObjectPrx> _adapters = new Dictionary<string, Ice.ObjectPrx>();
+ private Dictionary<string, HashSet<string>> _replicaGroups = new Dictionary<string, HashSet<string>>();
+ };
+
+ class LocatorI : Ice.LocatorDisp_
+ {
+ public LocatorI(LookupI lookup, Ice.LocatorRegistryPrx registry)
+ {
+ _lookup = lookup;
+ _registry = registry;
+ }
+
+ public override void findObjectById_async(Ice.AMD_Locator_findObjectById cb, Ice.Identity id, Ice.Current c)
+ {
+ _lookup.findObject(cb, id);
+ }
+
+ public override void findAdapterById_async(Ice.AMD_Locator_findAdapterById cb, string adapterId, Ice.Current c)
+ {
+ _lookup.findAdapter(cb, adapterId);
+ }
+
+ public override Ice.LocatorRegistryPrx getRegistry(Ice.Current current)
+ {
+ return _registry;
+ }
+
+ private LookupI _lookup;
+ private Ice.LocatorRegistryPrx _registry;
+ };
+} \ No newline at end of file
diff --git a/csharp/src/IceDiscovery/LookupI.cs b/csharp/src/IceDiscovery/LookupI.cs
new file mode 100644
index 00000000000..27a143f3d9d
--- /dev/null
+++ b/csharp/src/IceDiscovery/LookupI.cs
@@ -0,0 +1,385 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceDiscovery
+{
+ using System;
+ using System.Collections.Generic;
+
+ class Request<T, AmdCB>
+ {
+ protected Request(LookupI lookup, T id, int retryCount)
+ {
+ lookup_ = lookup;
+ nRetry_ = retryCount;
+ _id = id;
+ }
+
+ public T getId()
+ {
+ return _id;
+ }
+
+ public bool addCallback(AmdCB cb)
+ {
+ callbacks_.Add(cb);
+ return callbacks_.Count == 1;
+ }
+
+ public virtual bool retry()
+ {
+ return --nRetry_ >= 0;
+ }
+
+ protected LookupI lookup_;
+ protected int nRetry_;
+ protected List<AmdCB> callbacks_ = new List<AmdCB>();
+
+ private T _id;
+ };
+
+ class AdapterRequest : Request<string, Ice.AMD_Locator_findAdapterById>, IceInternal.TimerTask
+ {
+ public AdapterRequest(LookupI lookup, string id, int retryCount) : base(lookup, id, retryCount)
+ {
+ _start = System.DateTime.Now.Ticks;
+ }
+
+ public override bool retry()
+ {
+ return _proxies.Count == 0 && --nRetry_ >= 0;
+ }
+
+ public bool response(Ice.ObjectPrx proxy, bool isReplicaGroup)
+ {
+ if(isReplicaGroup)
+ {
+ _proxies.Add(proxy);
+ if(_latency == 0)
+ {
+ _latency = (long)((System.DateTime.Now.Ticks - _start) * lookup_.latencyMultiplier() / 10000.0);
+ if(_latency == 0)
+ {
+ _latency = 1; // 1ms
+ }
+ lookup_.timer().cancel(this);
+ lookup_.timer().schedule(this, _latency);
+ }
+ return false;
+ }
+ finished(proxy);
+ return true;
+ }
+
+ public void finished(Ice.ObjectPrx proxy)
+ {
+ if(proxy != null || _proxies.Count == 0)
+ {
+ sendResponse(proxy);
+ return;
+ }
+ else if(_proxies.Count == 1)
+ {
+ sendResponse(_proxies[0]);
+ return;
+ }
+
+ List<Ice.Endpoint> endpoints = new List<Ice.Endpoint>();
+ Ice.ObjectPrx result = null;
+ foreach(Ice.ObjectPrx prx in _proxies)
+ {
+ if(result == null)
+ {
+ result = prx;
+ }
+ endpoints.AddRange(prx.ice_getEndpoints());
+ }
+ sendResponse(result.ice_endpoints(endpoints.ToArray()));
+ }
+
+ public void runTimerTask()
+ {
+ lookup_.adapterRequestTimedOut(this);
+ }
+
+ private void sendResponse(Ice.ObjectPrx proxy)
+ {
+ foreach(Ice.AMD_Locator_findAdapterById cb in callbacks_)
+ {
+ cb.ice_response(proxy);
+ }
+ callbacks_.Clear();
+ }
+
+ private List<Ice.ObjectPrx> _proxies = new List<Ice.ObjectPrx>();
+ private long _start;
+ private long _latency;
+ };
+
+ class ObjectRequest : Request<Ice.Identity, Ice.AMD_Locator_findObjectById>, IceInternal.TimerTask
+ {
+ public ObjectRequest(LookupI lookup, Ice.Identity id, int retryCount) : base(lookup, id, retryCount)
+ {
+ }
+
+ public void response(Ice.ObjectPrx proxy)
+ {
+ finished(proxy);
+ }
+
+ public void finished(Ice.ObjectPrx proxy)
+ {
+ foreach(Ice.AMD_Locator_findObjectById cb in callbacks_)
+ {
+ cb.ice_response(proxy);
+ }
+ callbacks_.Clear();
+ }
+
+ public void runTimerTask()
+ {
+ lookup_.objectRequestTimedOut(this);
+ }
+ };
+
+ class LookupI : LookupDisp_
+ {
+ public LookupI(LocatorRegistryI registry, LookupPrx lookup, Ice.Properties properties)
+ {
+ _registry = registry;
+ _lookup = lookup;
+ _timeout = properties.getPropertyAsIntWithDefault("IceDiscovery.Timeout", 300);
+ _retryCount = properties.getPropertyAsIntWithDefault("IceDiscovery.RetryCount", 3);
+ _latencyMultiplier = properties.getPropertyAsIntWithDefault("IceDiscovery.LatencyMultiplier", 1);
+ _domainId = properties.getProperty("IceDiscovery.DomainId");
+ _timer = IceInternal.Util.getInstance(lookup.ice_getCommunicator()).timer();
+ }
+
+ public void setLookupReply(LookupReplyPrx lookupReply)
+ {
+ _lookupReply = lookupReply;
+ }
+
+ public override void findObjectById(string domainId, Ice.Identity id, IceDiscovery.LookupReplyPrx reply,
+ Ice.Current c)
+ {
+ if(!domainId.Equals(_domainId))
+ {
+ return; // Ignore
+ }
+
+ Ice.ObjectPrx proxy = _registry.findObject(id);
+ if(proxy != null)
+ {
+ //
+ // Reply to the mulicast request using the given proxy.
+ //
+ getLookupReply(reply, c).begin_foundObjectById(id, proxy);
+ }
+ }
+
+ public override void findAdapterById(string domainId, string adapterId, IceDiscovery.LookupReplyPrx reply,
+ Ice.Current c)
+ {
+ if(!domainId.Equals(_domainId))
+ {
+ return; // Ignore
+ }
+
+ bool isReplicaGroup;
+ Ice.ObjectPrx proxy = _registry.findAdapter(adapterId, out isReplicaGroup);
+ if(proxy != null)
+ {
+ //
+ // Reply to the multicast request using the given proxy.
+ //
+ getLookupReply(reply, c).begin_foundAdapterById(adapterId, proxy, isReplicaGroup);
+ }
+ }
+
+ internal void findObject(Ice.AMD_Locator_findObjectById cb, Ice.Identity id)
+ {
+ lock(this)
+ {
+ ObjectRequest request;
+ if(!_objectRequests.TryGetValue(id, out request))
+ {
+ request = new ObjectRequest(this, id, _retryCount);
+ _objectRequests.Add(id, request);
+ }
+ if(request.addCallback(cb))
+ {
+ _lookup.begin_findObjectById(_domainId, id, _lookupReply);
+ _timer.schedule(request, _timeout);
+ }
+ }
+ }
+
+ internal void findAdapter(Ice.AMD_Locator_findAdapterById cb, string adapterId)
+ {
+ lock(this)
+ {
+ AdapterRequest request;
+ if(!_adapterRequests.TryGetValue(adapterId, out request))
+ {
+ request = new AdapterRequest(this, adapterId, _retryCount);
+ _adapterRequests.Add(adapterId, request);
+ }
+ if(request.addCallback(cb))
+ {
+ _lookup.begin_findAdapterById(_domainId, adapterId, _lookupReply);
+ _timer.schedule(request, _timeout);
+ }
+ }
+ }
+
+ internal void foundObject(Ice.Identity id, Ice.ObjectPrx proxy)
+ {
+ lock(this)
+ {
+ ObjectRequest request;
+ if(!_objectRequests.TryGetValue(id, out request))
+ {
+ return;
+ }
+ request.response(proxy);
+ _timer.cancel(request);
+ _objectRequests.Remove(id);
+ }
+ }
+
+ internal void foundAdapter(string adapterId, Ice.ObjectPrx proxy, bool isReplicaGroup)
+ {
+ lock(this)
+ {
+ AdapterRequest request;
+ if(!_adapterRequests.TryGetValue(adapterId, out request))
+ {
+ return;
+ }
+
+ if(request.response(proxy, isReplicaGroup))
+ {
+ _timer.cancel(request);
+ _adapterRequests.Remove(request.getId());
+ }
+ }
+ }
+
+ internal void objectRequestTimedOut(ObjectRequest request)
+ {
+ lock(this)
+ {
+ ObjectRequest r;
+ if(!_objectRequests.TryGetValue(request.getId(), out r) || r != request)
+ {
+ return;
+ }
+
+ if(request.retry())
+ {
+ _lookup.begin_findObjectById(_domainId, request.getId(), _lookupReply);
+ _timer.schedule(request, _timeout);
+ }
+ else
+ {
+ request.finished(null);
+ _objectRequests.Remove(request.getId());
+ _timer.cancel(request);
+ }
+ }
+ }
+
+ internal void adapterRequestTimedOut(AdapterRequest request)
+ {
+ lock(this)
+ {
+ AdapterRequest r;
+ if(!_adapterRequests.TryGetValue(request.getId(), out r) || r != request)
+ {
+ return;
+ }
+
+ if(request.retry())
+ {
+ _lookup.begin_findAdapterById(_domainId, request.getId(), _lookupReply);
+ _timer.schedule(request, _timeout);
+ }
+ else
+ {
+ request.finished(null);
+ _adapterRequests.Remove(request.getId());
+ _timer.cancel(request);
+ }
+ }
+ }
+
+ internal IceInternal.Timer timer()
+ {
+ return _timer;
+ }
+
+ internal int latencyMultiplier()
+ {
+ return _latencyMultiplier;
+ }
+
+ private LookupReplyPrx getLookupReply(LookupReplyPrx reply, Ice.Current current)
+ {
+ // Ice.UDPConnectionInfo info = Ice.UDPConnectionInfoPtr.dynamicCast(current.con.getInfo());
+ // if(info)
+ // {
+ // Ice.Communicator com = current.adapter.getCommunicator();
+ // ostringstream os;
+ // os << "\"" << com.identityToString(reply.ice_getIdentity()) << "\"";
+ // os << ":udp -h " << info.remoteAddress << " -p " << info.remotePort;
+ // return LookupReplyPrx.uncheckedCast(com.stringToProxy(os.str()).ice_datagram());
+ // }
+ // else
+ {
+ return reply;
+ }
+ }
+
+ private LocatorRegistryI _registry;
+ private readonly LookupPrx _lookup;
+ private LookupReplyPrx _lookupReply;
+ private readonly int _timeout;
+ private readonly int _retryCount;
+ private readonly int _latencyMultiplier;
+ private readonly string _domainId;
+
+ private IceInternal.Timer _timer;
+
+ private Dictionary<Ice.Identity, ObjectRequest> _objectRequests = new Dictionary<Ice.Identity, ObjectRequest>();
+ private Dictionary<string, AdapterRequest> _adapterRequests = new Dictionary<string, AdapterRequest>();
+ };
+
+ class LookupReplyI : LookupReplyDisp_
+ {
+ public LookupReplyI(LookupI lookup)
+ {
+ _lookup = lookup;
+ }
+
+ public override void foundObjectById(Ice.Identity id, Ice.ObjectPrx proxy, Ice.Current c)
+ {
+ _lookup.foundObject(id, proxy);
+ }
+
+ public override void foundAdapterById(string adapterId, Ice.ObjectPrx proxy, bool isReplicaGroup, Ice.Current c)
+ {
+ _lookup.foundAdapter(adapterId, proxy, isReplicaGroup);
+ }
+
+ private LookupI _lookup;
+ };
+
+}
+
diff --git a/csharp/src/IceDiscovery/Makefile b/csharp/src/IceDiscovery/Makefile
new file mode 100644
index 00000000000..88581745332
--- /dev/null
+++ b/csharp/src/IceDiscovery/Makefile
@@ -0,0 +1,49 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = IceDiscovery
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs \
+ LocatorI.cs \
+ LookupI.cs \
+ PluginI.cs
+
+SLICE_SRCS = $(SDIR)/IceDiscovery.ice
+
+SDIR = $(slicedir)/IceDiscovery
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/IceDiscovery/Makefile.mak b/csharp/src/IceDiscovery/Makefile.mak
new file mode 100644
index 00000000000..0260afceba1
--- /dev/null
+++ b/csharp/src/IceDiscovery/Makefile.mak
@@ -0,0 +1,54 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = IceDiscovery
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs \
+ LocatorI.cs \
+ LookupI.cs \
+ PluginI.cs
+
+GEN_SRCS = $(GDIR)\IceDiscovery.cs
+
+SDIR = $(slicedir)\IceDiscovery
+GDIR = generated
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) -r:$(refdir)\Ice.dll $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
diff --git a/csharp/src/IceDiscovery/PluginI.cs b/csharp/src/IceDiscovery/PluginI.cs
new file mode 100644
index 00000000000..ec846f016fd
--- /dev/null
+++ b/csharp/src/IceDiscovery/PluginI.cs
@@ -0,0 +1,149 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceDiscovery
+{
+ using System;
+ using System.Text;
+ using System.Collections.Generic;
+
+ public sealed class PluginFactory : Ice.PluginFactory
+ {
+ public Ice.Plugin
+ create(Ice.Communicator communicator, string name, string[] args)
+ {
+ return new PluginI(communicator);
+ }
+ }
+
+ public sealed class PluginI : Ice.Plugin
+ {
+ public
+ PluginI(Ice.Communicator communicator)
+ {
+ _communicator = communicator;
+ }
+
+ public void initialize()
+ {
+ Ice.Properties properties = _communicator.getProperties();
+
+ bool ipv4 = properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0;
+ bool preferIPv6 = properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0;
+ string address;
+ if(ipv4 && !preferIPv6)
+ {
+ address = properties.getPropertyWithDefault("IceDiscovery.Address", "239.255.0.1");
+ }
+ else
+ {
+ address = properties.getPropertyWithDefault("IceDiscovery.Address", "ff15::1");
+ }
+ int port = properties.getPropertyAsIntWithDefault("IceDiscovery.Port", 4061);
+ string intf = properties.getProperty("IceDiscovery.Interface");
+
+ if(properties.getProperty("IceDiscovery.Multicast.Endpoints").Length == 0)
+ {
+ StringBuilder s = new StringBuilder();
+ s.Append("udp -h \"").Append(address).Append("\" -p ").Append(port);
+ if(intf.Length != 0)
+ {
+ s.Append(" --interface \"").Append(intf).Append("\"");
+ }
+ properties.setProperty("IceDiscovery.Multicast.Endpoints", s.ToString());
+ }
+ if(properties.getProperty("IceDiscovery.Reply.Endpoints").Length == 0)
+ {
+ StringBuilder s = new StringBuilder();
+ s.Append("udp");
+ if(intf.Length != 0)
+ {
+ s.Append(" -h \"").Append(intf).Append("\"");
+ }
+ properties.setProperty("IceDiscovery.Reply.Endpoints", s.ToString());
+ }
+ if(properties.getProperty("IceDiscovery.Locator.Endpoints").Length == 0)
+ {
+ properties.setProperty("IceDiscovery.Locator.AdapterId", Guid.NewGuid().ToString());
+ }
+
+ _multicastAdapter = _communicator.createObjectAdapter("IceDiscovery.Multicast");
+ _replyAdapter = _communicator.createObjectAdapter("IceDiscovery.Reply");
+ _locatorAdapter = _communicator.createObjectAdapter("IceDiscovery.Locator");
+
+ //
+ // Setup locatory registry.
+ //
+ LocatorRegistryI locatorRegistry = new LocatorRegistryI(_communicator);
+ Ice.LocatorRegistryPrx locatorRegistryPrx = Ice.LocatorRegistryPrxHelper.uncheckedCast(
+ _locatorAdapter.addWithUUID(locatorRegistry));
+
+ string lookupEndpoints = properties.getProperty("IceDiscovery.Lookup");
+ if(lookupEndpoints.Length == 0)
+ {
+ lookupEndpoints = "udp -h \"" + address + "\" -p " + port;
+ if(intf.Length > 0)
+ {
+ lookupEndpoints += " --interface \"" + intf + "\"";
+ }
+ }
+
+ Ice.ObjectPrx lookupPrx = _communicator.stringToProxy("IceDiscovery/Lookup -d:" + lookupEndpoints);
+ lookupPrx = lookupPrx.ice_collocationOptimized(false);
+ try
+ {
+ lookupPrx.ice_getConnection();
+ }
+ catch(Ice.LocalException ex)
+ {
+ StringBuilder b = new StringBuilder();
+ b.Append("unable to establish multicast connection, IceDiscovery will be disabled:\n");
+ b.Append("proxy = ");
+ b.Append(lookupPrx.ToString());
+ b.Append('\n');
+ b.Append(ex.ToString());
+ throw new Ice.PluginInitializationException(b.ToString());
+ }
+
+ //
+ // Add lookup and lookup reply Ice objects
+ //
+ LookupI lookup = new LookupI(locatorRegistry, LookupPrxHelper.uncheckedCast(lookupPrx), properties);
+ _multicastAdapter.add(lookup, _communicator.stringToIdentity("IceDiscovery/Lookup"));
+
+ Ice.ObjectPrx lookupReply = _replyAdapter.addWithUUID(new LookupReplyI(lookup)).ice_datagram();
+ lookup.setLookupReply(LookupReplyPrxHelper.uncheckedCast(lookupReply));
+
+ //
+ // Setup locator on the communicator.
+ //
+ Ice.ObjectPrx loc;
+ loc = _locatorAdapter.addWithUUID(
+ new LocatorI(lookup, Ice.LocatorRegistryPrxHelper.uncheckedCast(locatorRegistryPrx)));
+ _communicator.setDefaultLocator(Ice.LocatorPrxHelper.uncheckedCast(loc));
+
+ _multicastAdapter.activate();
+ _replyAdapter.activate();
+ _locatorAdapter.activate();
+ }
+
+ public void destroy()
+ {
+ _multicastAdapter.destroy();
+ _replyAdapter.destroy();
+ _locatorAdapter.destroy();
+ }
+
+ private Ice.Communicator _communicator;
+ private Ice.ObjectAdapter _multicastAdapter;
+ private Ice.ObjectAdapter _replyAdapter;
+ private Ice.ObjectAdapter _locatorAdapter;
+ }
+
+} \ No newline at end of file
diff --git a/csharp/src/IceDiscovery/generated/.gitignore b/csharp/src/IceDiscovery/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/IceDiscovery/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/IceGrid/.depend.mak b/csharp/src/IceGrid/.depend.mak
new file mode 100644
index 00000000000..c88e67a088b
--- /dev/null
+++ b/csharp/src/IceGrid/.depend.mak
@@ -0,0 +1,92 @@
+
+Admin.cs: \
+ "$(slicedir)\IceGrid\Admin.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/Properties.ice" \
+ "$(slicedir)/Ice/PropertiesAdmin.ice" \
+ "$(slicedir)/Ice/SliceChecksumDict.ice" \
+ "$(slicedir)/Glacier2/Session.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice" \
+ "$(slicedir)/IceGrid/Exception.ice" \
+ "$(slicedir)/IceGrid/Descriptor.ice"
+
+Descriptor.cs: \
+ "$(slicedir)\IceGrid\Descriptor.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+Discovery.cs: \
+ "$(slicedir)\IceGrid\Discovery.ice" \
+ "$(slicedir)/IceGrid/Locator.ice" \
+ "$(slicedir)/Ice/Locator.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/ProcessF.ice"
+
+Exception.cs: \
+ "$(slicedir)\IceGrid\Exception.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+FileParser.cs: \
+ "$(slicedir)\IceGrid\FileParser.ice" \
+ "$(slicedir)/IceGrid/Admin.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/Properties.ice" \
+ "$(slicedir)/Ice/PropertiesAdmin.ice" \
+ "$(slicedir)/Ice/SliceChecksumDict.ice" \
+ "$(slicedir)/Glacier2/Session.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice" \
+ "$(slicedir)/IceGrid/Exception.ice" \
+ "$(slicedir)/IceGrid/Descriptor.ice"
+
+Locator.cs: \
+ "$(slicedir)\IceGrid\Locator.ice" \
+ "$(slicedir)/Ice/Locator.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/ProcessF.ice"
+
+Observer.cs: \
+ "$(slicedir)\IceGrid\Observer.ice" \
+ "$(slicedir)/Glacier2/Session.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice" \
+ "$(slicedir)/IceGrid/Exception.ice" \
+ "$(slicedir)/IceGrid/Descriptor.ice" \
+ "$(slicedir)/IceGrid/Admin.ice" \
+ "$(slicedir)/Ice/Properties.ice" \
+ "$(slicedir)/Ice/PropertiesAdmin.ice" \
+ "$(slicedir)/Ice/SliceChecksumDict.ice"
+
+Query.cs: \
+ "$(slicedir)\IceGrid\Query.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/IceGrid/Exception.ice"
+
+Registry.cs: \
+ "$(slicedir)\IceGrid\Registry.ice" \
+ "$(slicedir)/IceGrid/Exception.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/IceGrid/Session.ice" \
+ "$(slicedir)/Glacier2/Session.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice" \
+ "$(slicedir)/IceGrid/Admin.ice" \
+ "$(slicedir)/Ice/Properties.ice" \
+ "$(slicedir)/Ice/PropertiesAdmin.ice" \
+ "$(slicedir)/Ice/SliceChecksumDict.ice" \
+ "$(slicedir)/IceGrid/Descriptor.ice"
+
+Session.cs: \
+ "$(slicedir)\IceGrid\Session.ice" \
+ "$(slicedir)/Glacier2/Session.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Glacier2/SSLInfo.ice" \
+ "$(slicedir)/IceGrid/Exception.ice"
+
+UserAccountMapper.cs: \
+ "$(slicedir)\IceGrid\UserAccountMapper.ice"
diff --git a/csharp/src/IceGrid/AssemblyInfo.cs b/csharp/src/IceGrid/AssemblyInfo.cs
new file mode 100644
index 00000000000..55fe78eb54d
--- /dev/null
+++ b/csharp/src/IceGrid/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IceGrid")]
+[assembly: AssemblyDescription("IceGrid run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IceGrid for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IceGrid/Makefile b/csharp/src/IceGrid/Makefile
new file mode 100644
index 00000000000..ec40bcd8cb7
--- /dev/null
+++ b/csharp/src/IceGrid/Makefile
@@ -0,0 +1,55 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = IceGrid
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs
+
+SLICE_SRCS = $(SDIR)/Admin.ice \
+ $(SDIR)/Descriptor.ice \
+ $(SDIR)/Exception.ice \
+ $(SDIR)/FileParser.ice \
+ $(SDIR)/Locator.ice \
+ $(SDIR)/Observer.ice \
+ $(SDIR)/Query.ice \
+ $(SDIR)/Registry.ice \
+ $(SDIR)/Session.ice \
+ $(SDIR)/UserAccountMapper.ice
+
+SDIR = $(slicedir)/IceGrid
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(call ref,Glacier2) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/IceGrid/Makefile.mak b/csharp/src/IceGrid/Makefile.mak
new file mode 100644
index 00000000000..f76a1370602
--- /dev/null
+++ b/csharp/src/IceGrid/Makefile.mak
@@ -0,0 +1,60 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = IceGrid
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs
+
+GEN_SRCS = $(GDIR)\Admin.cs \
+ $(GDIR)\Descriptor.cs \
+ $(GDIR)\Exception.cs \
+ $(GDIR)\FileParser.cs \
+ $(GDIR)\Locator.cs \
+ $(GDIR)\Observer.cs \
+ $(GDIR)\Query.cs \
+ $(GDIR)\Registry.cs \
+ $(GDIR)\Session.cs \
+ $(GDIR)\UserAccountMapper.cs
+
+SDIR = $(slicedir)\IceGrid
+GDIR = generated
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) /baseaddress:0x24000000 $(MCSFLAGS) -r:$(refdir)\Glacier2.dll -r:$(refdir)\Ice.dll $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
diff --git a/csharp/src/IceGrid/generated/.gitignore b/csharp/src/IceGrid/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/IceGrid/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/IceLocatorDiscovery/AssemblyInfo.cs b/csharp/src/IceLocatorDiscovery/AssemblyInfo.cs
new file mode 100644
index 00000000000..0e758129db3
--- /dev/null
+++ b/csharp/src/IceLocatorDiscovery/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IceLocatorDiscovery")]
+[assembly: AssemblyDescription("IceLocatorDiscovery core run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IceLocatorDiscovery for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IceLocatorDiscovery/Makefile b/csharp/src/IceLocatorDiscovery/Makefile
new file mode 100644
index 00000000000..1499c9cd80e
--- /dev/null
+++ b/csharp/src/IceLocatorDiscovery/Makefile
@@ -0,0 +1,47 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = IceLocatorDiscovery
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs \
+ PluginI.cs
+
+SLICE_SRCS = $(SDIR)/IceLocatorDiscovery.ice
+
+SDIR = $(slicedir)/IceLocatorDiscovery
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/IceLocatorDiscovery/Makefile.mak b/csharp/src/IceLocatorDiscovery/Makefile.mak
new file mode 100644
index 00000000000..bd0a9f729d2
--- /dev/null
+++ b/csharp/src/IceLocatorDiscovery/Makefile.mak
@@ -0,0 +1,52 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = IceLocatorDiscovery
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs \
+ PluginI.cs
+
+GEN_SRCS = $(GDIR)\IceLocatorDiscovery.cs
+
+SDIR = $(slicedir)\IceLocatorDiscovery
+GDIR = generated
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) -r:$(refdir)\Ice.dll $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
diff --git a/csharp/src/IceLocatorDiscovery/PluginI.cs b/csharp/src/IceLocatorDiscovery/PluginI.cs
new file mode 100644
index 00000000000..ed000dc0d6c
--- /dev/null
+++ b/csharp/src/IceLocatorDiscovery/PluginI.cs
@@ -0,0 +1,422 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceLocatorDiscovery
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Text;
+
+ public sealed class PluginFactory : Ice.PluginFactory
+ {
+ public Ice.Plugin
+ create(Ice.Communicator communicator, string name, string[] args)
+ {
+ return new PluginI(communicator);
+ }
+ }
+
+ internal class Request
+ {
+ public Request(LocatorI locator,
+ string operation,
+ Ice.OperationMode mode,
+ byte[] inParams,
+ Dictionary<string, string> context,
+ Ice.AMD_Object_ice_invoke amdCB)
+ {
+ _locator = locator;
+ _operation = operation;
+ _mode = mode;
+ _inParams = inParams;
+ _context = context;
+ _amdCB = amdCB;
+ }
+
+ public void
+ invoke(Ice.LocatorPrx l)
+ {
+ _locatorPrx = l;
+ Request self = this;
+ l.begin_ice_invoke(_operation, _mode, _inParams, _context).whenCompleted(
+ (bool ok, byte[] outParams) =>
+ {
+ _amdCB.ice_response(ok, outParams);
+ },
+ (Ice.Exception ex) =>
+ {
+ try
+ {
+ throw ex;
+ }
+ catch(Ice.RequestFailedException exc)
+ {
+ _amdCB.ice_exception(exc);
+ }
+ catch(Ice.UnknownException exc)
+ {
+ _amdCB.ice_exception(exc);
+ }
+ catch(Ice.Exception)
+ {
+ _locator.invoke(_locatorPrx, self); // Retry with new locator proxy
+ }
+ });
+ }
+
+ private readonly LocatorI _locator;
+ private readonly string _operation;
+ private readonly Ice.OperationMode _mode;
+ private readonly Dictionary<string, string> _context;
+ private readonly byte[] _inParams;
+ private readonly Ice.AMD_Object_ice_invoke _amdCB;
+
+ private Ice.LocatorPrx _locatorPrx;
+ }
+
+ internal class VoidLocatorI : Ice.LocatorDisp_
+ {
+ public override void
+ findObjectById_async(Ice.AMD_Locator_findObjectById amdCB, Ice.Identity id, Ice.Current current)
+ {
+ amdCB.ice_response(null);
+ }
+
+ public override void
+ findAdapterById_async(Ice.AMD_Locator_findAdapterById amdCB, String id, Ice.Current current)
+ {
+ amdCB.ice_response(null);
+ }
+
+ public override Ice.LocatorRegistryPrx
+ getRegistry(Ice.Current current)
+ {
+ return null;
+ }
+ };
+
+ internal class LocatorI : Ice.BlobjectAsync, IceInternal.TimerTask
+ {
+ public
+ LocatorI(LookupPrx lookup, Ice.Properties properties, string instanceName, Ice.LocatorPrx voidLocator)
+ {
+ _lookup = lookup;
+ _timeout = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.Timeout", 300);
+ _retryCount = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.RetryCount", 3);
+ _retryDelay = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.RetryDelay", 2000);
+ _timer = IceInternal.Util.getInstance(lookup.ice_getCommunicator()).timer();
+ _instanceName = instanceName;
+ _warned = false;
+ _locator = lookup.ice_getCommunicator().getDefaultLocator();
+ _voidLocator = voidLocator;
+ _pendingRetryCount = 0;
+ }
+
+ public void
+ setLookupReply(LookupReplyPrx lookupReply)
+ {
+ _lookupReply = lookupReply;
+ }
+
+ public override void
+ ice_invoke_async(Ice.AMD_Object_ice_invoke amdCB, byte[] inParams, Ice.Current current)
+ {
+ lock(this)
+ {
+ invoke(null, new Request(this, current.operation, current.mode, inParams, current.ctx, amdCB));
+ }
+ }
+
+ public void
+ foundLocator(Ice.LocatorPrx locator)
+ {
+ lock(this)
+ {
+ if(locator == null ||
+ (_instanceName.Length > 0 && !locator.ice_getIdentity().category.Equals(_instanceName)))
+ {
+ return;
+ }
+
+ //
+ // If we already have a locator assigned, ensure the given locator
+ // has the same identity, otherwise ignore it.
+ //
+ if(_locator != null && !locator.ice_getIdentity().category.Equals(_locator.ice_getIdentity().category))
+ {
+ if(!_warned)
+ {
+ _warned = true; // Only warn once
+
+ locator.ice_getCommunicator().getLogger().warning(
+ "received Ice locator with different instance name:\n" +
+ "using = `" + _locator.ice_getIdentity().category + "'\n" +
+ "received = `" + locator.ice_getIdentity().category + "'\n" +
+ "This is typically the case if multiple Ice locators with different " +
+ "instance names are deployed and the property `IceLocatorDiscovery.InstanceName'" +
+ "is not set.");
+
+ }
+ return;
+ }
+
+ if(_pendingRetryCount > 0) // No need to retry, we found a locator
+ {
+ _timer.cancel(this);
+ _pendingRetryCount = 0;
+ }
+
+ if(_locator != null)
+ {
+ //
+ // We found another locator replica, append its endpoints to the
+ // current locator proxy endpoints.
+ //
+ List<Ice.Endpoint> newEndpoints = new List<Ice.Endpoint>(_locator.ice_getEndpoints());
+ foreach(Ice.Endpoint p in locator.ice_getEndpoints())
+ {
+ //
+ // Only add endpoints if not already in the locator proxy endpoints
+ //
+ bool found = false;
+ foreach(Ice.Endpoint q in newEndpoints)
+ {
+ if(p.Equals(q))
+ {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ newEndpoints.Add(p);
+ }
+ }
+ _locator = (Ice.LocatorPrx) _locator.ice_endpoints(newEndpoints.ToArray());
+ }
+ else
+ {
+ _locator = locator;
+ if(_instanceName.Length == 0)
+ {
+ _instanceName = _locator.ice_getIdentity().category; // Stick to the first locator
+ }
+ }
+
+ //
+ // Send pending requests if any.
+ //
+ foreach(Request req in _pendingRequests)
+ {
+ req.invoke(_locator);
+ }
+ _pendingRequests.Clear();
+ }
+ }
+
+ public void
+ invoke(Ice.LocatorPrx locator, Request request)
+ {
+ lock(this)
+ {
+ if(_locator != null && _locator != locator)
+ {
+ request.invoke(_locator);
+ }
+ else if(IceInternal.Time.currentMonotonicTimeMillis() < _nextRetry)
+ {
+ request.invoke(_voidLocator); // Don't retry to find a locator before the retry delay expires
+ }
+ else
+ {
+ _locator = null;
+
+ _pendingRequests.Add(request);
+
+ if(_pendingRetryCount == 0) // No request in progress
+ {
+ _pendingRetryCount = _retryCount;
+ _lookup.begin_findLocator(_instanceName, _lookupReply); // Send multicast request.
+ _timer.schedule(this, _timeout);
+ }
+ }
+ }
+ }
+
+ public void
+ runTimerTask()
+ {
+ lock(this)
+ {
+ if(--_pendingRetryCount > 0)
+ {
+ _lookup.begin_findLocator(_instanceName, _lookupReply); // Send multicast request
+ _timer.schedule(this, _timeout);
+ }
+ else
+ {
+ Debug.Assert(_pendingRequests.Count > 0, "Pending requests is not empty");
+ foreach(Request req in _pendingRequests)
+ {
+ req.invoke(_voidLocator);
+ }
+ _pendingRequests.Clear();
+ _nextRetry = IceInternal.Time.currentMonotonicTimeMillis() + _retryDelay;
+ }
+ }
+ }
+
+ private LookupPrx _lookup;
+ private int _timeout;
+ private IceInternal.Timer _timer;
+ private int _retryCount;
+ private int _retryDelay;
+
+ private string _instanceName;
+ private bool _warned;
+ private LookupReplyPrx _lookupReply;
+ private Ice.LocatorPrx _locator;
+ private Ice.LocatorPrx _voidLocator;
+
+ private int _pendingRetryCount;
+ private List<Request> _pendingRequests = new List<Request>();
+ private long _nextRetry;
+ };
+
+ internal class LookupReplyI : LookupReplyDisp_
+ {
+ public LookupReplyI(LocatorI locator)
+ {
+ _locator = locator;
+ }
+
+ public override void
+ foundLocator(Ice.LocatorPrx locator, Ice.Current current)
+ {
+ _locator.foundLocator(locator);
+ }
+
+ private LocatorI _locator;
+ }
+
+ class PluginI : Ice.Plugin
+ {
+ public
+ PluginI(Ice.Communicator communicator)
+ {
+ _communicator = communicator;
+ }
+
+ public void
+ initialize()
+ {
+ Ice.Properties properties = _communicator.getProperties();
+
+ bool ipv4 = properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0;
+ bool preferIPv6 = properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0;
+ string address;
+ if(ipv4 && !preferIPv6)
+ {
+ address = properties.getPropertyWithDefault("IceLocatorDiscovery.Address", "239.255.0.1");
+ }
+ else
+ {
+ address = properties.getPropertyWithDefault("IceLocatorDiscovery.Address", "ff15::1");
+ }
+ int port = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.Port", 4061);
+ string intf = properties.getProperty("IceLocatorDiscovery.Interface");
+
+ if(properties.getProperty("IceLocatorDiscovery.Reply.Endpoints").Length == 0)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("udp");
+ if(intf.Length > 0)
+ {
+ s.Append(" -h \"");
+ s.Append(intf);
+ s.Append("\"");
+ }
+ properties.setProperty("IceLocatorDiscovery.Reply.Endpoints", s.ToString());
+ }
+ if(properties.getProperty("IceLocatorDiscovery.Locator.Endpoints").Length == 0)
+ {
+ properties.setProperty("IceLocatorDiscovery.Locator.AdapterId", Guid.NewGuid().ToString());
+ }
+
+ _replyAdapter = _communicator.createObjectAdapter("IceLocatorDiscovery.Reply");
+ _locatorAdapter = _communicator.createObjectAdapter("IceLocatorDiscovery.Locator");
+
+ // We don't want those adapters to be registered with the locator so clear their locator.
+ _replyAdapter.setLocator(null);
+ _locatorAdapter.setLocator(null);
+
+ string lookupEndpoints = properties.getProperty("IceLocatorDiscovery.Lookup");
+ if(lookupEndpoints.Length == 0)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("udp -h \"");
+ s.Append(address);
+ s.Append("\" -p ");
+ s.Append(port);
+ if(intf.Length > 0)
+ {
+ s.Append(" --interface \"");
+ s.Append(intf);
+ s.Append("\"");
+ }
+ lookupEndpoints = s.ToString();
+ }
+
+ Ice.ObjectPrx lookupPrx = _communicator.stringToProxy("IceLocatorDiscovery/Lookup -d:" + lookupEndpoints);
+ lookupPrx = lookupPrx.ice_collocationOptimized(false); // No colloc optimization for the multicast proxy!
+ try
+ {
+ lookupPrx.ice_getConnection(); // Ensure we can establish a connection to the multicast proxy
+ }
+ catch (Ice.LocalException ex)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("unable to establish multicast connection, Ice locator discovery will be disabled:\n");
+ s.Append("proxy = ");
+ s.Append(lookupPrx.ToString());
+ s.Append("\n");
+ s.Append(ex);
+ throw new Ice.PluginInitializationException(s.ToString());
+ }
+
+ Ice.LocatorPrx voidLo = Ice.LocatorPrxHelper.uncheckedCast(_locatorAdapter.addWithUUID(new VoidLocatorI()));
+
+ string instanceName = properties.getProperty("IceLocatorDiscovery.InstanceName");
+ Ice.Identity id = new Ice.Identity();
+ id.name = "Locator";
+ id.category = instanceName.Length > 0 ? instanceName : Guid.NewGuid().ToString();
+
+ LocatorI locator = new LocatorI(LookupPrxHelper.uncheckedCast(lookupPrx), properties, instanceName, voidLo);
+ _communicator.setDefaultLocator(Ice.LocatorPrxHelper.uncheckedCast(_locatorAdapter.addWithUUID(locator)));
+
+ Ice.ObjectPrx lookupReply = _replyAdapter.addWithUUID(new LookupReplyI(locator)).ice_datagram();
+ locator.setLookupReply(LookupReplyPrxHelper.uncheckedCast(lookupReply));
+
+ _replyAdapter.activate();
+ _locatorAdapter.activate();
+ }
+
+ public void
+ destroy()
+ {
+ _replyAdapter.destroy();
+ _locatorAdapter.destroy();
+ }
+
+ private Ice.Communicator _communicator;
+ private Ice.ObjectAdapter _locatorAdapter;
+ private Ice.ObjectAdapter _replyAdapter;
+ }
+}
diff --git a/csharp/src/IceLocatorDiscovery/generated/.gitignore b/csharp/src/IceLocatorDiscovery/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/IceLocatorDiscovery/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/IcePatch2/.depend.mak b/csharp/src/IcePatch2/.depend.mak
new file mode 100644
index 00000000000..c73ea5657cb
--- /dev/null
+++ b/csharp/src/IcePatch2/.depend.mak
@@ -0,0 +1,9 @@
+
+FileInfo.cs: \
+ "$(slicedir)\IcePatch2\FileInfo.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+FileServer.cs: \
+ "$(slicedir)\IcePatch2\FileServer.ice" \
+ "$(slicedir)/IcePatch2/FileInfo.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
diff --git a/csharp/src/IcePatch2/AssemblyInfo.cs b/csharp/src/IcePatch2/AssemblyInfo.cs
new file mode 100644
index 00000000000..8556d48518e
--- /dev/null
+++ b/csharp/src/IcePatch2/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IcePatch2")]
+[assembly: AssemblyDescription("IcePatch2 run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IcePatch2 for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IcePatch2/Makefile b/csharp/src/IcePatch2/Makefile
new file mode 100644
index 00000000000..4b64dab84df
--- /dev/null
+++ b/csharp/src/IcePatch2/Makefile
@@ -0,0 +1,47 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = IcePatch2
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs
+
+SLICE_SRCS = $(SDIR)/FileInfo.ice \
+ $(SDIR)/FileServer.ice
+
+SDIR = $(slicedir)/IcePatch2
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) -I$(slicedir) --ice
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/IcePatch2/Makefile.mak b/csharp/src/IcePatch2/Makefile.mak
new file mode 100644
index 00000000000..2dd8c822309
--- /dev/null
+++ b/csharp/src/IcePatch2/Makefile.mak
@@ -0,0 +1,52 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = IcePatch2
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs
+
+GEN_SRCS = $(GDIR)\FileInfo.cs \
+ $(GDIR)\FileServer.cs
+
+SDIR = $(slicedir)\IcePatch2
+GDIR = generated
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) -I$(slicedir) --ice
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) /baseaddress:0x23000000 $(MCSFLAGS) -r:$(refdir)\Ice.dll $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
diff --git a/csharp/src/IcePatch2/generated/.gitignore b/csharp/src/IcePatch2/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/IcePatch2/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/IceSSL/.depend.mak b/csharp/src/IceSSL/.depend.mak
new file mode 100644
index 00000000000..96f75256468
--- /dev/null
+++ b/csharp/src/IceSSL/.depend.mak
@@ -0,0 +1,17 @@
+
+ConnectionInfo.cs: \
+ "$(slicedir)\IceSSL\ConnectionInfo.ice" \
+ "$(slicedir)/Ice/Connection.ice" \
+ "$(slicedir)/Ice/ObjectAdapterF.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/Endpoint.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/EndpointF.ice"
+
+EndpointInfo.cs: \
+ "$(slicedir)\IceSSL\EndpointInfo.ice" \
+ "$(slicedir)/Ice/Endpoint.ice" \
+ "$(slicedir)/Ice/Version.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice" \
+ "$(slicedir)/Ice/EndpointF.ice"
diff --git a/csharp/src/IceSSL/AcceptorI.cs b/csharp/src/IceSSL/AcceptorI.cs
new file mode 100644
index 00000000000..5ddc84ff337
--- /dev/null
+++ b/csharp/src/IceSSL/AcceptorI.cs
@@ -0,0 +1,201 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Net;
+ using System.Net.Security;
+ using System.Net.Sockets;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Text;
+
+ class AcceptorI : IceInternal.Acceptor
+ {
+ public void close()
+ {
+ Debug.Assert(_acceptFd == null);
+ if(_fd != null)
+ {
+ IceInternal.Network.closeSocketNoThrow(_fd);
+ _fd = null;
+ }
+ }
+
+ public IceInternal.EndpointI listen()
+ {
+ try
+ {
+ _addr = IceInternal.Network.doBind(_fd, _addr);
+ IceInternal.Network.doListen(_fd, _backlog);
+ }
+ catch(SystemException)
+ {
+ _fd = null;
+ throw;
+ }
+ _endpoint = _endpoint.endpoint(this);
+ return _endpoint;
+ }
+
+ public bool startAccept(IceInternal.AsyncCallback callback, object state)
+ {
+ //
+ // The plug-in may not be fully initialized.
+ //
+ if(!_instance.initialized())
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: plug-in is not initialized";
+ throw ex;
+ }
+
+ try
+ {
+ _result = _fd.BeginAccept(delegate(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ callback(result.AsyncState);
+ }
+ }, state);
+ return _result.CompletedSynchronously;
+ }
+ catch(SocketException ex)
+ {
+ throw new Ice.SocketException(ex);
+ }
+ }
+
+ public void finishAccept()
+ {
+ if(_fd != null)
+ {
+ Debug.Assert(_result != null);
+ try
+ {
+ _acceptFd = _fd.EndAccept(_result);
+ _result = null;
+ }
+ catch(SocketException ex)
+ {
+ _acceptError = ex;
+ }
+ }
+ }
+
+ public IceInternal.Transceiver accept()
+ {
+ if(_acceptFd == null)
+ {
+ throw _acceptError;
+ }
+
+ Socket acceptFd = _acceptFd;
+ _acceptFd = null;
+ _acceptError = null;
+ return new TransceiverI(_instance, new IceInternal.StreamSocket(_instance, acceptFd), _adapterName, true);
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public override string ToString()
+ {
+ return IceInternal.Network.addrToString(_addr);
+ }
+
+ public string toDetailedString()
+ {
+ StringBuilder s = new StringBuilder("local address = ");
+ s.Append(ToString());
+
+ List<string> intfs = IceInternal.Network.getHostsForEndpointExpand(_addr.Address.ToString(),
+ _instance.protocolSupport(),
+ true);
+ if(intfs.Count != 0)
+ {
+ s.Append("\nlocal interfaces = ");
+ s.Append(String.Join(", ", intfs.ToArray()));
+ }
+ return s.ToString();
+ }
+
+ internal int effectivePort()
+ {
+ return _addr.Port;
+ }
+
+ internal AcceptorI(EndpointI endpoint, Instance instance, string adapterName, string host, int port)
+ {
+ _endpoint = endpoint;
+ _instance = instance;
+ _adapterName = adapterName;
+ _backlog = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.Backlog", 511);
+
+ //
+ // .NET requires that a certificate be supplied.
+ //
+ X509Certificate2Collection certs = instance.certs();
+ if(certs.Count == 0)
+ {
+ Ice.SecurityException ex = new Ice.SecurityException();
+ ex.reason = "IceSSL: certificate required for server endpoint";
+ throw ex;
+ }
+
+ try
+ {
+ int protocol = instance.protocolSupport();
+ _addr = IceInternal.Network.getAddressForServer(host, port, protocol, instance.preferIPv6()) as
+ IPEndPoint;
+ _fd = IceInternal.Network.createServerSocket(false, _addr.AddressFamily, protocol);
+ IceInternal.Network.setBlock(_fd, false);
+ IceInternal.Network.setTcpBufSize(_fd, _instance);
+ if(IceInternal.AssemblyUtil.platform_ != IceInternal.AssemblyUtil.Platform.Windows)
+ {
+ //
+ // Enable SO_REUSEADDR on Unix platforms to allow
+ // re-using the socket even if it's in the TIME_WAIT
+ // state. On Windows, this doesn't appear to be
+ // necessary and enabling SO_REUSEADDR would actually
+ // not be a good thing since it allows a second
+ // process to bind to an address even it's already
+ // bound by another process.
+ //
+ // TODO: using SO_EXCLUSIVEADDRUSE on Windows would
+ // probably be better but it's only supported by recent
+ // Windows versions (XP SP2, Windows Server 2003).
+ //
+ IceInternal.Network.setReuseAddress(_fd, true);
+ }
+ }
+ catch(System.Exception)
+ {
+ _fd = null;
+ throw;
+ }
+ }
+
+ private EndpointI _endpoint;
+ private Instance _instance;
+ private string _adapterName;
+ private Socket _fd;
+ private Socket _acceptFd;
+ private System.Exception _acceptError;
+ private int _backlog;
+ private IPEndPoint _addr;
+ private IAsyncResult _result;
+ }
+}
diff --git a/csharp/src/IceSSL/AssemblyInfo.cs b/csharp/src/IceSSL/AssemblyInfo.cs
new file mode 100644
index 00000000000..f75487dc2b1
--- /dev/null
+++ b/csharp/src/IceSSL/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IceSSL")]
+[assembly: AssemblyDescription("IceSSL run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IceSSL for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IceSSL/ConnectorI.cs b/csharp/src/IceSSL/ConnectorI.cs
new file mode 100644
index 00000000000..7c8a7f4becb
--- /dev/null
+++ b/csharp/src/IceSSL/ConnectorI.cs
@@ -0,0 +1,115 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Net;
+ using System.Net.Sockets;
+
+ sealed class ConnectorI : IceInternal.Connector
+ {
+ public IceInternal.Transceiver connect()
+ {
+ //
+ // The plug-in may not be fully initialized.
+ //
+ if(!_instance.initialized())
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: plug-in is not initialized";
+ throw ex;
+ }
+
+ return new TransceiverI(_instance, new IceInternal.StreamSocket(_instance, _proxy, _addr, _sourceAddr),
+ _host, false);
+ }
+
+ public short type()
+ {
+ return _instance.type();
+ }
+
+ //
+ // Only for use by EndpointI.
+ //
+ internal ConnectorI(Instance instance, string host, EndPoint addr, IceInternal.NetworkProxy proxy,
+ EndPoint sourceAddr, int timeout, string conId)
+ {
+ _instance = instance;
+ _host = host;
+ _addr = (IPEndPoint)addr;
+ _proxy = proxy;
+ _sourceAddr = sourceAddr;
+ _timeout = timeout;
+ _connectionId = conId;
+
+ _hashCode = 5381;
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _addr);
+ if(_sourceAddr != null)
+ {
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _sourceAddr);
+ }
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _timeout);
+ IceInternal.HashUtil.hashAdd(ref _hashCode, _connectionId);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(!(obj is ConnectorI))
+ {
+ return false;
+ }
+
+ if(this == obj)
+ {
+ return true;
+ }
+
+ ConnectorI p = (ConnectorI)obj;
+ if(_timeout != p._timeout)
+ {
+ return false;
+ }
+
+ if(!_connectionId.Equals(p._connectionId))
+ {
+ return false;
+ }
+
+ if(!IceInternal.Network.addressEquals(_sourceAddr, p._sourceAddr))
+ {
+ return false;
+ }
+
+ return _addr.Equals(p._addr);
+ }
+
+ public override string ToString()
+ {
+ return IceInternal.Network.addrToString(_proxy == null ? _addr : _proxy.getAddress());
+ }
+
+ public override int GetHashCode()
+ {
+ return _hashCode;
+ }
+
+ private Instance _instance;
+ private string _host;
+ private IPEndPoint _addr;
+ private IceInternal.NetworkProxy _proxy;
+ private EndPoint _sourceAddr;
+ private int _timeout;
+ private string _connectionId;
+ private int _hashCode;
+ }
+}
diff --git a/csharp/src/IceSSL/EndpointI.cs b/csharp/src/IceSSL/EndpointI.cs
new file mode 100644
index 00000000000..edc04dd09d9
--- /dev/null
+++ b/csharp/src/IceSSL/EndpointI.cs
@@ -0,0 +1,370 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.Diagnostics;
+ using System.Collections.Generic;
+ using System.Net;
+ using System.Globalization;
+
+ sealed class EndpointI : IceInternal.IPEndpointI
+ {
+ internal EndpointI(Instance instance, string ho, int po, EndPoint sourceAddr, int ti, string conId, bool co) :
+ base(instance, ho, po, sourceAddr, conId)
+ {
+ _instance = instance;
+ _timeout = ti;
+ _compress = co;
+ }
+
+ internal EndpointI(Instance instance) :
+ base(instance)
+ {
+ _instance = instance;
+ _timeout = instance.defaultTimeout();
+ _compress = false;
+ }
+
+ internal EndpointI(Instance instance, IceInternal.BasicStream s) :
+ base(instance, s)
+ {
+ _instance = instance;
+ _timeout = s.readInt();
+ _compress = s.readBool();
+ }
+
+ private sealed class InfoI : IceSSL.EndpointInfo
+ {
+ public InfoI(EndpointI e)
+ {
+ _endpoint = e;
+ }
+
+ override public short type()
+ {
+ return _endpoint.type();
+ }
+
+ override public bool datagram()
+ {
+ return _endpoint.datagram();
+ }
+
+ override public bool secure()
+ {
+ return _endpoint.secure();
+ }
+
+ private EndpointI _endpoint;
+ }
+
+ //
+ // Return the endpoint information.
+ //
+ public override Ice.EndpointInfo getInfo()
+ {
+ InfoI info = new InfoI(this);
+ fillEndpointInfo(info);
+ return info;
+ }
+
+ //
+ // Return the timeout for the endpoint in milliseconds. 0 means
+ // non-blocking, -1 means no timeout.
+ //
+ public override int timeout()
+ {
+ return _timeout;
+ }
+
+ //
+ // Return a new endpoint with a different timeout value, provided
+ // that timeouts are supported by the endpoint. Otherwise the same
+ // endpoint is returned.
+ //
+ public override IceInternal.EndpointI timeout(int timeout)
+ {
+ if(timeout == _timeout)
+ {
+ return this;
+ }
+ else
+ {
+ return new EndpointI(_instance, host_, port_, sourceAddr_, timeout, connectionId_, _compress);
+ }
+ }
+
+ //
+ // Return true if the endpoints support bzip2 compress, or false
+ // otherwise.
+ //
+ public override bool compress()
+ {
+ return _compress;
+ }
+
+ //
+ // Return a new endpoint with a different compression value,
+ // provided that compression is supported by the
+ // endpoint. Otherwise the same endpoint is returned.
+ //
+ public override IceInternal.EndpointI compress(bool compress)
+ {
+ if(compress == _compress)
+ {
+ return this;
+ }
+ else
+ {
+ return new EndpointI(_instance, host_, port_, sourceAddr_, _timeout, connectionId_, compress);
+ }
+ }
+
+ //
+ // Return true if the endpoint is datagram-based.
+ //
+ public override bool datagram()
+ {
+ return false;
+ }
+
+ //
+ // Return a server side transceiver for this endpoint, or null if a
+ // transceiver can only be created by an acceptor.
+ //
+ public override IceInternal.Transceiver transceiver()
+ {
+ return null;
+ }
+
+ //
+ // Return an acceptor for this endpoint, or null if no acceptor
+ // is available.
+ //
+ public override IceInternal.Acceptor acceptor(string adapterName)
+ {
+ return new AcceptorI(this, _instance, adapterName, host_, port_);
+ }
+
+ public EndpointI endpoint(AcceptorI acceptor)
+ {
+ return new EndpointI(_instance, host_, acceptor.effectivePort(), sourceAddr_, _timeout, connectionId_,
+ _compress);
+ }
+
+ public override string options()
+ {
+ //
+ // WARNING: Certain features, such as proxy validation in Glacier2,
+ // depend on the format of proxy strings. Changes to toString() and
+ // methods called to generate parts of the reference string could break
+ // these features. Please review for all features that depend on the
+ // format of proxyToString() before changing this and related code.
+ //
+ string s = base.options();
+
+ if(_timeout == -1)
+ {
+ s += " -t infinite";
+ }
+ else
+ {
+ s += " -t " + _timeout;
+ }
+
+ if(_compress)
+ {
+ s += " -z";
+ }
+
+ return s;
+ }
+
+ //
+ // Compare endpoints for sorting purposes
+ //
+ public override int CompareTo(IceInternal.EndpointI obj)
+ {
+ if(!(obj is EndpointI))
+ {
+ return type() < obj.type() ? -1 : 1;
+ }
+
+ EndpointI p = (EndpointI)obj;
+ if(this == p)
+ {
+ return 0;
+ }
+
+ if(_timeout < p._timeout)
+ {
+ return -1;
+ }
+ else if(p._timeout < _timeout)
+ {
+ return 1;
+ }
+
+ if(!_compress && p._compress)
+ {
+ return -1;
+ }
+ else if(!p._compress && _compress)
+ {
+ return 1;
+ }
+
+ return base.CompareTo(p);
+ }
+
+ public override void streamWriteImpl(IceInternal.BasicStream s)
+ {
+ base.streamWriteImpl(s);
+ s.writeInt(_timeout);
+ s.writeBool(_compress);
+ }
+
+ public override void hashInit(ref int h)
+ {
+ base.hashInit(ref h);
+ IceInternal.HashUtil.hashAdd(ref h, _timeout);
+ IceInternal.HashUtil.hashAdd(ref h, _compress);
+ }
+
+ public override void fillEndpointInfo(Ice.IPEndpointInfo info)
+ {
+ base.fillEndpointInfo(info);
+ info.timeout = _timeout;
+ info.compress = _compress;
+ }
+
+ protected override bool checkOption(string option, string argument, string endpoint)
+ {
+ if(base.checkOption(option, argument, endpoint))
+ {
+ return true;
+ }
+
+ switch(option[1])
+ {
+ case 't':
+ {
+ if(argument == null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "no argument provided for -t option in endpoint " + endpoint;
+ throw e;
+ }
+
+ if(argument.Equals("infinite"))
+ {
+ _timeout = -1;
+ }
+ else
+ {
+ try
+ {
+ _timeout = System.Int32.Parse(argument, CultureInfo.InvariantCulture);
+ if(_timeout < 1)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "invalid timeout value `" + argument + "' in endpoint " + endpoint;
+ throw e;
+ }
+ }
+ catch(System.FormatException ex)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException(ex);
+ e.str = "invalid timeout value `" + argument + "' in endpoint " + endpoint;
+ throw e;
+ }
+ }
+
+ return true;
+ }
+
+ case 'z':
+ {
+ if(argument != null)
+ {
+ Ice.EndpointParseException e = new Ice.EndpointParseException();
+ e.str = "unexpected argument `" + argument + "' provided for -z option in " + endpoint;
+ throw e;
+ }
+
+ _compress = true;
+ return true;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
+ protected override IceInternal.Connector createConnector(EndPoint addr, IceInternal.NetworkProxy proxy)
+ {
+ return new ConnectorI(_instance, host_, addr, proxy, sourceAddr_, _timeout, connectionId_);
+ }
+
+ protected override IceInternal.IPEndpointI createEndpoint(string host, int port, string connectionId)
+ {
+ return new EndpointI(_instance, host, port, sourceAddr_, _timeout, connectionId, _compress);
+ }
+
+ private Instance _instance;
+ private int _timeout;
+ private bool _compress;
+ }
+
+ internal sealed class EndpointFactoryI : IceInternal.EndpointFactory
+ {
+ internal EndpointFactoryI(Instance instance)
+ {
+ _instance = instance;
+ }
+
+ public short type()
+ {
+ return _instance.type();
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public IceInternal.EndpointI create(List<string> args, bool oaEndpoint)
+ {
+ IceInternal.IPEndpointI endpt = new EndpointI(_instance);
+ endpt.initWithOptions(args, oaEndpoint);
+ return endpt;
+ }
+
+ public IceInternal.EndpointI read(IceInternal.BasicStream s)
+ {
+ return new EndpointI(_instance, s);
+ }
+
+ public void destroy()
+ {
+ _instance = null;
+ }
+
+ public IceInternal.EndpointFactory clone(IceInternal.ProtocolInstance instance)
+ {
+ return new EndpointFactoryI(new Instance(_instance.engine(), instance.type(), instance.protocol()));
+ }
+
+ private Instance _instance;
+ }
+}
diff --git a/csharp/src/IceSSL/Instance.cs b/csharp/src/IceSSL/Instance.cs
new file mode 100644
index 00000000000..79b18435268
--- /dev/null
+++ b/csharp/src/IceSSL/Instance.cs
@@ -0,0 +1,78 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Security;
+ using System.Security.Authentication;
+ using System.Security.Cryptography;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Text;
+ using System.Globalization;
+
+ internal class Instance : IceInternal.ProtocolInstance
+ {
+ internal Instance(SSLEngine engine, short type, string protocol) :
+ base(engine.communicator(), type, protocol, true)
+ {
+ _engine = engine;
+ }
+
+ internal SSLEngine engine()
+ {
+ return _engine;
+ }
+
+ internal int securityTraceLevel()
+ {
+ return _engine.securityTraceLevel();
+ }
+
+ internal string securityTraceCategory()
+ {
+ return _engine.securityTraceCategory();
+ }
+
+ internal bool initialized()
+ {
+ return _engine.initialized();
+ }
+
+ internal X509Certificate2Collection certs()
+ {
+ return _engine.certs();
+ }
+
+ internal SslProtocols protocols()
+ {
+ return _engine.protocols();
+ }
+
+ internal int checkCRL()
+ {
+ return _engine.checkCRL();
+ }
+
+ internal void traceStream(System.Net.Security.SslStream stream, string connInfo)
+ {
+ _engine.traceStream(stream, connInfo);
+ }
+
+ internal void verifyPeer(NativeConnectionInfo info, System.Net.Sockets.Socket fd, string address)
+ {
+ _engine.verifyPeer(info, fd, address);
+ }
+
+ private SSLEngine _engine;
+ }
+}
diff --git a/csharp/src/IceSSL/Makefile b/csharp/src/IceSSL/Makefile
new file mode 100644
index 00000000000..0dd6b3cdd24
--- /dev/null
+++ b/csharp/src/IceSSL/Makefile
@@ -0,0 +1,59 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = IceSSL
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AcceptorI.cs \
+ AssemblyInfo.cs \
+ ConnectorI.cs \
+ EndpointI.cs \
+ Instance.cs \
+ Plugin.cs \
+ PluginI.cs \
+ RFC2253.cs \
+ SSLEngine.cs \
+ TransceiverI.cs \
+ TrustManager.cs \
+ Util.cs
+
+SLICE_SRCS = $(SDIR)/ConnectionInfo.ice \
+ $(SDIR)/EndpointInfo.ice
+
+
+SDIR = $(slicedir)/IceSSL
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/IceSSL/Makefile.mak b/csharp/src/IceSSL/Makefile.mak
new file mode 100644
index 00000000000..776891d49c1
--- /dev/null
+++ b/csharp/src/IceSSL/Makefile.mak
@@ -0,0 +1,64 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = IceSSL
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AcceptorI.cs \
+ AssemblyInfo.cs \
+ ConnectorI.cs \
+ EndpointI.cs \
+ Instance.cs \
+ Plugin.cs \
+ PluginI.cs \
+ RFC2253.cs \
+ SSLEngine.cs \
+ TransceiverI.cs \
+ TrustManager.cs \
+ Util.cs
+
+GEN_SRCS = $(GDIR)\ConnectionInfo.cs\
+ $(GDIR)\EndpointInfo.cs
+
+
+SDIR = $(slicedir)\IceSSL
+GDIR = generated
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) --ice -I$(slicedir)
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) -r:$(refdir)\Ice.dll $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
diff --git a/csharp/src/IceSSL/Plugin.cs b/csharp/src/IceSSL/Plugin.cs
new file mode 100644
index 00000000000..89575747441
--- /dev/null
+++ b/csharp/src/IceSSL/Plugin.cs
@@ -0,0 +1,114 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System.Security;
+ using System.Security.Cryptography.X509Certificates;
+
+ //
+ // An application can customize the certificate verification process
+ // by implementing the CertificateVerifier interface.
+ //
+ public interface CertificateVerifier
+ {
+ //
+ // Return true to allow a connection using the provided certificate
+ // information, or false to reject the connection.
+ //
+ bool verify(NativeConnectionInfo info);
+ }
+
+ /// <summary>
+ /// A password callback is an alternate way of supplying the plug-in with
+ /// passwords; this avoids using plain text configuration properties.
+ /// </summary>
+ public interface PasswordCallback
+ {
+ /// <summary>
+ /// Obtain the password necessary to access the private key associated with
+ /// the certificate in the given file.
+ /// <param name="file">The certificate file name.</param>
+ /// <returns>The password for the key or null, if no password is necessary.</returns>
+ /// </summary>
+ SecureString getPassword(string file);
+
+ /// <summary>
+ /// Obtain a password for a certificate being imported via an IceSSL.ImportCert
+ /// property. Return null if no password is necessary.
+ /// </summary>
+ /// <param name="file">The certificate file name.</param>
+ /// <returns>The password for the key or null, if no password is necessary.</returns>
+ SecureString getImportPassword(string file);
+ }
+
+ /// <summary>
+ /// Interface that allows applications to interact with the IceSSL plug-in.
+ /// </summary>
+ abstract public class Plugin : Ice.Plugin
+ {
+ abstract public void initialize();
+
+ /// <summary>
+ /// Specify the certificate authorities certificates to use
+ /// when validating SSL peer certificates. This must be done
+ /// before the plug-in is initialized; therefore, the application
+ /// must define the property Ice.InitPlugins=0, set the certificates,
+ /// and finally invoke initializePlugins on the PluginManager.
+ /// When the application supplies its own certificate authorities
+ /// certificates, the plug-in skips its normal property-based
+ /// configuration.
+ /// </summary>
+ /// <param name="certs">The certificate authorities certificates to use.</param>
+ abstract public void setCACertificates(X509Certificate2Collection certs);
+
+ /// <summary>
+ /// Specify the certificates to use for SSL connections. This
+ /// must be done before the plug-in is initialized; therefore,
+ /// the application must define the property Ice.InitPlugins=0,
+ /// set the certificates, and finally invoke initializePlugins
+ /// on the PluginManager.
+ /// When the application supplies its own certificates, the
+ /// plug-in skips its normal property-based configuration.
+ /// </summary>
+ /// <param name="certs">The certificates to use for SSL connections.</param>
+ abstract public void setCertificates(X509Certificate2Collection certs);
+
+ /// <summary>
+ /// Establish the certificate verifier object. This must be
+ /// done before any connections are established.
+ /// </summary>
+ /// <param name="verifier">The certificate verifier.</param>
+ abstract public void setCertificateVerifier(CertificateVerifier verifier);
+
+ /// <summary>
+ /// Obtain the certificate verifier object.
+ /// </summary>
+ /// <returns>The certificate verifier (null if not set).</returns>
+ abstract public CertificateVerifier getCertificateVerifier();
+
+ /// <summary>
+ /// Establish the password callback object. This must be
+ /// done before the plug-in is initialized.
+ /// </summary>
+ /// <param name="callback">The password callback.</param>
+ abstract public void setPasswordCallback(PasswordCallback callback);
+
+ /// <summary>
+ /// Returns the password callback.
+ /// </summary>
+ /// <returns>The password callback (null if not set).</returns>
+ abstract public PasswordCallback getPasswordCallback();
+
+ /// <summary>
+ /// This method is for internal use.
+ /// </summary>
+ abstract public void destroy();
+ }
+}
diff --git a/csharp/src/IceSSL/PluginI.cs b/csharp/src/IceSSL/PluginI.cs
new file mode 100644
index 00000000000..cbe540123fb
--- /dev/null
+++ b/csharp/src/IceSSL/PluginI.cs
@@ -0,0 +1,93 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System.Security.Cryptography.X509Certificates;
+
+namespace IceSSL
+{
+ /// <summary>
+ /// Plug-in factories must implement this interface.
+ /// </summary>
+ public sealed class PluginFactory : Ice.PluginFactory
+ {
+ /// <summary>
+ /// Returns a new plug-in.
+ /// </summary>
+ /// <param name="communicator">The communicator for the plug-in.</param>
+ /// <param name="name">The name of the plug-in.</param>
+ /// <param name="args">The arguments that are specified in the plug-in's configuration.</param>
+ ///
+ /// <returns>The new plug-in. null can be returned to indicate
+ /// that a general error occurred. Alternatively, create can throw
+ /// PluginInitializationException to provide more detailed information.</returns>
+ public Ice.Plugin create(Ice.Communicator communicator, string name, string[] args)
+ {
+ return new PluginI(communicator);
+ }
+ }
+
+ public sealed class PluginI : Plugin
+ {
+ public PluginI(Ice.Communicator communicator)
+ {
+ IceInternal.ProtocolPluginFacade facade = IceInternal.Util.getProtocolPluginFacade(communicator);
+
+ _engine = new SSLEngine(facade);
+
+ //
+ // Register the endpoint factory. We have to do this now, rather than
+ // in initialize, because the communicator may need to interpret
+ // proxies before the plug-in is fully initialized.
+ //
+ EndpointFactoryI factory = new EndpointFactoryI(new Instance(_engine, IceSSL.EndpointType.value, "ssl"));
+ facade.addEndpointFactory(factory);
+ }
+
+ public override void initialize()
+ {
+ _engine.initialize();
+ }
+
+ public override void destroy()
+ {
+ }
+
+ public override void setCACertificates(X509Certificate2Collection certs)
+ {
+ _engine.setCACertificates(certs);
+ }
+
+ public override void setCertificates(X509Certificate2Collection certs)
+ {
+ _engine.setCertificates(certs);
+ }
+
+ public override void setCertificateVerifier(CertificateVerifier verifier)
+ {
+ _engine.setCertificateVerifier(verifier);
+ }
+
+ public override CertificateVerifier getCertificateVerifier()
+ {
+ return _engine.getCertificateVerifier();
+ }
+
+ public override void setPasswordCallback(PasswordCallback callback)
+ {
+ _engine.setPasswordCallback(callback);
+ }
+
+ public override PasswordCallback getPasswordCallback()
+ {
+ return _engine.getPasswordCallback();
+ }
+
+ private SSLEngine _engine;
+ }
+}
diff --git a/csharp/src/IceSSL/RFC2253.cs b/csharp/src/IceSSL/RFC2253.cs
new file mode 100644
index 00000000000..117ece7c955
--- /dev/null
+++ b/csharp/src/IceSSL/RFC2253.cs
@@ -0,0 +1,504 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+//
+// See RFC 2253 and RFC 1779.
+//
+namespace IceSSL
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Text;
+
+ class RFC2253
+ {
+ internal class ParseException : System.Exception
+ {
+ internal ParseException()
+ {
+ }
+
+ internal ParseException(string reason)
+ {
+ this.reason = reason;
+ }
+
+ internal string
+ ice_name()
+ {
+ return "RFC2253::ParseException";
+ }
+
+ internal string reason;
+ }
+
+ internal struct RDNPair
+ {
+ internal string key;
+ internal string value;
+ }
+
+ internal class RDNEntry
+ {
+ internal List<RDNPair> rdn = new List<RDNPair>();
+ internal bool negate = false;
+ }
+
+ internal static List<RDNEntry> parse(string data)
+ {
+ List<RDNEntry> results = new List<RDNEntry>();
+ RDNEntry current = new RDNEntry();
+ int pos = 0;
+ while(pos < data.Length)
+ {
+ eatWhite(data, ref pos);
+ if(pos < data.Length && data[pos] == '!')
+ {
+ if(current.rdn.Count > 0)
+ {
+ throw new ParseException("negation symbol '!' must appear at start of list");
+ }
+ ++pos;
+ current.negate = true;
+ }
+ current.rdn.Add(parseNameComponent(data, ref pos));
+ eatWhite(data, ref pos);
+ if(pos < data.Length && data[pos] == ',')
+ {
+ ++pos;
+ }
+ else if(pos < data.Length && data[pos] == ';')
+ {
+ ++pos;
+ results.Add(current);
+ current = new RDNEntry();
+ }
+ else if(pos < data.Length)
+ {
+ throw new ParseException("expected ',' or ';' at `" + data.Substring(pos) + "'");
+ }
+ }
+ if(current.rdn.Count > 0)
+ {
+ results.Add(current);
+ }
+
+ return results;
+ }
+
+ internal static List<RDNPair> parseStrict(string data)
+ {
+ List<RDNPair> results = new List<RDNPair>();
+ int pos = 0;
+ while(pos < data.Length)
+ {
+ results.Add(parseNameComponent(data, ref pos));
+ eatWhite(data, ref pos);
+ if(pos < data.Length && (data[pos] == ',' || data[pos] == ';'))
+ {
+ ++pos;
+ }
+ else if(pos < data.Length)
+ {
+ throw new ParseException("expected ',' or ';' at `" + data.Substring(pos) + "'");
+ }
+ }
+ return results;
+ }
+
+ public static string unescape(string data)
+ {
+ if(data.Length == 0)
+ {
+ return data;
+ }
+
+ if(data[0] == '"')
+ {
+ if(data[data.Length - 1] != '"')
+ {
+ throw new ParseException("unescape: missing \"");
+ }
+ //
+ // Return the string without quotes.
+ //
+ return data.Substring(1, data.Length - 2);
+ }
+
+ //
+ // Unescape the entire string.
+ //
+ StringBuilder result = new StringBuilder();
+ if(data[0] == '#')
+ {
+ int pos = 1;
+ while(pos < data.Length)
+ {
+ result.Append(unescapeHex(data, pos));
+ pos += 2;
+ }
+ }
+ else
+ {
+ int pos = 0;
+ while (pos < data.Length)
+ {
+ if(data[pos] != '\\')
+ {
+ result.Append(data[pos]);
+ ++pos;
+ }
+ else
+ {
+ ++pos;
+ if(pos >= data.Length)
+ {
+ throw new ParseException("unescape: invalid escape sequence");
+ }
+ if(special.IndexOf(data[pos]) != -1 || data[pos] != '\\' || data[pos] != '"')
+ {
+ result.Append(data[pos]);
+ ++pos;
+ }
+ else
+ {
+ result.Append(unescapeHex(data, pos));
+ pos += 2;
+ }
+ }
+ }
+ }
+ return result.ToString();
+ }
+
+ private static int hexToInt(char v)
+ {
+ if(v >= '0' && v <= '9')
+ {
+ return v - '0';
+ }
+ if(v >= 'a' && v <= 'f')
+ {
+ return 10 + (v - 'a');
+ }
+ if(v >= 'A' && v <= 'F')
+ {
+ return 10 + (v - 'A');
+ }
+ throw new ParseException("unescape: invalid hex pair");
+ }
+
+ private static char unescapeHex(string data, int pos)
+ {
+ Debug.Assert(pos < data.Length);
+ if(pos + 2 >= data.Length)
+ {
+ throw new ParseException("unescape: invalid hex pair");
+ }
+ return (char)(hexToInt(data[pos]) * 16 + hexToInt(data[pos + 1]));
+ }
+
+ private static RDNPair parseNameComponent(string data, ref int pos)
+ {
+ RDNPair result = parseAttributeTypeAndValue(data, ref pos);
+ while(pos < data.Length)
+ {
+ eatWhite(data, ref pos);
+ if(pos < data.Length && data[pos] == '+')
+ {
+ ++pos;
+ }
+ else
+ {
+ break;
+ }
+ RDNPair p = parseAttributeTypeAndValue(data, ref pos);
+ result.value += "+";
+ result.value += p.key;
+ result.value += '=';
+ result.value += p.value;
+ }
+ return result;
+ }
+
+ private static RDNPair parseAttributeTypeAndValue(string data, ref int pos)
+ {
+ RDNPair p = new RDNPair();
+ p.key = parseAttributeType(data, ref pos);
+ eatWhite(data, ref pos);
+ if(pos >= data.Length)
+ {
+ throw new ParseException("invalid attribute type/value pair (unexpected end of data)");
+ }
+ if(data[pos] != '=')
+ {
+ throw new ParseException("invalid attribute type/value pair (missing =). remainder: " +
+ data.Substring(pos));
+ }
+ ++pos;
+ p.value = parseAttributeValue(data, ref pos);
+ return p;
+ }
+
+ private static string parseAttributeType(string data, ref int pos)
+ {
+ eatWhite(data, ref pos);
+ if(pos >= data.Length)
+ {
+ throw new ParseException("invalid attribute type (expected end of data)");
+ }
+
+ string result = "";
+
+ //
+ // RFC 1779.
+ // <key> ::= 1*( <keychar> ) | "OID." <oid> | "oid." <oid>
+ // <oid> ::= <digitstring> | <digitstring> "." <oid>
+ // RFC 2253:
+ // attributeType = (ALPHA 1*keychar) | oid
+ // keychar = ALPHA | DIGIT | "-"
+ // oid = 1*DIGIT *("." 1*DIGIT)
+ //
+ // In section 4 of RFC 2253 the document says:
+ // Implementations MUST allow an oid in the attribute type to be
+ // prefixed by one of the character strings "oid." or "OID.".
+ //
+ // Here we must also check for "oid." and "OID." before parsing
+ // according to the ALPHA KEYCHAR* rule.
+ //
+ // First the OID case.
+ //
+ if(Char.IsDigit(data[pos]) ||
+ (data.Length - pos >= 4 && (data.Substring(pos, 4).Equals("oid.") ||
+ data.Substring(pos, 4).Equals("OID."))))
+ {
+ if(!Char.IsDigit(data[pos]))
+ {
+ result += data.Substring(pos, 4);
+ pos += 4;
+ }
+
+ while(true)
+ {
+ // 1*DIGIT
+ while(pos < data.Length && Char.IsDigit(data[pos]))
+ {
+ result += data[pos];
+ ++pos;
+ }
+ // "." 1*DIGIT
+ if(pos < data.Length && data[pos] == '.')
+ {
+ result += data[pos];
+ ++pos;
+ // 1*DIGIT must follow "."
+ if(pos < data.Length && !Char.IsDigit(data[pos]))
+ {
+ throw new ParseException("invalid attribute type (expected end of data)");
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else if(Char.IsUpper(data[pos]) || Char.IsLower(data[pos]))
+ {
+ //
+ // The grammar is wrong in this case. It should be ALPHA
+ // KEYCHAR* otherwise it will not accept "O" as a valid
+ // attribute type.
+ //
+ result += data[pos];
+ ++pos;
+ // 1* KEYCHAR
+ while(pos < data.Length &&
+ (Char.IsDigit(data[pos]) ||
+ Char.IsUpper(data[pos]) ||
+ Char.IsLower(data[pos]) ||
+ data[pos] == '-'))
+ {
+ result += data[pos];
+ ++pos;
+ }
+ }
+ else
+ {
+ throw new ParseException("invalid attribute type");
+ }
+ return result;
+ }
+
+ private static string parseAttributeValue(string data, ref int pos)
+ {
+ eatWhite(data, ref pos);
+ if(pos >= data.Length)
+ {
+ return "";
+ }
+
+ //
+ // RFC 2253
+ // # hexstring
+ //
+ StringBuilder result = new StringBuilder();
+ if(data[pos] == '#')
+ {
+ result.Append(data[pos]);
+ ++pos;
+ while(true)
+ {
+ string h = parseHexPair(data, ref pos, true);
+ if(h.Length == 0)
+ {
+ break;
+ }
+ result.Append(h);
+ }
+ }
+ //
+ // RFC 2253
+ // QUOTATION *( quotechar | pair ) QUOTATION ; only from v2
+ // quotechar = <any character except "\" or QUOTATION >
+ //
+ else if(data[pos] == '"')
+ {
+ result.Append(data[pos]);
+ ++pos;
+ while(true)
+ {
+ if(pos >= data.Length)
+ {
+ throw new ParseException("invalid attribute value (unexpected end of data)");
+ }
+ // final terminating "
+ if(data[pos] == '"')
+ {
+ result.Append(data[pos]);
+ ++pos;
+ break;
+ }
+ // any character except '\'
+ else if(data[pos] != '\\')
+ {
+ result.Append(data[pos]);
+ ++pos;
+ }
+ // pair '\'
+ else
+ {
+ result.Append(parsePair(data, ref pos));
+ }
+ }
+ }
+ //
+ // RFC 2253
+ // * (stringchar | pair)
+ // stringchar = <any character except one of special, "\" or QUOTATION >
+ //
+ else
+ {
+ while(pos < data.Length)
+ {
+ if(data[pos] == '\\')
+ {
+ result.Append(parsePair(data, ref pos));
+ }
+ else if(special.IndexOf(data[pos]) == -1 && data[pos] != '"')
+ {
+ result.Append(data[pos]);
+ ++pos;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ return result.ToString();
+ }
+
+ //
+ // RFC2253:
+ // pair = "\" ( special | "\" | QUOTATION | hexpair )
+ //
+ private static string parsePair(string data, ref int pos)
+ {
+ string result = "";
+
+ Debug.Assert(data[pos] == '\\');
+ result += data[pos];
+ ++pos;
+
+ if(pos >= data.Length)
+ {
+ throw new ParseException("invalid escape format (unexpected end of data)");
+ }
+
+ if(special.IndexOf(data[pos]) != -1 || data[pos] != '\\' ||
+ data[pos] != '"')
+ {
+ result += data[pos];
+ ++pos;
+ return result;
+ }
+ return parseHexPair(data, ref pos, false);
+ }
+
+ //
+ // RFC 2253
+ // hexpair = hexchar hexchar
+ //
+ private static string parseHexPair(string data, ref int pos, bool allowEmpty)
+ {
+ string result = "";
+ if(pos < data.Length && hexvalid.IndexOf(data[pos]) != -1)
+ {
+ result += data[pos];
+ ++pos;
+ }
+ if(pos < data.Length && hexvalid.IndexOf(data[pos]) != -1)
+ {
+ result += data[pos];
+ ++pos;
+ }
+ if(result.Length != 2)
+ {
+ if(allowEmpty && result.Length == 0)
+ {
+ return result;
+ }
+ throw new ParseException("invalid hex format");
+ }
+ return result;
+ }
+
+ //
+ // RFC 2253:
+ //
+ // Implementations MUST allow for space (' ' ASCII 32) characters to be
+ // present between name-component and ',', between attributeTypeAndValue
+ // and '+', between attributeType and '=', and between '=' and
+ // attributeValue. These space characters are ignored when parsing.
+ //
+ private static void eatWhite(string data, ref int pos)
+ {
+ while(pos < data.Length && data[pos] == ' ')
+ {
+ ++pos;
+ }
+ }
+
+ private static string special = ",=+<>#;";
+ private static string hexvalid = "0123456789abcdefABCDEF";
+ }
+}
diff --git a/csharp/src/IceSSL/SSLEngine.cs b/csharp/src/IceSSL/SSLEngine.cs
new file mode 100644
index 00000000000..deac22369a3
--- /dev/null
+++ b/csharp/src/IceSSL/SSLEngine.cs
@@ -0,0 +1,1226 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Security;
+ using System.Security.Authentication;
+ using System.Security.Cryptography;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Text;
+ using System.Globalization;
+
+ internal class SSLEngine
+ {
+ internal SSLEngine(IceInternal.ProtocolPluginFacade facade)
+ {
+ _communicator = facade.getCommunicator();
+ _logger = _communicator.getLogger();
+ _facade = facade;
+ _securityTraceLevel = _communicator.getProperties().getPropertyAsIntWithDefault("IceSSL.Trace.Security", 0);
+ _securityTraceCategory = "Security";
+ _initialized = false;
+ _trustManager = new TrustManager(_communicator);
+
+#if !UNITY
+ _tls12Support = false;
+ try
+ {
+ Enum.Parse(typeof(System.Security.Authentication.SslProtocols), "Tls12");
+ _tls12Support = true;
+ }
+ catch(Exception)
+ {
+ }
+#endif
+ }
+
+ internal void initialize()
+ {
+ if(_initialized)
+ {
+ return;
+ }
+
+ const string prefix = "IceSSL.";
+ Ice.Properties properties = communicator().getProperties();
+
+ //
+ // Check for a default directory. We look in this directory for
+ // files mentioned in the configuration.
+ //
+ _defaultDir = properties.getProperty(prefix + "DefaultDir");
+
+#if UNITY
+ _certStore = null;
+#else
+ string keySet = properties.getPropertyWithDefault(prefix + "KeySet", "DefaultKeySet");
+ if(!keySet.Equals("DefaultKeySet") && !keySet.Equals("UserKeySet") && !keySet.Equals("MachineKeySet"))
+ {
+ _logger.warning("Invalid IceSSL.KeySet value `" + keySet + "' adjusted to `DefaultKeySet'");
+ keySet = "DefaultKeySet";
+ }
+
+ _certStore = properties.getPropertyWithDefault(prefix + "CertStore", "CurrentUser");
+ if(_certStore != "CurrentUser" && _certStore != "LocalMachine")
+ {
+ _logger.warning("Invalid IceSSL.CertStore value `" + _certStore + "' adjusted to `CurrentUser'");
+ _certStore = "CurrentUser";
+ }
+
+ X509KeyStorageFlags keyStorageFlags = X509KeyStorageFlags.DefaultKeySet;
+ if(keySet.Equals("UserKeySet"))
+ {
+ keyStorageFlags = X509KeyStorageFlags.UserKeySet;
+ }
+ else if(keySet.Equals("MachineKeySet"))
+ {
+ keyStorageFlags = X509KeyStorageFlags.MachineKeySet;
+ }
+
+ if(properties.getPropertyAsIntWithDefault(prefix + "PersistKeySet", 0) > 0)
+ {
+ keyStorageFlags |= X509KeyStorageFlags.PersistKeySet;
+ }
+
+ //
+ // Process IceSSL.ImportCert.* properties.
+ //
+ Dictionary<string, string> certs = properties.getPropertiesForPrefix(prefix + "ImportCert.");
+ foreach(KeyValuePair<string, string> entry in certs)
+ {
+ string name = entry.Key;
+ string val = entry.Value;
+ if(val.Length > 0)
+ {
+ importCertificate(name, val, keyStorageFlags);
+ }
+ }
+#endif
+
+ //
+ // Protocols selects which protocols to enable, by default we only enable TLS1.0
+ // TLS1.1 and TLS1.2 to avoid security issues with SSLv3
+ //
+ _protocols = parseProtocols(
+ properties.getPropertyAsListWithDefault(prefix + "Protocols",
+#if UNITY
+ new string[]{"TLS1_0"}));
+#else
+ _tls12Support ? new string[]{"TLS1_0", "TLS1_1", "TLS1_2"} :
+ new string[]{"TLS1_0", "TLS1_1"}));
+#endif
+ //
+ // CheckCertName determines whether we compare the name in a peer's
+ // certificate against its hostname.
+ //
+ _checkCertName = properties.getPropertyAsIntWithDefault(prefix + "CheckCertName", 0) > 0;
+
+ //
+ // VerifyDepthMax establishes the maximum length of a peer's certificate
+ // chain, including the peer's certificate. A value of 0 means there is
+ // no maximum.
+ //
+ _verifyDepthMax = properties.getPropertyAsIntWithDefault(prefix + "VerifyDepthMax", 2);
+
+ //
+ // CheckCRL determines whether the certificate revocation list is checked, and how strictly.
+ //
+ _checkCRL = properties.getPropertyAsIntWithDefault(prefix + "CheckCRL", 0);
+
+#if !UNITY
+ //
+ // Check for a certificate verifier.
+ //
+ string certVerifierClass = properties.getProperty(prefix + "CertVerifier");
+ if(certVerifierClass.Length > 0)
+ {
+ if(_verifier != null)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: certificate verifier already installed";
+ throw e;
+ }
+
+ Type cls = _facade.findType(certVerifierClass);
+ if(cls == null)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unable to load certificate verifier class " + certVerifierClass;
+ throw e;
+ }
+
+ try
+ {
+ _verifier = (CertificateVerifier)IceInternal.AssemblyUtil.createInstance(cls);
+ }
+ catch(Exception ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex);
+ e.reason = "IceSSL: unable to instantiate certificate verifier class " + certVerifierClass;
+ throw e;
+ }
+
+ if(_verifier == null)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unable to instantiate certificate verifier class " + certVerifierClass;
+ throw e;
+ }
+ }
+
+ //
+ // Check for a password callback.
+ //
+ string passwordCallbackClass = properties.getProperty(prefix + "PasswordCallback");
+ if(passwordCallbackClass.Length > 0)
+ {
+ if(_passwordCallback != null)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: password callback already installed";
+ throw e;
+ }
+
+ Type cls = _facade.findType(passwordCallbackClass);
+ if(cls == null)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unable to load password callback class " + passwordCallbackClass;
+ throw e;
+ }
+
+ try
+ {
+ _passwordCallback = (PasswordCallback)IceInternal.AssemblyUtil.createInstance(cls);
+ }
+ catch(Exception ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex);
+ e.reason = "IceSSL: unable to load password callback class " + passwordCallbackClass;
+ throw e;
+ }
+
+ if(_passwordCallback == null)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unable to load password callback class " + passwordCallbackClass;
+ throw e;
+ }
+ }
+
+ //
+ // If the user hasn't supplied a certificate collection, we need to examine
+ // the property settings.
+ //
+ if(_certs == null)
+ {
+ //
+ // If IceSSL.CertFile is defined, load a certificate from a file and
+ // add it to the collection.
+ //
+ // TODO: tracing?
+ _certs = new X509Certificate2Collection();
+ string certFile = properties.getProperty(prefix + "CertFile");
+ string passwordStr = properties.getProperty(prefix + "Password");
+
+ if(certFile.Length > 0)
+ {
+ if(!checkPath(ref certFile))
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: certificate file not found: " + certFile;
+ throw e;
+ }
+
+ SecureString password = null;
+ if(passwordStr.Length > 0)
+ {
+ password = createSecureString(passwordStr);
+ }
+ else if(_passwordCallback != null)
+ {
+ password = _passwordCallback.getPassword(certFile);
+ }
+
+ try
+ {
+ X509Certificate2 cert;
+ if(password != null)
+ {
+ cert = new X509Certificate2(certFile, password, keyStorageFlags);
+ }
+ else
+ {
+ cert = new X509Certificate2(certFile, "", keyStorageFlags);
+ }
+ _certs.Add(cert);
+ }
+ catch(CryptographicException ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex);
+ e.reason = "IceSSL: error while attempting to load certificate from " + certFile;
+ throw e;
+ }
+ }
+
+ //
+ // If IceSSL.FindCert.* properties are defined, add the selected certificates
+ // to the collection.
+ //
+ // TODO: tracing?
+ const string findPrefix = prefix + "FindCert.";
+ Dictionary<string, string> certProps = properties.getPropertiesForPrefix(findPrefix);
+ if(certProps.Count > 0)
+ {
+ foreach(KeyValuePair<string, string> entry in certProps)
+ {
+ string name = entry.Key;
+ string val = entry.Value;
+ if(val.Length > 0)
+ {
+ string storeSpec = name.Substring(findPrefix.Length);
+ X509Certificate2Collection coll = findCertificates(name, storeSpec, val);
+ _certs.AddRange(coll);
+ }
+ }
+ if(_certs.Count == 0)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: no certificates found";
+ throw e;
+ }
+ }
+ }
+
+ if(_caCerts == null)
+ {
+ string certAuthFile = properties.getProperty(prefix + "CertAuthFile");
+ if(certAuthFile.Length > 0)
+ {
+ if(!checkPath(ref certAuthFile))
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: CA certificate file not found: " + certAuthFile;
+ throw e;
+ }
+
+ _caCerts = new X509Certificate2Collection();
+ try
+ {
+ _caCerts.Add(new X509Certificate2(certAuthFile));
+ }
+ catch(CryptographicException ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex);
+ e.reason = "IceSSL: error while attempting to load CA certificate from " + certAuthFile;
+ throw e;
+ }
+ }
+ }
+#endif
+
+ _initialized = true;
+ }
+
+ internal string certStore()
+ {
+ return _certStore;
+ }
+
+ internal X509Certificate2Collection caCerts()
+ {
+ return _caCerts;
+ }
+
+ internal void setCACertificates(X509Certificate2Collection caCerts)
+ {
+ if(_initialized)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: plug-in is already initialized";
+ throw e;
+ }
+
+ _caCerts = caCerts;
+ }
+
+ internal void setCertificates(X509Certificate2Collection certs)
+ {
+ if(_initialized)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: plug-in is already initialized";
+ throw e;
+ }
+
+ _certs = certs;
+ }
+
+ internal void setCertificateVerifier(CertificateVerifier verifier)
+ {
+ _verifier = verifier;
+ }
+
+ internal CertificateVerifier getCertificateVerifier()
+ {
+ return _verifier;
+ }
+
+ internal void setPasswordCallback(PasswordCallback callback)
+ {
+ _passwordCallback = callback;
+ }
+
+ internal PasswordCallback getPasswordCallback()
+ {
+ return _passwordCallback;
+ }
+
+ internal Ice.Communicator communicator()
+ {
+ return _facade.getCommunicator();
+ }
+
+ internal int securityTraceLevel()
+ {
+ return _securityTraceLevel;
+ }
+
+ internal string securityTraceCategory()
+ {
+ return _securityTraceCategory;
+ }
+
+ internal bool initialized()
+ {
+ return _initialized;
+ }
+
+ internal X509Certificate2Collection certs()
+ {
+ return _certs;
+ }
+
+ internal SslProtocols protocols()
+ {
+ return _protocols;
+ }
+
+ internal int checkCRL()
+ {
+ return _checkCRL;
+ }
+
+ internal void traceStream(System.Net.Security.SslStream stream, string connInfo)
+ {
+ System.Text.StringBuilder s = new System.Text.StringBuilder();
+ s.Append("SSL connection summary");
+ if(connInfo.Length > 0)
+ {
+ s.Append("\n");
+ s.Append(connInfo);
+ }
+ s.Append("\nauthenticated = " + (stream.IsAuthenticated ? "yes" : "no"));
+ s.Append("\nencrypted = " + (stream.IsEncrypted ? "yes" : "no"));
+ s.Append("\nsigned = " + (stream.IsSigned ? "yes" : "no"));
+ s.Append("\nmutually authenticated = " + (stream.IsMutuallyAuthenticated ? "yes" : "no"));
+#if !UNITY
+ s.Append("\nhash algorithm = " + stream.HashAlgorithm + "/" + stream.HashStrength);
+ s.Append("\ncipher algorithm = " + stream.CipherAlgorithm + "/" + stream.CipherStrength);
+ s.Append("\nkey exchange algorithm = " + stream.KeyExchangeAlgorithm + "/" + stream.KeyExchangeStrength);
+ s.Append("\nprotocol = " + stream.SslProtocol);
+#endif
+ _logger.trace(_securityTraceCategory, s.ToString());
+ }
+
+ internal void verifyPeer(NativeConnectionInfo info, System.Net.Sockets.Socket fd, string address)
+ {
+ //
+ // For an outgoing connection, we compare the proxy address (if any) against
+ // fields in the server's certificate (if any).
+ //
+ if(info.nativeCerts != null && info.nativeCerts.Length > 0 && address.Length > 0)
+ {
+ //
+ // Extract the IP addresses and the DNS names from the subject
+ // alternative names.
+ //
+ List<string> dnsNames = null;
+ List<string> ipAddresses = null;
+
+ //
+ // Search for "subject alternative name" extensions. The OID value
+ // of interest is 2.5.29.17 and the encoded data has the following
+ // ASN.1 syntax:
+ //
+ // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ //
+ // GeneralName ::= CHOICE {
+ // otherName [0] OtherName,
+ // rfc822Name [1] IA5String,
+ // dNSName [2] IA5String,
+ // x400Address [3] ORAddress,
+ // directoryName [4] Name,
+ // ediPartyName [5] EDIPartyName,
+ // uniformResourceIdentifier [6] IA5String,
+ // iPAddress [7] OCTET STRING,
+ // registeredID [8] OBJECT IDENTIFIER
+ // }
+ //
+ foreach(X509Extension ext in info.nativeCerts[0].Extensions)
+ {
+ if(ext.Oid.Value.Equals("2.5.29.17") && ext.RawData.Length > 0)
+ {
+ byte[] data = ext.RawData;
+ if(data.Length < 2 || data[0] != 0x30) // ASN.1 sequence
+ {
+ continue;
+ }
+
+ int seqLen, pos;
+ if(!decodeASN1Length(data, 1, out seqLen, out pos))
+ {
+ continue;
+ }
+
+ while(pos < data.Length)
+ {
+ int tag = data[pos];
+
+ int len;
+ if(!decodeASN1Length(data, pos + 1, out len, out pos))
+ {
+ break;
+ }
+
+ if(tag == 0x82)
+ {
+ //
+ // Extract DNS name.
+ //
+ StringBuilder b = new StringBuilder();
+ for(int j = pos; j < pos + len; ++j)
+ {
+ b.Append((char)data[j]);
+ }
+ if(dnsNames == null)
+ {
+ dnsNames = new List<string>();
+ }
+ dnsNames.Add(b.ToString().ToUpperInvariant());
+ }
+ else if(tag == 0x87)
+ {
+ //
+ // Extract IP address.
+ //
+ char sep = len == 4 ? '.' : ':';
+ StringBuilder b = new StringBuilder();
+ for(int j = pos; j < pos + len; ++j)
+ {
+ if(j > pos)
+ {
+ b.Append(sep);
+ }
+ b.Append(data[j].ToString(CultureInfo.InvariantCulture));
+ }
+ if(ipAddresses == null)
+ {
+ ipAddresses = new List<string>();
+ }
+ ipAddresses.Add(b.ToString().ToUpperInvariant());
+ }
+
+ pos += len;
+ }
+ }
+ }
+
+ //
+ // Compare the peer's address against the common name as well as
+ // the dnsName and ipAddress values in the subject alternative name.
+ //
+ string dn = info.nativeCerts[0].Subject;
+ string addrLower = address.ToUpperInvariant();
+ bool certNameOK = false;
+ {
+ string cn = "cn=" + addrLower;
+ int pos = dn.ToLower(CultureInfo.InvariantCulture).IndexOf(cn, StringComparison.Ordinal);
+ if(pos >= 0)
+ {
+ //
+ // Ensure we match the entire common name.
+ //
+ certNameOK = (pos + cn.Length == dn.Length) || (dn[pos + cn.Length] == ',');
+ }
+ }
+
+ //
+ // Compare the peer's address against the dnsName and ipAddress
+ // values in the subject alternative name.
+ //
+ if(!certNameOK && ipAddresses != null)
+ {
+ certNameOK = ipAddresses.Contains(addrLower);
+ }
+ if(!certNameOK && dnsNames != null)
+ {
+ certNameOK = dnsNames.Contains(addrLower);
+ }
+
+ //
+ // Log a message if the name comparison fails. If CheckCertName is defined,
+ // we also raise an exception to abort the connection. Don't log a message if
+ // CheckCertName is not defined and a verifier is present.
+ //
+ if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && _verifier == null)))
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("IceSSL: ");
+ if(!_checkCertName)
+ {
+ sb.Append("ignoring ");
+ }
+ sb.Append("certificate validation failure:\npeer certificate does not have `");
+ sb.Append(address);
+ sb.Append("' as its commonName or in its subjectAltName extension");
+ if(dn.Length > 0)
+ {
+ sb.Append("\nSubject DN: ");
+ sb.Append(dn);
+ }
+ if(dnsNames != null)
+ {
+ sb.Append("\nDNS names found in certificate: ");
+ for(int j = 0; j < dnsNames.Count; ++j)
+ {
+ if(j > 0)
+ {
+ sb.Append(", ");
+ }
+ sb.Append(dnsNames[j]);
+ }
+ }
+ if(ipAddresses != null)
+ {
+ sb.Append("\nIP addresses found in certificate: ");
+ for(int j = 0; j < ipAddresses.Count; ++j)
+ {
+ if(j > 0)
+ {
+ sb.Append(", ");
+ }
+ sb.Append(ipAddresses[j]);
+ }
+ }
+ string msg = sb.ToString();
+ if(_securityTraceLevel >= 1)
+ {
+ _logger.trace(_securityTraceCategory, msg);
+ }
+ if(_checkCertName)
+ {
+ Ice.SecurityException ex = new Ice.SecurityException();
+ ex.reason = msg;
+ throw ex;
+ }
+ }
+ }
+
+ if(_verifyDepthMax > 0 && info.nativeCerts != null && info.nativeCerts.Length > _verifyDepthMax)
+ {
+ string msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected:\n" +
+ "length of peer's certificate chain (" + info.nativeCerts.Length + ") exceeds maximum of " +
+ _verifyDepthMax + "\n" +
+ IceInternal.Network.fdToString(fd);
+ if(_securityTraceLevel >= 1)
+ {
+ _logger.trace(_securityTraceCategory, msg);
+ }
+ Ice.SecurityException ex = new Ice.SecurityException();
+ ex.reason = msg;
+ throw ex;
+ }
+
+ if(!_trustManager.verify(info))
+ {
+ string msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected by trust manager\n" +
+ IceInternal.Network.fdToString(fd);
+ if(_securityTraceLevel >= 1)
+ {
+ _logger.trace(_securityTraceCategory, msg);
+ }
+
+ Ice.SecurityException ex = new Ice.SecurityException();
+ ex.reason = "IceSSL: " + msg;
+ throw ex;
+ }
+
+ if(_verifier != null && !_verifier.verify(info))
+ {
+ string msg = (info.incoming ? "incoming" : "outgoing") +
+ " connection rejected by certificate verifier\n" + IceInternal.Network.fdToString(fd);
+ if(_securityTraceLevel >= 1)
+ {
+ _logger.trace(_securityTraceCategory, msg);
+ }
+
+ Ice.SecurityException ex = new Ice.SecurityException();
+ ex.reason = "IceSSL: " + msg;
+ throw ex;
+ }
+ }
+
+ //
+ // Parse a string of the form "location.name" into two parts.
+ //
+ private static void parseStore(string prop, string store, ref StoreLocation loc, ref StoreName name,
+ ref string sname)
+ {
+ int pos = store.IndexOf('.');
+ if(pos == -1)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: property `" + prop + "' has invalid format";
+ throw e;
+ }
+
+ string sloc = store.Substring(0, pos).ToUpperInvariant();
+ if(sloc.Equals("CURRENTUSER"))
+ {
+ loc = StoreLocation.CurrentUser;
+ }
+ else if(sloc.Equals("LOCALMACHINE"))
+ {
+ loc = StoreLocation.LocalMachine;
+ }
+ else
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unknown store location `" + sloc + "' in " + prop;
+ throw e;
+ }
+
+ sname = store.Substring(pos + 1);
+ if(sname.Length == 0)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: invalid store name in " + prop;
+ throw e;
+ }
+
+ //
+ // Try to convert the name into the StoreName enumeration.
+ //
+ try
+ {
+ name = (StoreName)Enum.Parse(typeof(StoreName), sname, true);
+ sname = null;
+ }
+ catch(ArgumentException)
+ {
+ // Ignore - assume the user is selecting a non-standard store.
+ }
+ }
+
+ private bool checkPath(ref string path)
+ {
+ if(File.Exists(path))
+ {
+ return true;
+ }
+
+ if(_defaultDir.Length > 0)
+ {
+ string s = _defaultDir + Path.DirectorySeparatorChar + path;
+ if(File.Exists(s))
+ {
+ path = s;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+#if !UNITY
+ private void importCertificate(string propName, string propValue, X509KeyStorageFlags keyStorageFlags)
+ {
+ //
+ // Expecting a property of the following form:
+ //
+ // IceSSL.ImportCert.<location>.<name>=<file>[;password]
+ //
+ const string prefix = "IceSSL.ImportCert.";
+ StoreLocation loc = 0;
+ StoreName name = 0;
+ string sname = null;
+ parseStore(propName, propName.Substring(prefix.Length), ref loc, ref name, ref sname);
+
+ //
+ // Extract the filename and password. Either or both can be quoted.
+ //
+ string[] arr = splitString(propValue, ';');
+ if(arr == null)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unmatched quote in `" + propValue + "'";
+ throw e;
+ }
+ if(arr.Length == 0)
+ {
+ return;
+ }
+ string file = arr[0];
+ string passwordStr = null;
+ if(arr.Length > 1)
+ {
+ passwordStr = arr[1];
+ }
+
+ //
+ // Open the X509 certificate store.
+ //
+ X509Store store = null;
+ try
+ {
+ if(sname != null)
+ {
+ store = new X509Store(sname, loc);
+ }
+ else
+ {
+ store = new X509Store(name, loc);
+ }
+ store.Open(OpenFlags.ReadWrite);
+ }
+ catch(Exception ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex);
+ e.reason = "IceSSL: failure while opening store specified by " + propName;
+ throw e;
+ }
+
+ if(!checkPath(ref file))
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: certificate file not found:\n" + file;
+ throw e;
+ }
+
+ SecureString password = null;
+ if(passwordStr != null)
+ {
+ password = createSecureString(passwordStr);
+ }
+ else if(_passwordCallback != null)
+ {
+ password = _passwordCallback.getImportPassword(file);
+ }
+
+ //
+ // Add the certificate to the store.
+ //
+ try
+ {
+ X509Certificate2 cert;
+ if(password != null)
+ {
+ cert = new X509Certificate2(file, password, keyStorageFlags);
+ }
+ else
+ {
+ cert = new X509Certificate2(file, "", keyStorageFlags);
+ }
+ store.Add(cert);
+ }
+ catch(Exception ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex);
+ e.reason = "IceSSL: failure while adding certificate file:\n" + file;
+ throw e;
+ }
+ finally
+ {
+ store.Close();
+ }
+ }
+#endif
+
+ //
+ // Split strings using a delimiter. Quotes are supported.
+ // Returns null for an unmatched quote.
+ //
+ private static string[] splitString(string str, char delim)
+ {
+ ArrayList l = new ArrayList();
+ char[] arr = new char[str.Length];
+ int pos = 0;
+
+ while(pos < str.Length)
+ {
+ int n = 0;
+ char quoteChar = '\0';
+ if(str[pos] == '"' || str[pos] == '\'')
+ {
+ quoteChar = str[pos];
+ ++pos;
+ }
+ bool trim = true;
+ while(pos < str.Length)
+ {
+ if(quoteChar != '\0' && str[pos] == '\\' && pos + 1 < str.Length && str[pos + 1] == quoteChar)
+ {
+ ++pos;
+ }
+ else if(quoteChar != '\0' && str[pos] == quoteChar)
+ {
+ trim = false;
+ ++pos;
+ quoteChar = '\0';
+ break;
+ }
+ else if(str[pos] == delim)
+ {
+ if(quoteChar == '\0')
+ {
+ ++pos;
+ break;
+ }
+ }
+ if(pos < str.Length)
+ {
+ arr[n++] = str[pos++];
+ }
+ }
+ if(quoteChar != '\0')
+ {
+ return null; // Unmatched quote.
+ }
+ if(n > 0)
+ {
+ string s = new string(arr, 0, n);
+ if(trim)
+ {
+ s = s.Trim();
+ }
+ if(s.Length > 0)
+ {
+ l.Add(s);
+ }
+ }
+ }
+
+ return (string[])l.ToArray(typeof(string));
+ }
+
+ private SslProtocols parseProtocols(string[] arr)
+ {
+ SslProtocols result = SslProtocols.Default;
+
+ if(arr.Length > 0)
+ {
+ result = 0;
+ for(int i = 0; i < arr.Length; ++i)
+ {
+ string protocol = null;
+ string s = arr[i].ToUpperInvariant();
+ switch(s)
+ {
+ case "SSL3":
+ case "SSLV3":
+ {
+ protocol = "Ssl3";
+ break;
+ }
+ case "TLS":
+ case "TLS1":
+ case "TLS1_0":
+ case "TLSV1":
+ case "TLSV1_0":
+ {
+ protocol = "Tls";
+ break;
+ }
+ case "TLS1_1":
+ case "TLSV1_1":
+ {
+ protocol = "Tls11";
+ break;
+ }
+ case "TLS1_2":
+ case "TLSV1_2":
+ {
+ protocol = "Tls12";
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ try
+ {
+ SslProtocols value = (SslProtocols)Enum.Parse(typeof(SslProtocols), protocol);
+ result |= value;
+ }
+ catch(Exception)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unrecognized protocol `" + s + "'";
+ throw e;
+ }
+ }
+ }
+ return result;
+ }
+
+#if !UNITY
+ private static X509Certificate2Collection findCertificates(string prop, string storeSpec, string value)
+ {
+ StoreLocation storeLoc = 0;
+ StoreName storeName = 0;
+ string storeNameStr = null;
+ parseStore(prop, storeSpec, ref storeLoc, ref storeName, ref storeNameStr);
+
+ //
+ // Open the X509 certificate store.
+ //
+ X509Store store = null;
+ try
+ {
+ if(storeNameStr != null)
+ {
+ store = new X509Store(storeNameStr, storeLoc);
+ }
+ else
+ {
+ store = new X509Store(storeName, storeLoc);
+ }
+ store.Open(OpenFlags.ReadOnly);
+ }
+ catch(Exception ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex);
+ e.reason = "IceSSL: failure while opening store specified by " + prop;
+ throw e;
+ }
+
+ //
+ // Start with all of the certificates in the collection and filter as necessary.
+ //
+ // - If the value is "*", return all certificates.
+ // - Otherwise, search using key:value pairs. The following keys are supported:
+ //
+ // Issuer
+ // IssuerDN
+ // Serial
+ // Subject
+ // SubjectDN
+ // SubjectKeyId
+ // Thumbprint
+ //
+ // A value must be enclosed in single or double quotes if it contains whitespace.
+ //
+ X509Certificate2Collection result = new X509Certificate2Collection();
+ result.AddRange(store.Certificates);
+ try
+ {
+ if(value != "*")
+ {
+ int start = 0;
+ int pos;
+ while((pos = value.IndexOf(':', start)) != -1)
+ {
+ //
+ // Parse the X509FindType.
+ //
+ string field = value.Substring(start, pos - start).Trim().ToUpperInvariant();
+ X509FindType findType;
+ if(field.Equals("SUBJECT"))
+ {
+ findType = X509FindType.FindBySubjectName;
+ }
+ else if(field.Equals("SUBJECTDN"))
+ {
+ findType = X509FindType.FindBySubjectDistinguishedName;
+ }
+ else if(field.Equals("ISSUER"))
+ {
+ findType = X509FindType.FindByIssuerName;
+ }
+ else if(field.Equals("ISSUERDN"))
+ {
+ findType = X509FindType.FindByIssuerDistinguishedName;
+ }
+ else if(field.Equals("THUMBPRINT"))
+ {
+ findType = X509FindType.FindByThumbprint;
+ }
+ else if(field.Equals("SUBJECTKEYID"))
+ {
+ findType = X509FindType.FindBySubjectKeyIdentifier;
+ }
+ else if(field.Equals("SERIAL"))
+ {
+ findType = X509FindType.FindBySerialNumber;
+ }
+ else
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unknown key in `" + value + "'";
+ throw e;
+ }
+
+ //
+ // Parse the argument.
+ //
+ start = pos + 1;
+ while(start < value.Length && (value[start] == ' ' || value[start] == '\t'))
+ {
+ ++start;
+ }
+ if(start == value.Length)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: missing argument in `" + value + "'";
+ throw e;
+ }
+
+ string arg;
+ if(value[start] == '"' || value[start] == '\'')
+ {
+ int end = start;
+ ++end;
+ while(end < value.Length)
+ {
+ if(value[end] == value[start] && value[end - 1] != '\\')
+ {
+ break;
+ }
+ ++end;
+ }
+ if(end == value.Length || value[end] != value[start])
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unmatched quote in `" + value + "'";
+ throw e;
+ }
+ ++start;
+ arg = value.Substring(start, end - start);
+ start = end + 1;
+ }
+ else
+ {
+ char[] ws = new char[] { ' ', '\t' };
+ int end = value.IndexOfAny(ws, start);
+ if(end == -1)
+ {
+ arg = value.Substring(start);
+ start = value.Length;
+ }
+ else
+ {
+ arg = value.Substring(start, end - start);
+ start = end + 1;
+ }
+ }
+
+ //
+ // Execute the query.
+ //
+ // TODO: allow user to specify a value for validOnly?
+ //
+ bool validOnly = false;
+ result = result.Find(findType, arg, validOnly);
+ }
+ }
+ }
+ finally
+ {
+ store.Close();
+ }
+
+ return result;
+ }
+
+ private static SecureString createSecureString(string s)
+ {
+ SecureString result = new SecureString();
+ foreach(char ch in s)
+ {
+ result.AppendChar(ch);
+ }
+ return result;
+ }
+#endif
+
+ private static bool decodeASN1Length(byte[] data, int start, out int len, out int next)
+ {
+ len = 0;
+ next = 0;
+
+ if(start + 1 > data.Length)
+ {
+ return false;
+ }
+
+ len = data[start];
+ int len2 = 0;
+ if(len > 0x80) // Composed length
+ {
+ len2 = len - 0x80;
+ if(start + len2 + 1 > data.Length)
+ {
+ return false;
+ }
+ len = 0;
+ for(int i = 0; i < len2; i++)
+ {
+ len *= 256;
+ len += data[start + i + 1];
+ }
+ }
+ else if(len == 0x80) // Undefined length encoding
+ {
+ return false;
+ }
+
+ next = start + len2 + 1;
+ return (next + len <= data.Length);
+ }
+
+ private Ice.Communicator _communicator;
+ private Ice.Logger _logger;
+ private IceInternal.ProtocolPluginFacade _facade;
+ private int _securityTraceLevel;
+ private string _securityTraceCategory;
+ private bool _initialized;
+ private string _defaultDir;
+ private SslProtocols _protocols;
+ private bool _checkCertName;
+ private int _verifyDepthMax;
+ private int _checkCRL;
+ private X509Certificate2Collection _certs;
+ private string _certStore;
+ private X509Certificate2Collection _caCerts;
+ private CertificateVerifier _verifier;
+ private PasswordCallback _passwordCallback;
+ private TrustManager _trustManager;
+#if !UNITY
+ private bool _tls12Support;
+#endif
+ }
+}
diff --git a/csharp/src/IceSSL/TransceiverI.cs b/csharp/src/IceSSL/TransceiverI.cs
new file mode 100644
index 00000000000..84902367dc9
--- /dev/null
+++ b/csharp/src/IceSSL/TransceiverI.cs
@@ -0,0 +1,754 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Net;
+ using System.Net.Security;
+ using System.Net.Sockets;
+ using System.Security.Authentication;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Threading;
+ using System.Text;
+
+ sealed class TransceiverI : IceInternal.Transceiver
+ {
+ public Socket fd()
+ {
+ return _stream.fd();
+ }
+
+ public int initialize(IceInternal.Buffer readBuffer, IceInternal.Buffer writeBuffer, ref bool hasMoreData)
+ {
+ int status = _stream.connect(readBuffer, writeBuffer, ref hasMoreData);
+ if(status != IceInternal.SocketOperation.None)
+ {
+ return status;
+ }
+
+ _stream.setBlock(true); // SSL requires a blocking socket
+
+ if(_sslStream == null)
+ {
+ NetworkStream ns = new NetworkStream(_stream.fd(), false);
+ _sslStream = new SslStream(ns, false, new RemoteCertificateValidationCallback(validationCallback),
+ new LocalCertificateSelectionCallback(selectCertificate));
+ return IceInternal.SocketOperation.Connect;
+ }
+
+ Debug.Assert(_sslStream.IsAuthenticated);
+ _authenticated = true;
+ _instance.verifyPeer(getNativeConnectionInfo(), _stream.fd(), _host);
+
+ if(_instance.securityTraceLevel() >= 1)
+ {
+ _instance.traceStream(_sslStream, _stream.ToString());
+ }
+ return IceInternal.SocketOperation.None;
+ }
+
+ public int closing(bool initiator, Ice.LocalException ex)
+ {
+ // If we are initiating the connection closure, wait for the peer
+ // to close the TCP/IP connection. Otherwise, close immediately.
+ return initiator ? IceInternal.SocketOperation.Read : IceInternal.SocketOperation.None;
+ }
+
+ public void close()
+ {
+ if(_sslStream != null)
+ {
+ _sslStream.Close(); // Closing the stream also closes the socket.
+ _sslStream = null;
+ }
+
+ _stream.close();
+ }
+
+ public IceInternal.EndpointI bind()
+ {
+ Debug.Assert(false);
+ return null;
+ }
+
+ public void destroy()
+ {
+ _stream.destroy();
+ }
+
+ public int write(IceInternal.Buffer buf)
+ {
+ //
+ // Force caller to use async write.
+ //
+ return buf.b.hasRemaining() ? IceInternal.SocketOperation.Write : IceInternal.SocketOperation.None;
+ }
+
+ public int read(IceInternal.Buffer buf, ref bool hasMoreData)
+ {
+ //
+ // Force caller to use async read.
+ //
+ return buf.b.hasRemaining() ? IceInternal.SocketOperation.Read : IceInternal.SocketOperation.None;
+ }
+
+ public bool startRead(IceInternal.Buffer buf, IceInternal.AsyncCallback callback, object state)
+ {
+ if(!_stream.isConnected())
+ {
+ return _stream.startRead(buf, callback, state);
+ }
+
+ Debug.Assert(_sslStream != null && _sslStream.IsAuthenticated);
+
+ int packetSz = _stream.getRecvPacketSize(buf.b.remaining());
+ try
+ {
+ _readCallback = callback;
+ _readResult = _sslStream.BeginRead(buf.b.rawBytes(), buf.b.position(), packetSz, readCompleted, state);
+ return _readResult.CompletedSynchronously;
+ }
+ catch(IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ if(IceInternal.Network.timeout(ex))
+ {
+ throw new Ice.TimeoutException();
+ }
+ throw new Ice.SocketException(ex);
+ }
+ catch(ObjectDisposedException ex)
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.SyscallException(ex);
+ }
+ }
+
+ public void finishRead(IceInternal.Buffer buf)
+ {
+ if(!_stream.isConnected())
+ {
+ _stream.finishRead(buf);
+ return;
+ }
+ else if(_sslStream == null) // Transceiver was closed
+ {
+ _readResult = null;
+ return;
+ }
+
+ Debug.Assert(_readResult != null);
+ try
+ {
+ int ret = _sslStream.EndRead(_readResult);
+ _readResult = null;
+
+ if(ret == 0)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ Debug.Assert(ret > 0);
+ buf.b.position(buf.b.position() + ret);
+ }
+ catch(Ice.LocalException)
+ {
+ throw;
+ }
+ catch(IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ if(IceInternal.Network.timeout(ex))
+ {
+ throw new Ice.TimeoutException();
+ }
+ throw new Ice.SocketException(ex);
+ }
+ catch(ObjectDisposedException ex)
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.SyscallException(ex);
+ }
+ }
+
+ public bool startWrite(IceInternal.Buffer buf, IceInternal.AsyncCallback callback, object state,
+ out bool completed)
+ {
+ if(!_stream.isConnected())
+ {
+ return _stream.startWrite(buf, callback, state, out completed);
+ }
+
+ Debug.Assert(_sslStream != null);
+ if(!_authenticated)
+ {
+ completed = false;
+ return startAuthenticate(callback, state);
+ }
+
+ //
+ // We limit the packet size for beingWrite to ensure connection timeouts are based
+ // on a fixed packet size.
+ //
+ int packetSize = _stream.getSendPacketSize(buf.b.remaining());
+ try
+ {
+ _writeCallback = callback;
+ _writeResult = _sslStream.BeginWrite(buf.b.rawBytes(), buf.b.position(), packetSize, writeCompleted,
+ state);
+ completed = packetSize == buf.b.remaining();
+ return _writeResult.CompletedSynchronously;
+ }
+ catch(IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ if(IceInternal.Network.timeout(ex))
+ {
+ throw new Ice.TimeoutException();
+ }
+ throw new Ice.SocketException(ex);
+ }
+ catch(ObjectDisposedException ex)
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.SyscallException(ex);
+ }
+ }
+
+ public void finishWrite(IceInternal.Buffer buf)
+ {
+ if(!_stream.isConnected())
+ {
+ _stream.finishWrite(buf);
+ return;
+ }
+ else if(_sslStream == null) // Transceiver was closed
+ {
+ if(_stream.getSendPacketSize(buf.b.remaining()) == buf.b.remaining()) // Sent last packet
+ {
+ buf.b.position(buf.b.limit()); // Assume all the data was sent for at-most-once semantics.
+ }
+ _writeResult = null;
+ return;
+ }
+ else if(!_authenticated)
+ {
+ finishAuthenticate();
+ return;
+ }
+
+ Debug.Assert(_writeResult != null);
+ int sent = _stream.getSendPacketSize(buf.b.remaining());
+ try
+ {
+ _sslStream.EndWrite(_writeResult);
+ _writeResult = null;
+ buf.b.position(buf.b.position() + sent);
+ }
+ catch(IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ if(IceInternal.Network.timeout(ex))
+ {
+ throw new Ice.TimeoutException();
+ }
+ throw new Ice.SocketException(ex);
+ }
+ catch(ObjectDisposedException ex)
+ {
+ throw new Ice.ConnectionLostException(ex);
+ }
+ catch(Exception ex)
+ {
+ throw new Ice.SyscallException(ex);
+ }
+ }
+
+ public string protocol()
+ {
+ return _instance.protocol();
+ }
+
+ public Ice.ConnectionInfo getInfo()
+ {
+ return getNativeConnectionInfo();
+ }
+
+ public void checkSendSize(IceInternal.Buffer buf)
+ {
+ }
+
+ public void setBufferSize(int rcvSize, int sndSize)
+ {
+ _stream.setBufferSize(rcvSize, sndSize);
+ }
+
+ public override string ToString()
+ {
+ return _stream.ToString();
+ }
+
+ public string toDetailedString()
+ {
+ return ToString();
+ }
+
+ //
+ // Only for use by ConnectorI, AcceptorI.
+ //
+ internal TransceiverI(Instance instance, IceInternal.StreamSocket stream, string hostOrAdapterName, bool incoming)
+ {
+ _instance = instance;
+ _stream = stream;
+ _incoming = incoming;
+ if(_incoming)
+ {
+ _adapterName = hostOrAdapterName;
+ }
+ else
+ {
+ _host = hostOrAdapterName;
+ }
+ _sslStream = null;
+
+ if(_incoming)
+ {
+ //
+ // Determine whether a certificate is required from the peer.
+ //
+ _verifyPeer = _instance.properties().getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2);
+ }
+ else
+ {
+ _verifyPeer = 0;
+ }
+
+ _chain = new X509Chain(_instance.engine().certStore() == "LocalMachine");
+
+ if(_instance.checkCRL() == 0)
+ {
+ _chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
+ }
+
+ X509Certificate2Collection caCerts = _instance.engine().caCerts();
+ if(caCerts != null)
+ {
+#if !UNITY
+ //
+ // We need to set this flag to be able to use a certificate authority from the extra store.
+ //
+ _chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
+#endif
+
+ foreach(X509Certificate2 cert in caCerts)
+ {
+ _chain.ChainPolicy.ExtraStore.Add(cert);
+ }
+ }
+ }
+
+ private NativeConnectionInfo getNativeConnectionInfo()
+ {
+ IceSSL.NativeConnectionInfo info = new IceSSL.NativeConnectionInfo();
+ if(_stream.fd() != null)
+ {
+ IPEndPoint localEndpoint = (IPEndPoint)IceInternal.Network.getLocalAddress(_stream.fd());
+ info.localAddress = localEndpoint.Address.ToString();
+ info.localPort = localEndpoint.Port;
+ IPEndPoint remoteEndpoint = (IPEndPoint)IceInternal.Network.getRemoteAddress(_stream.fd());
+ if(remoteEndpoint != null)
+ {
+ info.remoteAddress = remoteEndpoint.Address.ToString();
+ info.remotePort = remoteEndpoint.Port;
+ }
+ info.rcvSize = IceInternal.Network.getRecvBufferSize(_stream.fd());
+ info.sndSize = IceInternal.Network.getSendBufferSize(_stream.fd());
+ }
+ if(_sslStream != null)
+ {
+#if UNITY
+ info.cipher = "";
+#else
+ info.cipher = _sslStream.CipherAlgorithm.ToString();
+ if(_chain.ChainElements != null && _chain.ChainElements.Count > 0)
+ {
+ info.nativeCerts = new X509Certificate2[_chain.ChainElements.Count];
+ for(int i = 0; i < _chain.ChainElements.Count; ++i)
+ {
+ info.nativeCerts[i] = _chain.ChainElements[i].Certificate;
+ }
+ }
+#endif
+
+ List<string> certs = new List<string>();
+#if !UNITY
+ if(info.nativeCerts != null)
+ {
+ foreach(X509Certificate2 cert in info.nativeCerts)
+ {
+ StringBuilder s = new StringBuilder();
+ s.Append("-----BEGIN CERTIFICATE-----\n");
+ s.Append(Convert.ToBase64String(cert.Export(X509ContentType.Cert)));
+ s.Append("\n-----END CERTIFICATE-----");
+ certs.Add(s.ToString());
+ }
+ }
+#endif
+ info.certs = certs.ToArray();
+ }
+ info.adapterName = _adapterName;
+ info.incoming = _incoming;
+ return info;
+ }
+
+ private bool startAuthenticate(IceInternal.AsyncCallback callback, object state)
+ {
+ try
+ {
+ _writeCallback = callback;
+ if(!_incoming)
+ {
+ //
+ // Client authentication.
+ //
+ _writeResult = _sslStream.BeginAuthenticateAsClient(_host,
+ _instance.certs(),
+ _instance.protocols(),
+ _instance.checkCRL() > 0,
+ writeCompleted,
+ state);
+ }
+ else
+ {
+#if UNITY
+ throw new Ice.FeatureNotSupportedException("ssl server socket");
+#else
+ //
+ // Server authentication.
+ //
+ // Get the certificate collection and select the first one.
+ //
+ X509Certificate2Collection certs = _instance.certs();
+ X509Certificate2 cert = null;
+ if(certs.Count > 0)
+ {
+ cert = certs[0];
+ }
+
+ _writeResult = _sslStream.BeginAuthenticateAsServer(cert,
+ _verifyPeer > 1,
+ _instance.protocols(),
+ _instance.checkCRL() > 0,
+ writeCompleted,
+ state);
+#endif
+ }
+ }
+ catch(IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ //
+ // This situation occurs when connectToSelf is called; the "remote" end
+ // closes the socket immediately.
+ //
+ throw new Ice.ConnectionLostException();
+ }
+ throw new Ice.SocketException(ex);
+ }
+#if !UNITY
+ catch(AuthenticationException ex)
+ {
+ Ice.SecurityException e = new Ice.SecurityException(ex);
+ e.reason = ex.Message;
+ throw e;
+ }
+#endif
+ catch(Exception ex)
+ {
+ throw new Ice.SyscallException(ex);
+ }
+
+ Debug.Assert(_writeResult != null);
+ return _writeResult.CompletedSynchronously;
+ }
+
+ private void finishAuthenticate()
+ {
+ Debug.Assert(_writeResult != null);
+
+ try
+ {
+ if(!_incoming)
+ {
+ _sslStream.EndAuthenticateAsClient(_writeResult);
+ }
+ else
+ {
+ _sslStream.EndAuthenticateAsServer(_writeResult);
+ }
+ }
+ catch(IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ //
+ // This situation occurs when connectToSelf is called; the "remote" end
+ // closes the socket immediately.
+ //
+ throw new Ice.ConnectionLostException();
+ }
+ throw new Ice.SocketException(ex);
+ }
+#if !UNITY
+ catch(AuthenticationException ex)
+ {
+ Ice.SecurityException e = new Ice.SecurityException(ex);
+ e.reason = ex.Message;
+ throw e;
+ }
+#endif
+ catch(Exception ex)
+ {
+ throw new Ice.SyscallException(ex);
+ }
+ }
+
+ private X509Certificate selectCertificate(
+ object sender,
+ string targetHost,
+ X509CertificateCollection localCertificates,
+ X509Certificate remoteCertificate,
+ string[] acceptableIssuers)
+ {
+ X509Certificate2Collection certs = _instance.engine().certs();
+
+ //
+ // Use the first certificate that match the acceptable issuers.
+ //
+ if(acceptableIssuers != null && acceptableIssuers.Length > 0 && certs != null && certs.Count > 0)
+ {
+ foreach(X509Certificate certificate in certs)
+ {
+ if(Array.IndexOf(acceptableIssuers, certificate.Issuer) != -1)
+ {
+ return certificate;
+ }
+ }
+ }
+
+ //
+ // Send first certificate
+ //
+ if(certs.Count > 0)
+ {
+ return certs[0];
+ }
+ return null;
+ }
+
+ private bool validationCallback(object sender, X509Certificate certificate, X509Chain chainEngine,
+ SslPolicyErrors policyErrors)
+ {
+#if !UNITY
+ SslPolicyErrors sslPolicyErrors = policyErrors;
+ bool valid = false;
+ if(certificate != null)
+ {
+ sslPolicyErrors = SslPolicyErrors.None;
+ valid = _chain.Build(new X509Certificate2(certificate));
+ if(_chain.ChainStatus.Length > 0)
+ {
+ sslPolicyErrors = SslPolicyErrors.RemoteCertificateChainErrors;
+ }
+ }
+
+ string message = "";
+ int errors = (int)sslPolicyErrors;
+ if((errors & (int)SslPolicyErrors.RemoteCertificateNotAvailable) > 0)
+ {
+ //
+ // The RemoteCertificateNotAvailable case does not appear to be possible
+ // for an outgoing connection. Since .NET requires an authenticated
+ // connection, the remote peer closes the socket if it does not have a
+ // certificate to provide.
+ //
+
+ if(_incoming)
+ {
+ if(_verifyPeer > 1)
+ {
+ if(_instance.securityTraceLevel() >= 1)
+ {
+ _instance.logger().trace(_instance.securityTraceCategory(),
+ "SSL certificate validation failed - client certificate not provided");
+ }
+ return false;
+ }
+ errors ^= (int)SslPolicyErrors.RemoteCertificateNotAvailable;
+ message = message + "\nremote certificate not provided (ignored)";
+ }
+ }
+
+ if((errors & (int)SslPolicyErrors.RemoteCertificateNameMismatch) > 0)
+ {
+ //
+ // Ignore this error here; we'll check the peer certificate in verifyPeer().
+ //
+ errors ^= (int)SslPolicyErrors.RemoteCertificateNameMismatch;
+ }
+
+ if((errors & (int)SslPolicyErrors.RemoteCertificateChainErrors) > 0)
+ {
+ if(_chain.ChainStatus != null)
+ {
+ int errorCount = _chain.ChainStatus.Length;
+ foreach(X509ChainStatus status in _chain.ChainStatus)
+ {
+ if(status.Status == X509ChainStatusFlags.UntrustedRoot &&
+ _instance.engine().caCerts() != null && valid)
+ {
+ //
+ // Untrusted root is OK when using our custom chain engine if
+ // the CA certificate is present in the chain policy extra store.
+ //
+ X509ChainElement e = _chain.ChainElements[_chain.ChainElements.Count - 1];
+ if(_chain.ChainPolicy.ExtraStore.Contains(e.Certificate))
+ {
+ --errorCount;
+ }
+ }
+ else if(status.Status == X509ChainStatusFlags.Revoked)
+ {
+ if(_instance.checkCRL() > 0)
+ {
+ message = message + "\ncertificate revoked";
+ }
+ else
+ {
+ message = message + "\ncertificate revoked (ignored)";
+ --errorCount;
+ }
+ }
+ else if(status.Status == X509ChainStatusFlags.RevocationStatusUnknown)
+ {
+ //
+ // If a certificate's revocation status cannot be determined, the strictest
+ // policy is to reject the connection.
+ //
+ if(_instance.checkCRL() > 1)
+ {
+ message = message + "\ncertificate revocation status unknown";
+ }
+ else
+ {
+ message = message + "\ncertificate revocation status unknown (ignored)";
+ --errorCount;
+ }
+ }
+ else if(status.Status == X509ChainStatusFlags.NoError)
+ {
+ --errorCount;
+ }
+ else
+ {
+ message = message + "\ncertificate chain error: " + status.Status.ToString();
+ }
+ }
+
+ if(errorCount == 0)
+ {
+ errors ^= (int)SslPolicyErrors.RemoteCertificateChainErrors;
+ }
+ }
+ }
+
+ if(errors > 0)
+ {
+ if(_instance.securityTraceLevel() >= 1)
+ {
+ if(message.Length > 0)
+ {
+ _instance.logger().trace(_instance.securityTraceCategory(),
+ "SSL certificate validation failed:" + message);
+ }
+ else
+ {
+ _instance.logger().trace(_instance.securityTraceCategory(),
+ "SSL certificate validation failed");
+ }
+ }
+ return false;
+ }
+ else if(message.Length > 0 && _instance.securityTraceLevel() >= 1)
+ {
+ _instance.logger().trace(_instance.securityTraceCategory(), "SSL certificate validation status:" +
+ message);
+ }
+#endif
+
+ return true;
+ }
+
+ internal void readCompleted(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ _readCallback(result.AsyncState);
+ }
+ }
+
+ internal void writeCompleted(IAsyncResult result)
+ {
+ if(!result.CompletedSynchronously)
+ {
+ _writeCallback(result.AsyncState);
+ }
+ }
+
+ private Instance _instance;
+ private IceInternal.StreamSocket _stream;
+ private string _host = "";
+ private string _adapterName = "";
+ private bool _incoming;
+ private SslStream _sslStream;
+ private int _verifyPeer;
+ private bool _authenticated;
+ private IAsyncResult _writeResult;
+ private IAsyncResult _readResult;
+ private IceInternal.AsyncCallback _readCallback;
+ private IceInternal.AsyncCallback _writeCallback;
+ private X509Chain _chain;
+ }
+}
diff --git a/csharp/src/IceSSL/TrustManager.cs b/csharp/src/IceSSL/TrustManager.cs
new file mode 100644
index 00000000000..98bbd1ff59f
--- /dev/null
+++ b/csharp/src/IceSSL/TrustManager.cs
@@ -0,0 +1,343 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Text;
+
+ sealed class TrustManager
+ {
+ internal TrustManager(Ice.Communicator communicator)
+ {
+ Debug.Assert(communicator != null);
+ communicator_ = communicator;
+ Ice.Properties properties = communicator.getProperties();
+ traceLevel_ = properties.getPropertyAsInt("IceSSL.Trace.Security");
+ string key = null;
+ try
+ {
+ key = "IceSSL.TrustOnly";
+ parse(properties.getProperty(key), rejectAll_, acceptAll_);
+ key = "IceSSL.TrustOnly.Client";
+ parse(properties.getProperty(key), rejectClient_, acceptClient_);
+ key = "IceSSL.TrustOnly.Server";
+ parse(properties.getProperty(key), rejectAllServer_, acceptAllServer_);
+ Dictionary<string, string> dict = properties.getPropertiesForPrefix("IceSSL.TrustOnly.Server.");
+ foreach(KeyValuePair<string, string> entry in dict)
+ {
+ key = entry.Key;
+ string name = key.Substring("IceSSL.TrustOnly.Server.".Length);
+ List<List<RFC2253.RDNPair>> reject = new List<List<RFC2253.RDNPair>>();
+ List<List<RFC2253.RDNPair>> accept = new List<List<RFC2253.RDNPair>>();
+ parse(entry.Value, reject, accept);
+ if(reject.Count > 0)
+ {
+ rejectServer_[name] = reject;
+ }
+ if(accept.Count > 0)
+ {
+ acceptServer_[name] = accept;
+ }
+ }
+ }
+ catch(RFC2253.ParseException e)
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: invalid property " + key + ":\n" + e.reason;
+ throw ex;
+ }
+ }
+
+ internal bool verify(NativeConnectionInfo info)
+ {
+ List<List<List<RFC2253.RDNPair>>> reject = new List<List<List<RFC2253.RDNPair>>>(),
+ accept = new List<List<List<RFC2253.RDNPair>>>();
+
+ if(rejectAll_.Count != 0)
+ {
+ reject.Add(rejectAll_);
+ }
+ if(info.incoming)
+ {
+ if(rejectAllServer_.Count != 0)
+ {
+ reject.Add(rejectAllServer_);
+ }
+ if(info.adapterName.Length > 0)
+ {
+ List<List<RFC2253.RDNPair>> p = null;
+ if(rejectServer_.TryGetValue(info.adapterName, out p))
+ {
+ reject.Add(p);
+ }
+ }
+ }
+ else
+ {
+ if(rejectClient_.Count != 0)
+ {
+ reject.Add(rejectClient_);
+ }
+ }
+
+ if(acceptAll_.Count != 0)
+ {
+ accept.Add(acceptAll_);
+ }
+ if(info.incoming)
+ {
+ if(acceptAllServer_.Count != 0)
+ {
+ accept.Add(acceptAllServer_);
+ }
+ if(info.adapterName.Length > 0)
+ {
+ List<List<RFC2253.RDNPair>> p = null;
+ if(acceptServer_.TryGetValue(info.adapterName, out p))
+ {
+ accept.Add(p);
+ }
+ }
+ }
+ else
+ {
+ if(acceptClient_.Count != 0)
+ {
+ accept.Add(acceptClient_);
+ }
+ }
+
+ //
+ // If there is nothing to match against, then we accept the cert.
+ //
+ if(reject.Count == 0 && accept.Count == 0)
+ {
+ return true;
+ }
+
+ //
+ // If there is no certificate then we match false.
+ //
+ if(info.nativeCerts != null && info.nativeCerts.Length > 0)
+ {
+#if UNITY
+ throw new Ice.FeatureNotSupportedException("certificate subjectName not available");
+#else
+ X500DistinguishedName subjectDN = info.nativeCerts[0].SubjectName;
+ string subjectName = subjectDN.Name;
+ Debug.Assert(subjectName != null);
+ try
+ {
+ //
+ // Decompose the subject DN into the RDNs.
+ //
+ if(traceLevel_ > 0)
+ {
+ if(info.incoming)
+ {
+ communicator_.getLogger().trace("Security", "trust manager evaluating client:\n" +
+ "subject = " + subjectName + "\n" +
+ "adapter = " + info.adapterName + "\n" +
+ "local addr = " + info.localAddress + ":" + info.localPort + "\n" +
+ "remote addr = " + info.remoteAddress + ":" + info.remotePort);
+ }
+ else
+ {
+ communicator_.getLogger().trace("Security", "trust manager evaluating server:\n" +
+ "subject = " + subjectName + "\n" +
+ "local addr = " + info.localAddress + ":" + info.localPort + "\n" +
+ "remote addr = " + info.remoteAddress + ":" + info.remotePort);
+ }
+ }
+
+ List<RFC2253.RDNPair> dn = RFC2253.parseStrict(subjectName);
+
+ //
+ // Unescape the DN. Note that this isn't done in
+ // the parser in order to keep the various RFC2253
+ // implementations as close as possible.
+ //
+ for(int i = 0; i < dn.Count; ++i)
+ {
+ RFC2253.RDNPair p = dn[i];
+ p.value = RFC2253.unescape(p.value);
+ dn[i] = p;
+ }
+
+ //
+ // Fail if we match anything in the reject set.
+ //
+ foreach(List<List<RFC2253.RDNPair>> matchSet in reject)
+ {
+ if(traceLevel_ > 0)
+ {
+ StringBuilder s = new StringBuilder("trust manager rejecting PDNs:\n");
+ stringify(matchSet, s);
+ communicator_.getLogger().trace("Security", s.ToString());
+ }
+ if(match(matchSet, dn))
+ {
+ return false;
+ }
+ }
+
+ //
+ // Succeed if we match anything in the accept set.
+ //
+ foreach(List<List<RFC2253.RDNPair>> matchSet in accept)
+ {
+ if(traceLevel_ > 0)
+ {
+ StringBuilder s = new StringBuilder("trust manager accepting PDNs:\n");
+ stringify(matchSet, s);
+ communicator_.getLogger().trace("Security", s.ToString());
+ }
+ if(match(matchSet, dn))
+ {
+ return true;
+ }
+ }
+ }
+ catch(RFC2253.ParseException e)
+ {
+ communicator_.getLogger().warning(
+ "IceSSL: unable to parse certificate DN `" + subjectName + "'\nreason: " + e.reason);
+ }
+
+ //
+ // At this point we accept the connection if there are no explicit accept rules.
+ //
+ return accept.Count == 0;
+#endif
+ }
+
+ return false;
+ }
+
+ private bool match(List<List<RFC2253.RDNPair>> matchSet, List<RFC2253.RDNPair> subject)
+ {
+ foreach(List<RFC2253.RDNPair> item in matchSet)
+ {
+ if(matchRDNs(item, subject))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private bool matchRDNs(List<RFC2253.RDNPair> match, List<RFC2253.RDNPair> subject)
+ {
+ foreach(RFC2253.RDNPair matchRDN in match)
+ {
+ bool found = false;
+ foreach(RFC2253.RDNPair subjectRDN in subject)
+ {
+ if(matchRDN.key.Equals(subjectRDN.key))
+ {
+ found = true;
+ if(!matchRDN.value.Equals(subjectRDN.value))
+ {
+ return false;
+ }
+ }
+ }
+ if(!found)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Note that unlike the C++ & Java implementation this returns unescaped data.
+ void parse(string value, List<List<RFC2253.RDNPair>> reject, List<List<RFC2253.RDNPair>> accept)
+ {
+ //
+ // As with the Java implementation, the DN that comes from
+ // the X500DistinguishedName does not necessarily match
+ // the user's input form. Therefore we need to normalize the
+ // data to match the C# forms.
+ //
+ List<RFC2253.RDNEntry> l = RFC2253.parse(value);
+ for(int i = 0; i < l.Count; ++i)
+ {
+ List<RFC2253.RDNPair> dn = l[i].rdn;
+ for(int j = 0; j < dn.Count; ++j)
+ {
+ RFC2253.RDNPair pair = dn[j];
+ // Normalize the RDN key.
+ if (pair.key == "emailAddress")
+ {
+ pair.key = "E";
+ }
+ else if (pair.key == "ST")
+ {
+ pair.key = "S";
+ }
+ // Unescape the value.
+ pair.value = RFC2253.unescape(pair.value);
+ dn[j] = pair;
+ }
+ if(l[i].negate)
+ {
+ reject.Add(l[i].rdn);
+ }
+ else
+ {
+ accept.Add(l[i].rdn);
+ }
+ }
+ }
+
+ private static void stringify(List<List<RFC2253.RDNPair>> matchSet, StringBuilder s)
+ {
+ bool addSemi = false;
+ foreach(List<RFC2253.RDNPair> rdnSet in matchSet)
+ {
+ if(addSemi)
+ {
+ s.Append(';');
+ }
+ addSemi = true;
+ bool addComma = false;
+ foreach(RFC2253.RDNPair rdn in rdnSet)
+ {
+ if(addComma)
+ {
+ s.Append(',');
+ }
+ addComma = true;
+ s.Append(rdn.key);
+ s.Append('=');
+ s.Append(rdn.value);
+ }
+ }
+ }
+
+ private Ice.Communicator communicator_;
+ private int traceLevel_;
+
+ private List<List<RFC2253.RDNPair>> rejectAll_ = new List<List<RFC2253.RDNPair>>();
+ private List<List<RFC2253.RDNPair>> rejectClient_ = new List<List<RFC2253.RDNPair>>();
+ private List<List<RFC2253.RDNPair>> rejectAllServer_ = new List<List<RFC2253.RDNPair>>();
+ private Dictionary<string, List<List<RFC2253.RDNPair>>> rejectServer_ =
+ new Dictionary<string, List<List<RFC2253.RDNPair>>>();
+
+ private List<List<RFC2253.RDNPair>> acceptAll_ = new List<List<RFC2253.RDNPair>>();
+ private List<List<RFC2253.RDNPair>> acceptClient_ = new List<List<RFC2253.RDNPair>>();
+ private List<List<RFC2253.RDNPair>> acceptAllServer_ = new List<List<RFC2253.RDNPair>>();
+ private Dictionary<string, List<List<RFC2253.RDNPair>>> acceptServer_ =
+ new Dictionary<string, List<List<RFC2253.RDNPair>>>();
+ }
+}
diff --git a/csharp/src/IceSSL/Util.cs b/csharp/src/IceSSL/Util.cs
new file mode 100644
index 00000000000..9fa6b8d0142
--- /dev/null
+++ b/csharp/src/IceSSL/Util.cs
@@ -0,0 +1,44 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+namespace IceSSL
+{
+ using System;
+ using System.Diagnostics;
+ using System.Security.Cryptography.X509Certificates;
+
+ /// <summary>
+ /// This class provides information about a connection to applications
+ /// that require information about a peer, for example, to implement
+ /// a CertificateVerifier.
+ /// </summary>
+ public sealed class NativeConnectionInfo : ConnectionInfo
+ {
+ /// <summary>
+ /// The certificate chain. This may be null if the peer did not
+ /// supply a certificate. The peer's certificate (if any) is the
+ /// first one in the chain.
+ /// </summary>
+ public System.Security.Cryptography.X509Certificates.X509Certificate2[] nativeCerts;
+ }
+
+ public sealed class Util
+ {
+ public static X509Certificate2 createCertificate(string certPEM)
+ {
+ char[] chars = certPEM.ToCharArray();
+ byte[] bytes = new byte[chars.Length];
+ for(int i = 0; i < chars.Length; ++i)
+ {
+ bytes[i] = (byte)chars[i];
+ }
+ return new X509Certificate2(bytes);
+ }
+ }
+}
diff --git a/csharp/src/IceSSL/generated/.gitignore b/csharp/src/IceSSL/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/IceSSL/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/IceStorm/.depend.mak b/csharp/src/IceStorm/.depend.mak
new file mode 100644
index 00000000000..de028ef4015
--- /dev/null
+++ b/csharp/src/IceStorm/.depend.mak
@@ -0,0 +1,13 @@
+
+IceStorm.cs: \
+ "$(slicedir)\IceStorm\IceStorm.ice" \
+ "$(slicedir)/Ice/Identity.ice" \
+ "$(slicedir)/Ice/SliceChecksumDict.ice" \
+ "$(slicedir)/IceStorm/Metrics.ice" \
+ "$(slicedir)/Ice/Metrics.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
+
+Metrics.cs: \
+ "$(slicedir)\IceStorm\Metrics.ice" \
+ "$(slicedir)/Ice/Metrics.ice" \
+ "$(slicedir)/Ice/BuiltinSequences.ice"
diff --git a/csharp/src/IceStorm/AssemblyInfo.cs b/csharp/src/IceStorm/AssemblyInfo.cs
new file mode 100644
index 00000000000..3ee62207196
--- /dev/null
+++ b/csharp/src/IceStorm/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("IceStorm")]
+[assembly: AssemblyDescription("IceStorm run-time support")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("IceStorm for .NET")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("Ice")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+[assembly: AssemblyDelaySign(false)]
+
+[assembly: ComVisible(false)]
diff --git a/csharp/src/IceStorm/Makefile b/csharp/src/IceStorm/Makefile
new file mode 100644
index 00000000000..2a02bcef619
--- /dev/null
+++ b/csharp/src/IceStorm/Makefile
@@ -0,0 +1,47 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+PKG = IceStorm
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)/$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs
+
+SLICE_SRCS = $(SDIR)/IceStorm.ice \
+ $(SDIR)/Metrics.ice
+
+SDIR = $(slicedir)/IceStorm
+GDIR = generated
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS := $(MCSFLAGS) -keyfile:$(KEYFILE)
+MCSFLAGS := $(MCSFLAGS) /doc:$(assembliesdir)/$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS := $(SLICE2CSFLAGS) -I$(slicedir) --ice
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) $(MCSFLAGS) $(call ref,Ice) $(subst /,$(DSEP),$^)
+
+install:: all
+ (cd $(assembliesdir); $(call installassembly,$(LIBNAME),$(PKG)); $(call installpolicy,$(POLICY)); \
+ $(call installmdb,$(LIBNAME).mdb); \
+ $(call installdata,$(PKG).xml,$(DESTDIR)$(install_assembliesdir)))
+
+ifeq ($(GACINSTALL),yes)
+install:: all
+ $(call installdata,../../lib/pkgconfig/$(PKG).pc,$(DESTDIR)$(install_pkgconfigdir))
+endif
+
+clean::
+ -rm -f $(assembliesdir)/$(PKG).xml
diff --git a/csharp/src/IceStorm/Makefile.mak b/csharp/src/IceStorm/Makefile.mak
new file mode 100644
index 00000000000..7094b571653
--- /dev/null
+++ b/csharp/src/IceStorm/Makefile.mak
@@ -0,0 +1,52 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+PKG = IceStorm
+LIBNAME = $(PKG).dll
+TARGETS = $(assembliesdir)\$(LIBNAME)
+POLICY_TARGET = $(POLICY).dll
+
+SRCS = AssemblyInfo.cs
+
+GEN_SRCS = $(GDIR)\IceStorm.cs \
+ $(GDIR)\Metrics.cs
+
+SDIR = $(slicedir)\IceStorm
+GDIR = generated
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCSFLAGS = $(MCSFLAGS) -target:library -out:$(TARGETS) -warnaserror-
+MCSFLAGS = $(MCSFLAGS) -keyfile:"$(KEYFILE)"
+MCSFLAGS = $(MCSFLAGS) /doc:$(assembliesdir)\$(PKG).xml /nowarn:1591
+
+SLICE2CSFLAGS = $(SLICE2CSFLAGS) -I$(slicedir) --ice
+
+$(TARGETS):: $(SRCS) $(GEN_SRCS)
+ $(MCS) /baseaddress:0x21000000 $(MCSFLAGS) -r:$(refdir)\Ice.dll $(SRCS) $(GEN_SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(assembliesdir)\$(PKG).pdb
+!endif
+
+clean::
+ del /q $(assembliesdir)\$(PKG).xml
+
+install:: all
+ copy $(assembliesdir)\$(LIBNAME) "$(install_assembliesdir)"
+ copy $(assembliesdir)\$(PKG).xml "$(install_assembliesdir)"
+!if "$(generate_policies)" == "yes"
+ copy $(assembliesdir)\$(POLICY_TARGET) "$(install_assembliesdir)"
+!endif
+!if "$(DEBUG)" == "yes"
+ copy $(assembliesdir)\$(PKG).pdb "$(install_assembliesdir)"
+!endif
diff --git a/csharp/src/IceStorm/generated/.gitignore b/csharp/src/IceStorm/generated/.gitignore
new file mode 100644
index 00000000000..39af5887579
--- /dev/null
+++ b/csharp/src/IceStorm/generated/.gitignore
@@ -0,0 +1 @@
+# Dummy file, so that git retains this otherwise empty directory.
diff --git a/csharp/src/Makefile b/csharp/src/Makefile
new file mode 100644
index 00000000000..4b9a3e17400
--- /dev/null
+++ b/csharp/src/Makefile
@@ -0,0 +1,21 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..
+
+include $(top_srcdir)/config/Make.rules.cs
+
+SUBDIRS = Ice IceStorm Glacier2 IcePatch2 IceGrid IceBox IceDiscovery IceLocatorDiscovery
+
+$(EVERYTHING)::
+ @for subdir in $(SUBDIRS); \
+ do \
+ echo "making $@ in $$subdir"; \
+ ( cd $$subdir && $(MAKE) $@ ) || exit 1; \
+ done
diff --git a/csharp/src/Makefile.mak b/csharp/src/Makefile.mak
new file mode 100644
index 00000000000..1c73e5fd7ae
--- /dev/null
+++ b/csharp/src/Makefile.mak
@@ -0,0 +1,26 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+SUBDIRS = Ice IceStorm Glacier2 IcePatch2 IceGrid
+!if "$(COMPACT)" != "yes" && "$(SILVERLIGHT)" != "yes"
+SUBDIRS = $(SUBDIRS) IceSSL IceDiscovery IceLocatorDiscovery
+!endif
+
+!if "$(SILVERLIGHT)" != "yes"
+SUBDIRS = $(SUBDIRS) IceBox PolicyServer
+!endif
+
+$(EVERYTHING)::
+ @for %i in ( $(SUBDIRS) ) do \
+ @echo "making $@ in %i" && \
+ cmd /c "cd %i && $(MAKE) -nologo -f Makefile.mak $@" || exit 1
diff --git a/csharp/src/PolicyServer/AssemblyInfo.cs b/csharp/src/PolicyServer/AssemblyInfo.cs
new file mode 100644
index 00000000000..37d7139fc91
--- /dev/null
+++ b/csharp/src/PolicyServer/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("PolicyServer")]
+[assembly: AssemblyDescription("Ice for Silveright policy server")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("ZeroC, Inc.")]
+[assembly: AssemblyProduct("Ice PolicyServer")]
+[assembly: AssemblyCopyright("Copyright © 2012-2015 ZeroC, Inc.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("3.6.0")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("ddd45a23-8a57-4389-aad4-401a2ae2a7fa")]
diff --git a/csharp/src/PolicyServer/Makefile b/csharp/src/PolicyServer/Makefile
new file mode 100644
index 00000000000..244f1c54e0b
--- /dev/null
+++ b/csharp/src/PolicyServer/Makefile
@@ -0,0 +1,26 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+POLICYSERVER = $(bindir)/policyserver.exe
+TARGETS = $(POLICYSERVER)
+SRCS = AssemblyInfo.cs PolicyServer.cs
+
+include $(top_srcdir)/config/Make.rules.cs
+
+MCSFLAGS := $(MCSFLAGS) -target:exe
+
+
+$(POLICYSERVER): $(SRCS) $(assembliesdir)/$(LIBNAME)
+ $(MCS) $(MCSFLAGS) -out:$@ $(SRCS)
+
+install:: all
+ $(call installprogram,$(POLICYSERVER),$(DESTDIR)$(install_bindir))
+ $(call installmdb,$(POLICYSERVER).mdb)
diff --git a/csharp/src/PolicyServer/Makefile.mak b/csharp/src/PolicyServer/Makefile.mak
new file mode 100644
index 00000000000..46c89d13b6c
--- /dev/null
+++ b/csharp/src/PolicyServer/Makefile.mak
@@ -0,0 +1,44 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice for Silverlight is licensed to you under the terms
+# described in the ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+TARGETS = $(bindir)\policyserver.exe
+
+SRCS = PolicyServer.cs \
+ AssemblyInfo.cs
+
+!include $(top_srcdir)\config\Make.rules.mak.cs
+
+MCS = csc -nologo
+
+MCSFLAGS = -warnaserror -d:MAKEFILE_BUILD
+!if "$(DEBUG)" == "yes"
+MCSFLAGS = $(MCSFLAGS) -debug -define:DEBUG
+!endif
+
+!if "$(OPTIMIZE)" == "yes"
+MCSFLAGS = $(MCSFLAGS) -optimize+
+!endif
+
+MCSFLAGS = $(MCSFLAGS) -target:exe
+
+$(bindir)\policyserver.exe: $(SRCS)
+ $(MCS) $(MCSFLAGS) -out:$@ $(SRCS)
+
+!if "$(DEBUG)" == "yes"
+clean::
+ del /q $(bindir)\policyserver.pdb
+!endif
+
+install:: all
+ copy $(bindir)\policyserver.exe "$(install_bindir)"
+!if "$(DEBUG)" == "yes"
+ copy $(bindir)\policyserver.pdb "$(install_bindir)"
+!endif \ No newline at end of file
diff --git a/csharp/src/PolicyServer/PolicyServer.cs b/csharp/src/PolicyServer/PolicyServer.cs
new file mode 100644
index 00000000000..153db23627d
--- /dev/null
+++ b/csharp/src/PolicyServer/PolicyServer.cs
@@ -0,0 +1,127 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Text;
+
+namespace PolicyService
+{
+
+//
+// This class implements a simple policy server for
+// Silverlight.
+//
+public sealed class PolicyServer : IDisposable
+{
+ public PolicyServer(string ipAddress, string policyFile)
+ {
+ _ipAddress = ipAddress;
+ _policyFile = policyFile;
+ }
+
+ public void Start()
+ {
+ IPAddress address = null;
+ try
+ {
+ address = IPAddress.Parse(_ipAddress);
+ }
+ catch(System.FormatException ex)
+ {
+ Console.WriteLine("Invalid IP address format: " + _ipAddress);
+ Console.WriteLine(ex.ToString());
+ return;
+ }
+ // Read policy file
+ try
+ {
+ _policyBytes = File.ReadAllBytes(_policyFile);
+ }
+ catch(System.IO.IOException ex)
+ {
+ Console.WriteLine("Error reading policy file: " + _policyFile);
+ Console.WriteLine(ex.ToString());
+ return;
+ }
+ _policyListener = new TcpListener(address, 943);
+ try
+ {
+ // Listen for policy requests
+ _policyListener.Start();
+ }
+ catch(SocketException ex)
+ {
+ Console.WriteLine("Error starting Policy Server:\n" + ex.ToString());
+ return;
+ }
+ Console.WriteLine("Policy Server started...");
+ // Start policy response thread
+ Thread policyThread = new Thread(ServePolicy);
+ policyThread.IsBackground = true;
+ policyThread.Start();
+ policyThread.Join();
+ }
+
+ private void ServePolicy()
+ {
+ while(true)
+ {
+ Console.WriteLine("Accepting Policy Requests...");
+ using(Socket client = _policyListener.AcceptSocket())
+ {
+ Console.WriteLine("Policy Request Accepted...");
+
+ // Get policy request header
+ byte[] buffer = new byte[1024];
+ int bytesReceived = client.Receive(buffer);
+
+ // Basic check of request header
+ string header = Encoding.UTF8.GetString(buffer, 0, bytesReceived);
+ if(header == "<policy-file-request/>")
+ {
+ client.Send(_policyBytes, 0, _policyBytes.Length, SocketFlags.None);
+ }
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ }
+
+ private string _ipAddress = "";
+ private string _policyFile = "";
+ private byte[] _policyBytes = null; // byte array used to store the response in memory.
+ private TcpListener _policyListener = null;
+}
+
+class Program
+{
+ static void Main(string[] args)
+ {
+ if(args.Length == 2)
+ {
+ // Start our Policy Service
+ using (PolicyServer server = new PolicyServer(args[0], args[1]))
+ {
+ server.Start();
+ }
+ }
+ else
+ {
+ Console.WriteLine("Usage: PolicyServer <ip-address> <policy-file>");
+ }
+ }
+}
+
+}