private static void _setupNewSocketServer(RelayNode relayNode, string instanceName, int portNumber, bool useAsyncHandler, ConnectionWhitelist connectionWhitelist, bool whitelistOnly) { //all public method should lock(_syncRoot) so we should be ok SocketServer socketServer = new SocketServer(instanceName, portNumber); IMessageHandler messageHandler; if (useAsyncHandler) { messageHandler = new SocketServerAsyncMessageHandler(relayNode, relayNode); } else { messageHandler = new SocketServerRelayMessageHandler(relayNode, relayNode); } socketServer.MessageHandler = messageHandler; socketServer.AcceptingConnectionsDelegate = relayNode.AcceptNewConnection; socketServer.WhitelistOnly = whitelistOnly; socketServer.Start(connectionWhitelist); _socketServer = socketServer; if (_cachedWhiteListValue != null) { _socketServer.WhitelistOnly = _cachedWhiteListValue.Value; _cachedWhiteListValue = null; } }
/// <summary> /// Binds the server to a port and starts the server to accept new connections. /// </summary> /// <param name="instanceName"></param> /// <param name="portNumber"></param> /// <param name="relayNode">The node to handle new message requests.</param> /// <param name="useAsyncHandler">A value indicating if out messages should be asynchronous.</param> /// <param name="connectionWhitelist">A delegate that tells if a given /// remote endpoint is allowable to connect.</param> /// <param name="whitelistOnly">Whether to only allow whitelisted connections.</param> public static void Initialize(string instanceName, int portNumber, RelayNode relayNode, bool useAsyncHandler, ConnectionWhitelist connectionWhitelist, bool whitelistOnly) { lock (_syncRoot) { _myRelayNode = relayNode; _connectionWhitelist = connectionWhitelist; _setupNewSocketServer(relayNode, instanceName, portNumber, useAsyncHandler, _connectionWhitelist, whitelistOnly); } }
/// <summary> /// Closes out any connections that don't satisfy a supplied callback. /// </summary> /// <param name="connectionWhitelist"><see cref="ConnectionWhitelist"/> /// callback that takes the remote <see cref="IPEndPoint"/> and /// returns a <see cref="Boolean"/> specifying whether to retain /// the connection.</param> /// <remarks>If the callback returns <see langword="true"/> then /// the connection is retained; otherwise it is closed.</remarks> public void PurgeNotWhitelisted(ConnectionWhitelist connectionWhitelist) { var purgedStates = new List <ConnectionState>(); connectionsLock.ReadUpgradable(delegate { var count = connections.Count; var keys = new IPEndPoint[count]; connections.Keys.CopyTo(keys, 0); var values = new ConnectionState[count]; connections.Values.CopyTo(values, 0); for (var idx = count - 1; idx >= 0; --idx) { var key = keys[idx]; if (!connectionWhitelist(key)) { var value = values[idx]; connectionsLock.Write(delegate { connections.Remove(key); DecrementCount(); }); purgedStates.Add(value); } } }); foreach (var state in purgedStates) { try { Close(state); } catch (Exception ex) { if (SocketServer.log.IsErrorEnabled) { SocketServer.log.ErrorFormat("Exception doing whitelist check of sockets for closing: {0}", ex.ToString()); } } } }
private static void _setupNewSocketServer(RelayNode relayNode, string instanceName, int portNumber, bool useAsyncHandler, ConnectionWhitelist connectionWhitelist, bool whitelistOnly) { //all public method should lock(_syncRoot) so we should be ok SocketServer socketServer = new SocketServer(instanceName, portNumber); IMessageHandler messageHandler; if (useAsyncHandler) { messageHandler = new SocketServerAsyncMessageHandler(relayNode, relayNode); } else { messageHandler = new SocketServerRelayMessageHandler(relayNode, relayNode); } socketServer.MessageHandler = messageHandler; socketServer.AcceptingConnectionsDelegate = relayNode.AcceptNewRequest; socketServer.AcceptingRequestsDelegate = relayNode.AcceptNewRequest; socketServer.WhitelistOnly = whitelistOnly; socketServer.Start(connectionWhitelist); _socketServer = socketServer; if (_cachedWhiteListValue != null) { _socketServer.WhitelistOnly = _cachedWhiteListValue.Value; _cachedWhiteListValue = null; } }
/// <summary> /// Closes out any connections that don't satisfy a supplied callback. /// </summary> /// <param name="connectionWhitelist"><see cref="ConnectionWhitelist"/> /// callback that takes the remote <see cref="IPEndPoint"/> and /// returns a <see cref="Boolean"/> specifying whether to retain /// the connection.</param> /// <remarks>If the callback returns <see langword="true"/> then /// the connection is retained; otherwise it is closed.</remarks> public void PurgeNotWhitelisted(ConnectionWhitelist connectionWhitelist) { var purgedStates = new List<ConnectionState>(); connectionsLock.ReadUpgradable(delegate { var count = connections.Count; var keys = new IPEndPoint[count]; connections.Keys.CopyTo(keys, 0); var values = new ConnectionState[count]; connections.Values.CopyTo(values, 0); for(var idx = count - 1; idx >= 0; --idx) { var key = keys[idx]; if (!connectionWhitelist(key)) { var value = values[idx]; connectionsLock.Write(delegate { connections.Remove(key); DecrementCount(); }); purgedStates.Add(value); } } }); foreach(var state in purgedStates) { try { Close(state); } catch (Exception ex) { if (SocketServer.log.IsErrorEnabled) SocketServer.log.ErrorFormat("Exception doing whitelist check of sockets for closing: {0}",ex.ToString()); } } }
/// <summary> /// Stop listening for connections and dispose of resources /// </summary> public void Stop() { if (!isRunning) { return; } if (log.IsInfoEnabled) log.Info("Socket Server Shutting Down."); isRunning = false; if (log.IsInfoEnabled) log.Info("Socket Server Disconnecting Listener."); if (listener.Connected) { listener.Shutdown(SocketShutdown.Both); listener.Disconnect(false); } listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); listener.Close(); if (countersInitialized) { if (requestsQueued.RawValue > 0) //give queued requests a chance to execute { for (int waits = 0; waits < 5; waits++) { Thread.Sleep(500); if (requestsQueued.RawValue == 0) break; } } } //try to get rid of all connections //kill the connection watcher timer loop if (connectionWatcher != null) { connectionWatcher.Change(Timeout.Infinite, Timeout.Infinite); connectionWatcher = null; } if (log.IsInfoEnabled) log.Info("Socket Server Closing Down Sockets."); connections.Purge(); if (log.IsInfoEnabled) log.Info("Shutting down dispatchers."); OnewayDispatcher.Dispose(); OnewayDispatcher = null; SyncDispatcher.Dispose(); SyncDispatcher = null; if (countersInitialized) { socketCountCounter.RawValue = 0; allocatedBuffers.RawValue = 0; } connectionWhitelist = null; if (log.IsInfoEnabled) log.InfoFormat("MySpace SocketTransport Server stopped on port {0}", this.portNumber); }
/// <summary> /// Start listening for connections. /// </summary> /// <param name="connectionWhiteList">An optional <see cref="ConnectionWhitelist"/> /// used to evaluate whether incoming and existing connections are /// whitelisted.</param> public void Start(ConnectionWhitelist connectionWhiteList) { if (isRunning) { if (log.IsWarnEnabled) log.Warn("Attempt to start already running socket server on port " + this.portNumber); return; } this.connectionWhitelist = connectionWhiteList; InitializeCounters(); GetConfig(); if (log.IsInfoEnabled) log.InfoFormat("Using a memory stream pool with an initial size of {0} bytes, reusing buffers {1} times. Reusing connectionstates {2} times. Using {3} sync threads and {4} one way threads", config.InitialMessageSize, config.BufferPoolReuses, config.ConnectionStateReuses, SyncThreads, OnewayThreads); bufferPool = new MemoryStreamPool(config.InitialMessageSize, config.BufferPoolReuses); if (countersInitialized) { bufferPool.AllocatedItemsCounter = this.allocatedBuffers; } buildConnectionStateDelegate = new ResourcePool<ConnectionState>.BuildItemDelegate(BuildConnectionState); resetConnectionStateDelegate = new ResourcePool<ConnectionState>.ResetItemDelegate(ResetConnectionState); connectionStatePool = new ResourcePool<ConnectionState>(buildConnectionStateDelegate, resetConnectionStateDelegate); connectionStatePool.MaxItemReuses = config.ConnectionStateReuses; listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); connections = new ConnectionList(socketCountCounter); connectionCheckInterval = config.ConnectionCheckIntervalSeconds * 1000; connectionWatcher = new Timer(new TimerCallback(CheckConnections), null, connectionCheckInterval, connectionCheckInterval); int currentWorker, currentCompletion, oldWorker, oldCompletion; ThreadPool.GetAvailableThreads(out currentWorker, out currentCompletion); oldWorker = currentWorker; oldCompletion= currentCompletion; if (config.MaximumWorkerThreads > 0) currentWorker = config.MaximumWorkerThreads; if (config.MaximumCompletionPortThreads > 0) currentCompletion = config.MaximumCompletionPortThreads; bool maxSet = ThreadPool.SetMaxThreads(currentWorker, currentCompletion); if (config.MaximumWorkerThreads > 0 || config.MaximumCompletionPortThreads > 0) { if (maxSet == false) { if (log.IsWarnEnabled) { log.WarnFormat("FAILED to change max ThreadPool threads from ({0}worker/{1}completion) to ({2}worker/{3}completion)", oldWorker, oldCompletion, currentWorker, currentCompletion); } } else { if (log.IsInfoEnabled) log.InfoFormat("Successfully changed max ThreadPool threads from ({0}worker/{1}completion) to ({2}worker/{3}completion)", oldWorker, oldCompletion, currentWorker, currentCompletion); } } //kick off CCR OnewayDispatcher = new Dispatcher(OnewayThreads, ThreadPriority.Normal, true, "Socket Server OneWay:" + portNumber.ToString()); SyncDispatcher = new Dispatcher(SyncThreads, ThreadPriority.AboveNormal, true, "Socket Server Sync:" + portNumber.ToString()); OnewayMessageQueue = new DispatcherQueue("Socket Server " + portNumber.ToString() + " one way", OnewayDispatcher, TaskExecutionPolicy.ConstrainQueueDepthThrottleExecution, config.OnewayQueueDepth); SyncMessageQueue = new DispatcherQueue("Socket Server " + portNumber.ToString() + " sync", SyncDispatcher, TaskExecutionPolicy.ConstrainQueueDepthThrottleExecution, config.SyncQueueDepth); Arbiter.Activate(OnewayMessageQueue, Arbiter.Receive<ProcessState>(true, OnewayMessagePort, delegate(ProcessState state) { ProcessCall(state); })); Arbiter.Activate(SyncMessageQueue, Arbiter.Receive<ProcessState>(true, SyncMessagePort, delegate(ProcessState state) { ProcessCall(state); })); listener.Bind(new IPEndPoint(IPAddress.Any, this.portNumber)); listener.Listen(500); isRunning = true; listener.BeginAccept(acceptCallBack, listener); timerThread = new Thread(TimerStart); timerThread.IsBackground = true; timerThread.Start(); if (log.IsInfoEnabled) log.Info("MySpace SocketTransport Server started on port " + this.portNumber); }