Пример #1
0
        //N.B., MessageSets are not preceded by an int32 like other array elements in the protocol.
        //
        //MessageSet => [Offset MessageSize Message]
        //  Offset => int64
        //  MessageSize => int32
        //
        //Message => Crc MagicByte Attributes Key Value
        //  Crc => int32
        //  MagicByte => int8
        //  Attributes => int8
        //  Key => bytes
        //  Value => bytes
        private static IEnumerable <Message> ReadMessageSet(MemoryStream stream)
        {
            // "As an optimization the server is allowed to return a partial message at the end of the message set.
            // Clients should handle this case"

            var messageSetSize           = BigEndianConverter.ReadInt32(stream);
            var remainingMessageSetBytes = messageSetSize;

            while (remainingMessageSetBytes > 0)
            {
                // we need at least be able to read offset and messageSize
                if (remainingMessageSetBytes < +8 + 4)
                {
                    // not enough bytes left. This is a partial message. Skip to the end of the message set.
                    stream.Position += remainingMessageSetBytes;
                    yield break;
                }

                var offset      = BigEndianConverter.ReadInt64(stream);
                var messageSize = BigEndianConverter.ReadInt32(stream);

                // we took 12 bytes there, check again that we have a full message.
                remainingMessageSetBytes -= 8 + 4;
                if (remainingMessageSetBytes < messageSize)
                {
                    // not enough bytes left. This is a partial message. Skip to the end of the message set.
                    stream.Position += remainingMessageSetBytes;
                    yield break;
                }

                // Message
                var crc        = BigEndianConverter.ReadInt32(stream);
                var crcPos     = stream.Position;
                var magic      = stream.ReadByte();
                var attributes = stream.ReadByte();
                var msg        = new Message();
                msg.Key    = ReadByteArray(stream);
                msg.Value  = ReadByteArray(stream);
                msg.Offset = offset;
                var pos = stream.Position;
                var computedCrcArray = Crc32.Compute(stream, crcPos, pos - crcPos);
                var computedCrc      = BigEndianConverter.ToInt32(computedCrcArray);
                if (computedCrc != crc)
                {
                    throw new BrokerException(string.Format("Corrupt message: Crc does not match. Caclulated {0} but got {1}", computedCrc, crc));
                }
                yield return(msg);

                // subtract messageSize of that message from remaining bytes
                remainingMessageSetBytes -= messageSize;
            }
        }
Пример #2
0
        protected void ActionOpen()
        {
            string path = Path.Combine(Root, GetPath());
            int    mode = BigEndianConverter.ToInt32(Options[Option.Mode]);

            DebugPrint("File_Open(\"" + path + "\", 0x" + mode.ToString("X") + ");");

            int        fd      = -1;
            FileMode   fmode   = FileMode.Open;
            FileAccess faccess = FileAccess.ReadWrite;

            if ((mode & (int)FileModes.O_WRONLY) == (int)FileModes.O_WRONLY)
            {
                faccess = FileAccess.Write;
            }
            else if ((mode & (int)FileModes.O_RDWR) == (int)FileModes.O_RDWR)
            {
                faccess = FileAccess.ReadWrite;
            }
            else
            {
                faccess = FileAccess.Read;
            }
            if ((mode & (int)FileModes.O_CREAT) == (int)FileModes.O_CREAT)
            {
                fmode = FileMode.Create;
            }
            else if ((mode & (int)FileModes.O_TRUNC) == (int)FileModes.O_TRUNC)
            {
                fmode = FileMode.Truncate;
            }
            else if ((mode & (int)FileModes.O_APPEND) == (int)FileModes.O_APPEND)
            {
                fmode = FileMode.Append;
            }

            try {
                if (ReadOnly && (fmode == FileMode.Append || fmode == FileMode.Create || fmode == FileMode.Truncate || faccess == FileAccess.Write || faccess == FileAccess.ReadWrite))
                {
                    Return(-1);
                    return;
                }
                Stream fstream = new FileStream(path, fmode, faccess, FileShare.ReadWrite | FileShare.Delete);
                fd = OpenFileFD++;

                OpenFiles.Add(fd, fstream);
            } catch { }

            Return(fd);
        }
Пример #3
0
        protected void ActionSeek()
        {
            int fd = GetFD();

            int where = BigEndianConverter.ToInt32(Options[Option.SeekWhere]);
            int whence = BigEndianConverter.ToInt32(Options[Option.SeekWhence]);

            DebugPrint("File_Seek(" + fd + ", " + where + ", " + whence + ");");
            if (!OpenFiles.ContainsKey(fd))
            {
                Return(-1);
            }
            else
            {
                OpenFiles[fd].Seek(where, (SeekOrigin)whence);
                Return(0);
            }
        }
