/// <summary>
        /// Accepts an incoming connection.
        /// </summary>
        /// <param name="url">The name of the share.</param>
        /// <param name="localUri">URI of the local host.</param>
        /// <param name="protocolVersion">The version of the protocol supported by the remote host.</param>
        /// <param name="remoteUri">Uri of the remote host.</param>
        /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param>
        /// <returns>The established connection.</returns>
        private SharedMemoryConnection LowLevel_AcceptConnection_1(string url, string localUri, byte protocolVersion, out string remoteUri, out int remoteHostUniqueIdentifier)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            using (new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                {
                    throw OperationException.WrapException(this._disposeReason);
                }
            }

            remoteUri = null;
            Stream inputStream  = null;
            Stream outputStream = null;

            remoteHostUniqueIdentifier = 0;

            // the maximum time during which the connection must be established
            int timeout = GenuineUtility.GetTimeout((TimeSpan)this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]);

            // open the client's share
            SharedMemoryConnection sharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, url, false, true);

            // LOG:
            if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0)
            {
                binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_AcceptConnection",
                                                              LogMessageType.ConnectionParameters, null, null, this.ITransportContext.IParameterProvider,
                                                              GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, sharedMemoryConnection.DbgConnectionId,
                                                              "The connection is being established to \"{0}\".", url);
            }

            // get the connection-level Security Session
            string          connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string;
            SecuritySession securitySession       = null;

            if (connectionLevelSSName != null)
            {
                securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null);
            }

            // establish it
            if (securitySession != null && !securitySession.IsEstablished)
            {
                for ( ; ;)
                {
                    inputStream = Stream.Null;

                    try
                    {
                        // prepare streams
                        inputStream  = sharedMemoryConnection.LowLevel_ReadSync(timeout);
                        outputStream = securitySession.EstablishSession(inputStream, true);

                        if (outputStream == null)
                        {
                            break;
                        }

                        // send a packet to the remote host
                        sharedMemoryConnection.LowLevel_SendSync(outputStream, timeout);
                        if (securitySession.IsEstablished)
                        {
                            break;
                        }
                    }
                    finally
                    {
                        if (inputStream != null)
                        {
                            inputStream.Close();
                        }
                        if (outputStream != null)
                        {
                            outputStream.Close();
                        }
                    }
                }
            }

            sharedMemoryConnection.ConnectionLevelSecurity = securitySession;
            HostInformation remote = null;

            // read remote info
            using (Stream remoteUriStream = sharedMemoryConnection.LowLevel_ReadSync(timeout))
            {
                BinaryReader binaryReader = new BinaryReader(remoteUriStream);
                remoteUri = binaryReader.ReadString();

                remote = this.ITransportContext.KnownHosts[remoteUri];
                if (protocolVersion > 0)
                {
                    remoteHostUniqueIdentifier = binaryReader.ReadInt32();
                }
            }

            // now send connection info through the established connection
            using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false))
            {
                // serialize local info
                BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo);
                binaryWriter.Write((string)localUri);

                if (protocolVersion > 0)
                {
                    binaryWriter.Write((int)remote.LocalHostUniqueIdentifier);
                }

                // and send it
                sharedMemoryConnection.LowLevel_SendSync(serializedLocalInfo, timeout);
            }

            // LOG:
            if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0)
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_AcceptConnection_1",
                                           LogMessageType.ConnectionEstablished, null, null, remote, null,
                                           GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                           securitySession, connectionLevelSSName,
                                           sharedMemoryConnection.DbgConnectionId, (int)GenuineConnectionType.Persistent, 0, 0, this.GetType().Name, null, null, null,
                                           "The connection to the remote host has been established.");
            }

            return(sharedMemoryConnection);
        }
