Beispiel #1
0
        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;
                    }

                    int n = Math.Min(_readBuffer.b.position() - _readBufferPos, buf.b.remaining());
                    if(n > _readPayloadLength)
                    {
                        n = _readPayloadLength;
                    }
                    if(n > 0)
                    {
                        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() && n < _readPayloadLength;
                }
            }
        }
Beispiel #2
0
        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;
        }
Beispiel #3
0
        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);
            }

            if(_state == StateClosed)
            {
                _writeBuffer.clear();
                return;
            }

            postWrite(buf, SocketOperation.None);
        }
Beispiel #4
0
        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;
            }
        }