Пример #4
0
        protected void ActionRead()
        {
            int fd     = GetFD();
            int length = BigEndianConverter.ToInt32(Options[Option.Length]);

            DebugPrint("File_Read(" + fd + ", " + length + ");");

            if (!OpenFiles.ContainsKey(fd))
            {
                Return(0);
            }
            else
            {
                int ret = (int)Util.StreamCopy(Stream, OpenFiles[fd], length);
                Writer.Pad(length - ret);
                Return(ret);
            }
        }
Пример #5
0
        private void ReceiveOption(Option option)
        {
            int length = BigEndianConverter.ToInt32(GetData(4));

            byte[] data;
            if (length > 0)
            {
                data = GetData(length);
            }
            else
            {
                data = new byte[0];
            }

            Options[option] = data;

            if (option == Option.Ping)
            {
                DebugPrint("Ping()");
            }
        }
Пример #6
0
        // Extract size and correlation Id, then start receive body loop.
        private void HandleHeaderState(ReceiveContext context, ISocket socket, ISocketAsyncEventArgs saea)
        {
            int responseSize  = BigEndianConverter.ToInt32(saea.Buffer);
            int correlationId = BigEndianConverter.ToInt32(saea.Buffer, SizeLength);
            // TODO check absurd response size?

            int matching;

            if (!_correlationIds.TryDequeue(out matching) || matching != correlationId)
            {
                throw new CorrelationException(matching, correlationId);
            }

            context.State         = ReceiveState.Body;
            context.CorrelationId = correlationId;
            // responseSize includes 4 bytes of correlation id
            context.RemainingExpected = responseSize - CorrelationIdLength;
            context.Response          = _responsePool.Reserve();
            saea.SetBuffer(0, Math.Min(context.Buffer.Length, context.RemainingExpected));
            if (!socket.ReceiveAsync(saea))
            {
                OnReceiveCompleted(socket, saea);
            }
        }
Пример #7
0
        internal async Task CorrelateResponseLoop(TcpClient client, CancellationToken cancel)
        {
            try
            {
                _cancellation = cancel;
                _log.Debug("Starting reading loop from socket. {0}", _id);
                _etw.CorrelationStart();

                var buff = new byte[16 * 1024];

                while (client.Connected && !cancel.IsCancellationRequested)
                {
                    try
                    {
                        // read message size
                        //var buff = new byte[4];
                        _etw.CorrelationReadingMessageSize();
                        await ReadBuffer(client, buff, 4, cancel);

                        if (cancel.IsCancellationRequested)
                        {
                            _log.Debug("Stopped reading from {0} because cancell requested", _id);
                            return;
                        }

                        var size = BigEndianConverter.ToInt32(buff);
                        _etw.CorrelationReadMessageSize(size);

                        // TODO: size sanity check. What is the reasonable max size?
                        //var body = new byte[size];
                        if (size > buff.Length)
                        {
                            buff = new byte[size];
                        }
                        await ReadBuffer(client, buff, size, cancel);

                        _etw.CorrelationReadBody(size);

                        try
                        {
                            int correlationId = -1;
                            // TODO: check read==size && read > 4
                            correlationId = BigEndianConverter.ToInt32(buff);
                            _etw.CorrelationReceivedCorrelationId(correlationId);

                            // find correlated action
                            Action <byte[], int, Exception> handler;
                            // TODO: if correlation id is not found, there is a chance of corrupt
                            // connection. Maybe recycle the connection?
                            if (!_corelationTable.TryRemove(correlationId, out handler))
                            {
                                _log.Error("Unknown correlationId: " + correlationId);
                                continue;
                            }
                            _etw.CorrelationExecutingHandler();
                            handler(buff, size, null);
                            _etw.CorrelationExecutedHandler();
                        }
                        catch (Exception ex)
                        {
                            var error = string.Format("Error with handling message. Message bytes:\n{0}\n", FormatBytes(buff, size));
                            _etw.CorrelationError(ex.Message + " " + error);
                            _log.Error(ex, error);
                            throw;
                        }
                    }
                    catch (SocketException e)
                    {
                        // shorter version of socket exception, without stack trace dump
                        _log.Info("CorrelationLoop socket exception. {0}. {1}", e.Message, _id);
                        throw;
                    }
                    catch (ObjectDisposedException)
                    {
                        _log.Debug("CorrelationLoop socket exception. Object disposed. {0}", _id);
                        throw;
                    }
                    catch (IOException)
                    {
                        _log.Info("CorrelationLoop IO exception. {0}", _id);
                        throw;
                    }
                    catch (Exception e)
                    {
                        _log.Error(e, "CorrelateResponseLoop error. {0}", _id);
                        throw;
                    }
                }

                _log.Debug("Finished reading loop from socket. {0}", _id);
                EtwTrace.Log.CorrelationComplete();
            }
            catch (Exception e)
            {
                _corelationTable.Values.ForEach(c => c(null, 0, e));
                if (_onError != null && !cancel.IsCancellationRequested) // don't call back OnError if we were told to cancel
                {
                    _onError(e);
                }

                if (!cancel.IsCancellationRequested)
                {
                    throw;
                }
            }
            finally
            {
                _log.Debug("Finishing CorrelationLoop. Calling back error to clear waiters.");
                _corelationTable.Values.ForEach(c => c(null, 0, new CorrelationLoopException("Correlation loop closed. Request will never get a response.")
                {
                    IsRequestedClose = cancel.IsCancellationRequested
                }));
                _log.Debug("Finished CorrelationLoop.");
            }
        }