예제 #2
0
        /// <summary>
        /// Starts listening to the specified end point and accepting incoming connections.
        /// </summary>
        /// <param name="endPoint">The end point.</param>
        public override void StartListening(object endPoint)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            this._closing = false;

            // LOG:
            if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0)
            {
                binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "UdpConnectionManager.StartListening",
                                                              LogMessageType.ConnectionParameters, null, null, this.ITransportContext.IParameterProvider,
                                                              GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId,
                                                              "UDP socket is being associated with the end point: {0}.", endPoint.ToString());
            }

            // get the ip end point
            IPEndPoint ipEndPoint = null;
            int        port;
            string     url;

            try
            {
                url        = (string)endPoint;
                url        = GenuineUtility.SplitToHostAndPort(url, out port);
                ipEndPoint = new IPEndPoint(GenuineUtility.ResolveIPAddress(url), port);
            }
            catch (Exception ex)
            {
                // LOG:
                if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0)
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "UdpConnectionManager.StartListening",
                                               LogMessageType.ListeningStarted, ex, null, null, null,
                                               GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                               null, null, this.DbgConnectionId, 0, 0, 0, null, null, null, null,
                                               "The listening socket cannot be associated with the {0} local end point.", endPoint.ToString());
                }

                throw GenuineExceptions.Get_Server_IncorrectAddressToListen(endPoint as string);
            }

            lock (this)
            {
                if (this._socket != null)
                {
                    throw GenuineExceptions.Get_Server_EndPointIsAlreadyBeingListenedTo(this._socket.LocalEndPoint.ToString());
                }

                // initialize the socket
                this._socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                if (this.ITransportContext.IParameterProvider[GenuineParameter.UdpTtl] != null)
                {
                    this._socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, (int)this.ITransportContext.IParameterProvider[GenuineParameter.UdpTtl]);
                }

                // Receive buffer size
                this._socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, (int)this.ITransportContext.IParameterProvider[GenuineParameter.UdpReceiveBuffer]);
                this._socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);

                this._socket.Bind(ipEndPoint);

                // if it's an IP multicast sender
                if (this.ITransportContext.IParameterProvider[GenuineParameter.UdpMulticastTo] != null)
                {
                    try
                    {
                        url = (string)this.ITransportContext.IParameterProvider[GenuineParameter.UdpMulticastTo];
                        url = GenuineUtility.SplitToHostAndPort(url, out port);
                        this._multicastTo = new IPEndPoint(GenuineUtility.ResolveIPAddress(url), port);

                        this._socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
                        if (this.ITransportContext.IParameterProvider[GenuineParameter.UdpTtl] != null)
                        {
                            this._socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, (int)this.ITransportContext.IParameterProvider[GenuineParameter.UdpTtl]);
                        }
                    }
                    catch (Exception)
                    {
                        throw GenuineExceptions.Get_Channel_InvalidParameter("UdpMulticastTo");
                    }
                }

                // and join to the specified broadcast network
                if (this.ITransportContext.IParameterProvider[GenuineParameter.UdpJoinTo] != null)
                {
                    string joinTo = (string)this.ITransportContext.IParameterProvider[GenuineParameter.UdpJoinTo];
                    this._socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);

                    IPAddress       ipAddressToJoinTo = GenuineUtility.ResolveIPAddress(joinTo);
                    MulticastOption multicastOption   = new MulticastOption(ipAddressToJoinTo, ipEndPoint.Address);
                    this._socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, multicastOption);
                }

                // initiate receiving
                Thread receivingThread = new Thread(new ThreadStart(this.ReceiveSynchronously));
                receivingThread.IsBackground = true;
                receivingThread.Start();

                // LOG:
                if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0)
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "UdpConnectionManager.StartListening",
                                               LogMessageType.ConnectionEstablished, null, null, null, null,
                                               GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                               null, null,
                                               this.DbgConnectionId, (int)GenuineConnectionType.Invocation, 0, 0, this.GetType().Name, this._socket.LocalEndPoint.ToString(), null, null,
                                               "The UDP socket is ready for action.");
                }
            }
        }
        /// <summary>
        /// Opens a connection to the host specified by the url.
        /// </summary>
        /// <param name="remote">The HostInformation of the Remote Host.</param>
        /// <param name="localUri">The uri of the local host.</param>
        /// <param name="remoteUri">The uri of the remote host.</param>
        /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param>
        /// <returns>The established connection.</returns>
        private SharedMemoryConnection LowLevel_OpenConnection(HostInformation remote, string localUri, out string remoteUri, out int remoteHostUniqueIdentifier)
        {
            using (new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                {
                    throw OperationException.WrapException(this._disposeReason);
                }
            }

            remoteUri = null;
            Stream inputStream  = null;
            Stream outputStream = null;
            string url          = remote.Url;

            // the maximum time during which the connection must be established
            int timeout = GenuineUtility.GetTimeout((TimeSpan)this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]);

            IParameterProvider parameters = this.ITransportContext.IParameterProvider;

            string mutexName = GenuineSharedMemoryChannel.ConstructSharedObjectName(
                "MUTEX" + url, parameters);
            string clientConnected = GenuineSharedMemoryChannel.ConstructSharedObjectName(
                "CC" + url, parameters);
            string clientAccepted = GenuineSharedMemoryChannel.ConstructSharedObjectName(
                "CA" + url, parameters);

            // open the server share
            SharedMemoryConnection serverSharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, url, false, false);

            // LOG:
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0)
            {
                binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_OpenConnection",
                                                              LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider,
                                                              GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, serverSharedMemoryConnection.DbgConnectionId,
                                                              "A Shared Memory connection is being established.");
            }

            // and create the local share
            string shareName = "gshmem://" + Guid.NewGuid().ToString("N");
            SharedMemoryConnection sharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, shareName, true, true);

            BinaryWriter connectionInformation = MessageCoder.SerializeConnectionHeader(MessageCoder.PROTOCOL_VERSION, GenuineConnectionType.Persistent, "Default");

            connectionInformation.Write(shareName);

            // let the server know that a client's share is ready
            Mutex mutex = null;

            try
            {
                mutex = WindowsAPI.OpenMutex(mutexName);

                NamedEvent _clientConnected = NamedEvent.OpenNamedEvent(clientConnected);
                NamedEvent _clientAccepted  = NamedEvent.OpenNamedEvent(clientAccepted);

                if (!GenuineUtility.WaitOne(mutex, GenuineUtility.GetMillisecondsLeft(timeout)))
                {
                    throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Can not acquire the lock for the global mutex.");
                }

                // wait until server accepts this client
                _clientAccepted.ManualResetEvent.Reset();
                _clientConnected.ManualResetEvent.Set();

                // copy client's name
                serverSharedMemoryConnection.LowLevel_SendSync(connectionInformation.BaseStream, timeout);

                if (!GenuineUtility.WaitOne(_clientAccepted.ManualResetEvent, GenuineUtility.GetMillisecondsLeft(timeout)))
                {
                    throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Remote server did not accept a request within the specified time span.");
                }
            }
            finally
            {
                if (mutex != null)
                {
                    try
                    {
                        mutex.ReleaseMutex();
                    }
                    catch
                    {
                    }

                    try
                    {
                        mutex.Close();
                    }
                    catch
                    {
                    }
                }
            }

            // get the connection-level Security Session
            string          connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string;
            SecuritySession securitySession       = null;

            if (connectionLevelSSName != null)
            {
                securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null);
            }

            // establish it
            if (securitySession != null && !securitySession.IsEstablished)
            {
                bool firstPass = true;
                for ( ; ;)
                {
                    inputStream = Stream.Null;

                    try
                    {
                        // prepare streams
                        if (!firstPass)
                        {
                            inputStream = sharedMemoryConnection.LowLevel_ReadSync(timeout);
                        }
                        else
                        {
                            firstPass = false;
                        }

                        outputStream = securitySession.EstablishSession(inputStream, true);

                        if (outputStream == null)
                        {
                            break;
                        }

                        // send a packet to the remote host
                        sharedMemoryConnection.LowLevel_SendSync(outputStream, timeout);
                        if (securitySession.IsEstablished)
                        {
                            break;
                        }
                    }
                    finally
                    {
                        if (inputStream != null)
                        {
                            inputStream.Close();
                        }
                        if (outputStream != null)
                        {
                            outputStream.Close();
                        }
                    }
                }
            }

            sharedMemoryConnection.ConnectionLevelSecurity = securitySession;

            // now send connection info through the established connection
            using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false))
            {
                // serialize local info
                BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo);
                binaryWriter.Write((string)localUri);
                binaryWriter.Write((int)remote.LocalHostUniqueIdentifier);

                // and send it
                sharedMemoryConnection.LowLevel_SendSync(serializedLocalInfo, timeout);

                // read remote info
                using (Stream remoteUriStream = sharedMemoryConnection.LowLevel_ReadSync(timeout))
                {
                    BinaryReader binaryReader = new BinaryReader(remoteUriStream);
                    remoteUri = binaryReader.ReadString();
                    remoteHostUniqueIdentifier = binaryReader.ReadInt32();
                }
            }

            sharedMemoryConnection.Remote = remote;
            sharedMemoryConnection.Remote.UpdateUri(remoteUri, remoteHostUniqueIdentifier);
            sharedMemoryConnection.Remote.GenuinePersistentConnectionState = GenuinePersistentConnectionState.Opened;

            // LOG:
            if (binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0)
            {
                binaryLogWriter.WriteHostInformationEvent("SharedMemoryConnectionManager.LowLevel_OpenConnection",
                                                          LogMessageType.HostInformationCreated, null, remote,
                                                          GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                                                          sharedMemoryConnection.DbgConnectionId,
                                                          "HostInformation is ready for actions.");
            }

            // LOG:
            if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0)
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_OpenConnection",
                                           LogMessageType.ConnectionEstablished, null, null, remote, null,
                                           GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                           securitySession, connectionLevelSSName,
                                           sharedMemoryConnection.DbgConnectionId, (int)GenuineConnectionType.Persistent, 0, 0, this.GetType().Name, null, null, null,
                                           "The connection to the remote host is established.");
            }

            return(sharedMemoryConnection);
        }