예제 #1
0
        /// <summary>
        /// Processes an incomming comand and prepares the response data
        /// </summary>
        /// <param name="commandId">Id of the command</param>
        /// <param name="data">Custom data of the command. The array might be larger then the actual data.
        /// The 1st valid byte is at <paramref name="dataOffset"/>. The number of valid bytes is provided by <paramref name="dataLength"/>.</param>
        /// <param name="dataOffset">First valid data byte in <paramref name="data"/>.</param>
        /// <param name="dataLength">Number of valid bytes in <paramref name="data"/>.</param>
        /// <param name="response">Byte array to write the custom response data into. The 1st written byte must be at <paramref name="responseOffset"/>.
        /// At the end <paramref name="responseOffset"/> must be set to the 1st byte after the response.
        /// The byte array can be replaced by a larger arrqay if needed. All data up to the current <paramref name="responseOffset"/> must be copied into this new array.</param>
        /// <param name="responseOffset">Holds the 1st byte offset to write response data to <paramref name="response"/> when mthod is called.
        /// The value must be updatet to the 1st byte offset after the valid response date before the method returns.</param>
        /// <returns>Returns the command response code.</returns>
        private Ipc.ResponseCode ProcessCommand(Ipc.Command commandId, byte[] data, int dataOffset, int dataLength, ref byte[] response, ref int responseOffset)
        {
            switch (commandId)
            {
            case Ipc.Command.GetProcessId:
                using (var process = System.Diagnostics.Process.GetCurrentProcess())
                {
                    BitConverter.GetBytes(process.Id).CopyTo(response, responseOffset);
                }
                responseOffset += 4;
                return(Ipc.ResponseCode.Ok);

            case Ipc.Command.Shutdown:
                return(ShutdownApplication() ? Ipc.ResponseCode.Ok : Ipc.ResponseCode.False);
            }

            return(Ipc.ResponseCode.UnknownCommand);
        }
예제 #2
0
        protected Ipc.ResponseCode SendReceive(Ipc.Command commandId, byte[] data, int dataLength, out byte[] response)
        {
            CheckConnected();
            ushort messageId = _nextMessageId;

            _nextMessageId = (ushort)(_nextMessageId == UInt16.MaxValue ? 1 : _nextMessageId + 1);

            BitConverter.GetBytes((ushort)commandId).CopyTo(data, 0);
            BitConverter.GetBytes(messageId).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)(dataLength - 6)).CopyTo(data, 4);

            _pipe.Write(data, 0, dataLength);
            _pipe.Flush();
            if (((ushort)commandId & Ipc.NO_RESPONSE_COMMAND) != 0)
            {
                response = null;
                return(Ipc.ResponseCode.Ok);
            }
            var header = new byte[6];
            var tEnd   = DateTime.Now.AddMilliseconds(ResponseTimeout);

            while (DateTime.Now <= tEnd)
            {
                // read 6 byte header
                int cnt = 0;
                while (cnt < header.Length)
                {
                    var       readDoneEvent = new ManualResetEvent(false);
                    int       newCnt        = 0;
                    Exception endReadEx     = null;
                    _pipe.BeginRead(header, cnt, header.Length - cnt, ar =>
                    {
                        try
                        {
                            newCnt = _pipe.EndRead(ar);
                        }
                        catch (Exception ex)
                        {
                            endReadEx = ex;
                        }
                        readDoneEvent.Set();
                    }, null);
                    if (!readDoneEvent.WaitOne(ResponseTimeout))
                    {
                        Disconnect();
                        Connect();
                        throw new TimeoutException(cnt == 0
               ? String.Format("No response for IPC message from {0} for command {1}", AppName, commandId)
               : String.Format("Timeout for IPC message from {0} for command {1}", AppName, commandId));
                    }
                    if (endReadEx != null)
                    {
                        throw new IpcException(endReadEx.Message, endReadEx);
                    }
                    if (newCnt == 0) // end of stream
                    {
                        throw new IpcException("Connection closed unexpected");
                    }
                    cnt += newCnt;
                }
                Ipc.ResponseCode responseCode      = (Ipc.ResponseCode)BitConverter.ToUInt16(header, 0);
                ushort           responseMessageId = BitConverter.ToUInt16(header, 2); // for future use to allow parallel messages from a single client
                ushort           responseLength    = BitConverter.ToUInt16(header, 4);

                response = new byte[responseLength];
                if (responseLength > 0)
                {
                    cnt = 0;
                    while (cnt < response.Length)
                    {
                        var       readDoneEvent = new ManualResetEvent(false);
                        int       newCnt        = 0;
                        Exception endReadEx     = null;
                        _pipe.BeginRead(response, cnt, response.Length - cnt, ar =>
                        {
                            try
                            {
                                newCnt = _pipe.EndRead(ar);
                            }
                            catch (Exception ex)
                            {
                                endReadEx = ex;
                            }
                            readDoneEvent.Set();
                        }, null);
                        if (!readDoneEvent.WaitOne(ResponseTimeout))
                        {
                            Disconnect();
                            Connect();
                            throw new TimeoutException(String.Format("Timeout for IPC message from {0} for command {1}", AppName, commandId));
                        }
                        if (endReadEx != null)
                        {
                            throw new IpcException(endReadEx.Message, endReadEx);
                        }
                        if (newCnt == 0) // end of stream
                        {
                            throw new IpcException("Connection closed unexpected");
                        }
                        cnt += newCnt;
                    }
                }
                if (responseMessageId == messageId)
                {
                    if (responseCode == Ipc.ResponseCode.ServerException)
                    {
                        int offset   = 0;
                        var message  = Ipc.BytesToString(response, ref offset);
                        var typeName = Ipc.BytesToString(response, ref offset);
                        throw new IpcException(String.Format("A IPC server exception of type {0} was thrown:\n{1}", typeName, message));
                    }
                    return(responseCode);
                }
            }
            throw new TimeoutException(String.Format("No response for IPC message from {0} for command {1}", AppName, commandId));
        }