Пример #8
0
            private async Task ListenLoop()
            {
                TcpClient client = null;

                try
                {
                    client = await _listener.AcceptTcpClientAsync();

                    while (!_cancel.IsCancellationRequested)
                    {
                        if (_mode == SimulationMode.SendError)
                        {
                            throw new SocketException((int)SocketError.ConnectionAborted);
                        }

                        var stream = client.GetStream();
                        var buffer = new byte[4];
                        int read   = 0;
                        while (read != buffer.Length)
                        {
                            read += await stream.ReadAsync(buffer, read, buffer.Length - read, _cancel.Token).ConfigureAwait(false);
                        }
                        if (_mode == SimulationMode.ReceiveError)
                        {
                            throw new SocketException((int)SocketError.ConnectionAborted);
                        }
                        int size = BigEndianConverter.ToInt32(buffer);
                        buffer = new byte[size];
                        read   = 0;
                        while (read != buffer.Length)
                        {
                            read += await stream.ReadAsync(buffer, read, buffer.Length - read, _cancel.Token).ConfigureAwait(false);
                        }
                        if (buffer[4] == 0)
                        {
                            continue;
                        }

                        var sbuffer     = new byte[4 + size - 1];
                        int correlation = BigEndianConverter.ToInt32(buffer);
                        if (_mode == SimulationMode.CorrelationIdError)
                        {
                            correlation -= 723;
                        }

                        BigEndianConverter.Write(sbuffer, size - 1);
                        BigEndianConverter.Write(sbuffer, correlation, 4);
                        Array.Copy(buffer, 5, sbuffer, 8, buffer.Length - 5);
                        await stream.WriteAsync(sbuffer, 0, sbuffer.Length, _cancel.Token).ConfigureAwait(false);
                    }
#if NET_CORE
                    client.Dispose(); // Same behavior as Close() called Dispose() internally
#else
                    client.Close();
#endif
                }
                catch
                {
                    if (client != null)
#if NET_CORE
                    { client.Dispose();   // Same behavior as Close() called Dispose() internally
                    }
#else
                    { client.Close(); }
#endif

                    _listener.Stop();
                }
            }
Пример #9
0
        protected void Poll()
        {
            Action action = (Action)BigEndianConverter.ToInt32(GetData(4));

            Ping();

            switch (action)
            {
            case Action.Send:
                ReceiveOption((Option)BigEndianConverter.ToInt32(GetData(4)));
                break;

            case Action.Receive:
                Command command = (Command)BigEndianConverter.ToInt32(GetData(4));
                switch (command)
                {
                case Command.Handshake:
                    ActionHandshake();
                    break;

                case Command.Goodbye:
                    ActionGoodbye();
                    break;

                case Command.Log:
                    ActionLog();
                    break;

                case Command.FileOpen:
                    ActionOpen();
                    break;

                case Command.FileRead:
                    ActionRead();
                    break;

                case Command.FileWrite:
                    ActionWrite();
                    break;

                case Command.FileSeek:
                    ActionSeek();
                    break;

                case Command.FileTell:
                    ActionTell();
                    break;

                case Command.FileSync:
                    ActionSync();
                    break;

                case Command.FileClose:
                    ActionClose();
                    break;

                case Command.FileStat:
                    ActionStat();
                    break;

                case Command.FileCreate:
                    ActionCreateFile();
                    break;

                case Command.FileDelete:
                    ActionDelete();
                    break;

                case Command.FileRename:
                    ActionRename();
                    break;

                case Command.FileCreateDir:
                    ActionCreateDir();
                    break;

                case Command.FileOpenDir:
                    ActionDirOpen();
                    break;

                case Command.FileCloseDir:
                    ActionDirClose();
                    break;

                case Command.FileNextDirPath:
                    ActionDirNextPath();
                    break;

                case Command.FileNextDirStat:
                    ActionDirNextStat();
                    break;

                case Command.FileNextDirCache:
                    ActionDirNextCache();
                    break;

                default:
                    break;
                }
                break;
            }
        }
Пример #10
0
 protected int GetFD()
 {
     return(BigEndianConverter.ToInt32(Options[Option.File]));
 }