예제 #3
0
        private void WaitForConnectionCallback(IAsyncResult ar)
        {
            try
            {
                // finish async wait
                var pipe = (NamedPipeServerStream)ar.AsyncState;
                pipe.EndWaitForConnection(ar);

                // start another pipe for the next client
                OpenNewPipe();

                try
                {
                    var header = new byte[6];
                    while (true)
                    {
                        // read 6 byte header
                        int cnt = 0;
                        while (cnt < header.Length)
                        {
                            int newCnt = pipe.Read(header, cnt, header.Length - cnt);
                            if (newCnt == 0) // end of stream
                            {
                                return;
                            }
                            cnt += newCnt;
                        }
                        Ipc.Command commandId  = (Ipc.Command)BitConverter.ToUInt16(header, 0);
                        ushort      messageId  = BitConverter.ToUInt16(header, 2); // for future use to allow parallel messages from a single client
                        ushort      dataLength = BitConverter.ToUInt16(header, 4);

                        var data = new byte[dataLength];
                        if (dataLength > 0)
                        {
                            cnt = 0;
                            while (cnt < data.Length)
                            {
                                int newCnt = pipe.Read(data, cnt, data.Length - cnt);
                                if (newCnt == 0) // end of stream
                                {
                                    return;
                                }
                                cnt += newCnt;
                            }
                        }

                        var response       = new byte[1024];
                        int responseOffset = 6;
                        Ipc.ResponseCode responseCode;
                        try
                        {
                            responseCode = ProcessCommand(commandId, data, 0, dataLength, ref response, ref responseOffset);
                        }
                        catch (Exception ex)
                        {
                            responseCode   = Ipc.ResponseCode.ServerException;
                            responseOffset = 6;
                            Ipc.StringToBytes(ex.Message, response, ref responseOffset);
                            Ipc.StringToBytes(ex.GetType().FullName, response, ref responseOffset);
                        }
                        if (((ushort)commandId & Ipc.NO_RESPONSE_COMMAND) == 0)
                        {
                            // send response
                            BitConverter.GetBytes((ushort)responseCode).CopyTo(response, 0);
                            BitConverter.GetBytes(messageId).CopyTo(response, 2);
                            BitConverter.GetBytes((ushort)(responseOffset - 6)).CopyTo(response, 4);
                            pipe.Write(response, 0, responseOffset);
                        }
                    }
                }
                finally
                {
                    lock (_serverPipes)
                    {
                        _serverPipes.Remove(pipe);
                        pipe.Close();
                    }
                }
            }
            catch (Exception)
            {
            }
        }