private void BeginSending() { if (m_outsize == 0) { m_outpos = null; m_encoder.GetData(ref m_outpos, ref m_outsize); if (m_outsize == 0) { m_sendingState = SendState.Idle; } else { BeginWrite(m_outpos, m_outsize); } } else { BeginWrite(m_outpos, m_outsize); } }
private void HandleHandshake(Action action, SocketError socketError, int bytesTransferred) { int bytesSent; int bytesReceived; switch (m_handshakeState) { case HandshakeState.Closed: switch (action) { case Action.Start: // Send the 'length' and 'flags' fields of the identity message. // The 'length' field is encoded in the long format. m_greetingOutputBuffer[m_outsize++] = ((byte)0xff); m_greetingOutputBuffer.PutLong(m_options.Endian, (long)m_options.IdentitySize + 1, 1); m_outsize += 8; m_greetingOutputBuffer[m_outsize++] = ((byte)0x7f); m_outpos = new ByteArraySegment(m_greetingOutputBuffer); m_handshakeState = HandshakeState.SendingGreeting; BeginWrite(m_outpos, m_outsize); break; default: Debug.Assert(false); break; } break; case HandshakeState.SendingGreeting: switch (action) { case Action.OutCompleted: bytesSent = EndWrite(socketError, bytesTransferred); if (bytesSent == -1) { Error(); } else { m_outpos.AdvanceOffset(bytesSent); m_outsize -= bytesSent; if (m_outsize > 0) { BeginWrite(m_outpos, m_outsize); } else { m_greetingBytesRead = 0; var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); m_handshakeState = HandshakeState.ReceivingGreeting; BeginRead(greetingSegment, PreambleSize); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; case HandshakeState.ReceivingGreeting: switch (action) { case Action.InCompleted: bytesReceived = EndRead(socketError, bytesTransferred); if (bytesReceived == -1) { Error(); } else { m_greetingBytesRead += bytesReceived; // check if it is an unversion protocol if (m_greeting[0] != 0xff || (m_greetingBytesRead == 10 && (m_greeting[9] & 0x01) == 0)) { m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian); m_encoder.SetMsgSource(m_session); m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian); m_decoder.SetMsgSink(m_session); // We have already sent the message header. // Since there is no way to tell the encoder to // skip the message header, we simply throw that // header data away. int headerSize = m_options.IdentitySize + 1 >= 255 ? 10 : 2; var tmp = new byte[10]; var bufferp = new ByteArraySegment(tmp); int bufferSize = headerSize; m_encoder.GetData(ref bufferp, ref bufferSize); Debug.Assert(bufferSize == headerSize); // Make sure the decoder sees the data we have already received. m_inpos = new ByteArraySegment(m_greeting); m_insize = m_greetingBytesRead; // To allow for interoperability with peers that do not forward // their subscriptions, we inject a phony subscription // message into the incoming message stream. To put this // message right after the identity message, we temporarily // divert the message stream from session to ourselves. if (m_options.SocketType == ZmqSocketType.Pub || m_options.SocketType == ZmqSocketType.Xpub) m_decoder.SetMsgSink(this); ActivateOut(); } else if (m_greetingBytesRead < 10) { var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); BeginRead(greetingSegment, PreambleSize - m_greetingBytesRead); } else { // The peer is using versioned protocol. // Send the rest of the greeting. m_outpos[m_outsize++] = 1; // Protocol version m_outpos[m_outsize++] = (byte)m_options.SocketType; m_handshakeState = HandshakeState.SendingRestOfGreeting; BeginWrite(m_outpos, m_outsize); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; case HandshakeState.SendingRestOfGreeting: switch (action) { case Action.OutCompleted: bytesSent = EndWrite(socketError, bytesTransferred); if (bytesSent == -1) { Error(); } else { m_outpos.AdvanceOffset(bytesSent); m_outsize -= bytesSent; if (m_outsize > 0) { BeginWrite(m_outpos, m_outsize); } else { var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); m_handshakeState = HandshakeState.ReceivingRestOfGreeting; BeginRead(greetingSegment, GreetingSize - m_greetingBytesRead); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; case HandshakeState.ReceivingRestOfGreeting: switch (action) { case Action.InCompleted: bytesReceived = EndRead(socketError, bytesTransferred); if (bytesReceived == -1) { Error(); } else { m_greetingBytesRead += bytesReceived; if (m_greetingBytesRead < GreetingSize) { var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); BeginRead(greetingSegment, GreetingSize); } else { if (m_greeting[VersionPos] == 0) { // ZMTP/1.0 framing. m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian); m_encoder.SetMsgSource(m_session); m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian); m_decoder.SetMsgSink(m_session); } else { // v1 framing protocol. m_encoder = new V2Encoder(Config.OutBatchSize, m_session, m_options.Endian); m_decoder = new V2Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_session, m_options.Endian); } // handshake is done Activate(); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; default: Debug.Assert(false); break; } }
// The function returns a batch of binary data. The data // are filled to a supplied buffer. If no buffer is supplied (data_ // points to NULL) decoder object will provide buffer of its own. public void GetData(ref ByteArraySegment data, ref int size) { int offset = -1; GetData(ref data, ref size, ref offset); }
public void GetData(ref ByteArraySegment data, ref int size, ref int offset) { ByteArraySegment buffer = data ?? new ByteArraySegment(m_buf); int bufferSize = data == null ? m_buffersize : size; int pos = 0; while (pos < bufferSize) { // If there are no more data to return, run the state machine. // If there are still no data, return what we already have // in the buffer. if (m_toWrite == 0) { // If we are to encode the beginning of a new message, // adjust the message offset. if (m_beginning) { if (offset == -1) { offset = pos; } } if (!Next()) { break; } } // If there are no data in the buffer yet and we are able to // fill whole buffer in a single go, let's use zero-copy. // There's no disadvantage to it as we cannot stuck multiple // messages into the buffer anyway. Note that subsequent // write(s) are non-blocking, thus each single write writes // at most SO_SNDBUF bytes at once not depending on how large // is the chunk returned from here. // As a consequence, large messages being sent won't block // other engines running in the same I/O thread for excessive // amounts of time. if (pos == 0 && data == null && m_toWrite >= bufferSize) { data = m_writePos; size = m_toWrite; m_writePos = null; m_toWrite = 0; return; } // Copy data to the buffer. If the buffer is full, return. int toCopy = Math.Min(m_toWrite, bufferSize - pos); if (toCopy != 0) { m_writePos.CopyTo(0, buffer, pos, toCopy); pos += toCopy; m_writePos.AdvanceOffset(toCopy); m_toWrite -= toCopy; } } data = buffer; size = pos; }
/// <summary> /// Returns a buffer to be filled with binary data. /// </summary> public void GetBuffer(out ByteArraySegment data, out int size) { // If we are expected to read large message, we'll opt for zero- // copy, i.e. we'll ask caller to fill the data directly to the // message. Note that subsequent read(s) are non-blocking, thus // each single read reads at most SO_RCVBUF bytes at once not // depending on how large is the chunk returned from here. // As a consequence, large messages being received won't block // other engines running in the same I/O thread for excessive // amounts of time. if (m_toRead >= m_bufsize) { data = m_readPos.Clone(); size = m_toRead; return; } data = new ByteArraySegment(m_buf); size = m_bufsize; }
protected void NextStep(ByteArraySegment readPos, int toRead, int state) { m_readPos = readPos; m_toRead = toRead; this.State = state; }
/// <summary> /// The function returns a batch of binary data. The data /// are filled to a supplied buffer. If no buffer is supplied (data_ /// points to NULL) decoder object will provide buffer of its own. /// </summary> public void GetData(ref ByteArraySegment data, ref int size) { int offset = -1; GetData(ref data, ref size, ref offset); }
public void CopyTo(int fromOffset, [NotNull] ByteArraySegment dest, int destOffset, int toCopy) { Buffer.BlockCopy(m_innerBuffer, Offset + fromOffset, dest.m_innerBuffer, dest.Offset + destOffset, toCopy); }
private void ProcessInput() { bool disconnection = false; int processed; if (m_insize == -1) { m_insize = 0; disconnection = true; } if (m_options.RawSocket) { if (m_insize == 0 || !m_decoder.MessageReadySize(m_insize)) { processed = 0; } else { processed = m_decoder.ProcessBuffer(m_inpos, m_insize); } } else { // Push the data to the decoder. processed = m_decoder.ProcessBuffer(m_inpos, m_insize); } if (processed == -1) { disconnection = true; } else { // Stop polling for input if we got stuck. if (processed < m_insize) { m_receivingState = ReceiveState.Stuck; m_inpos.AdvanceOffset(processed); m_insize -= processed; } else { m_inpos = null; m_insize = 0; } } // Flush all messages the decoder may have produced. m_session.Flush(); // An input error has occurred. If the last decoded message // has already been accepted, we terminate the engine immediately. // Otherwise, we stop waiting for socket events and postpone // the termination until after the message is accepted. if (disconnection) { if (m_decoder.Stalled()) { m_ioObject.RemoveSocket(m_handle); m_ioEnabled = false; m_state = State.Stalled; } else { Error(); } } else if (m_receivingState != ReceiveState.Stuck) { m_decoder.GetBuffer(out m_inpos, out m_insize); BeginRead(m_inpos, m_insize); } }
//protected void next_step (Msg msg_, int state_, bool beginning_) { // if (msg_ == null) // next_step((ByteBuffer) null, 0, state_, beginning_); // else // next_step(msg_.data(), msg_.size(), state_, beginning_); //} protected void NextStep(ByteArraySegment writePos, int toWrite, int state, bool beginning) { m_writePos = writePos; m_toWrite = toWrite; State = state; m_beginning = beginning; }
private void HandleHandshake(Action action, SocketError socketError, int bytesTransferred) { int bytesSent; int bytesReceived; switch (m_handshakeState) { case HandshakeState.Closed: switch (action) { case Action.Start: // Send the 'length' and 'flags' fields of the identity message. // The 'length' field is encoded in the long format. m_greetingOutputBuffer[m_outsize++] = ((byte)0xff); m_greetingOutputBuffer.PutLong(m_options.Endian, (long)m_options.IdentitySize + 1, 1); m_outsize += 8; m_greetingOutputBuffer[m_outsize++] = ((byte)0x7f); m_outpos = new ByteArraySegment(m_greetingOutputBuffer); m_handshakeState = HandshakeState.SendingGreeting; BeginWrite(m_outpos, m_outsize); break; default: Debug.Assert(false); break; } break; case HandshakeState.SendingGreeting: switch (action) { case Action.OutCompleted: bytesSent = EndWrite(socketError, bytesTransferred); if (bytesSent == -1) { Error(); } else { m_outpos.AdvanceOffset(bytesSent); m_outsize -= bytesSent; if (m_outsize > 0) { BeginWrite(m_outpos, m_outsize); } else { m_greetingBytesRead = 0; var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); m_handshakeState = HandshakeState.ReceivingGreeting; BeginRead(greetingSegment, PreambleSize); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; case HandshakeState.ReceivingGreeting: switch (action) { case Action.InCompleted: bytesReceived = EndRead(socketError, bytesTransferred); if (bytesReceived == -1) { Error(); } else { m_greetingBytesRead += bytesReceived; // check if it is an unversion protocol if (m_greeting[0] != 0xff || (m_greetingBytesRead == 10 && (m_greeting[9] & 0x01) == 0)) { m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian); m_encoder.SetMsgSource(m_session); m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian); m_decoder.SetMsgSink(m_session); // We have already sent the message header. // Since there is no way to tell the encoder to // skip the message header, we simply throw that // header data away. int headerSize = m_options.IdentitySize + 1 >= 255 ? 10 : 2; var tmp = new byte[10]; var bufferp = new ByteArraySegment(tmp); int bufferSize = headerSize; m_encoder.GetData(ref bufferp, ref bufferSize); Debug.Assert(bufferSize == headerSize); // Make sure the decoder sees the data we have already received. m_inpos = new ByteArraySegment(m_greeting); m_insize = m_greetingBytesRead; // To allow for interoperability with peers that do not forward // their subscriptions, we inject a phony subscription // message into the incoming message stream. To put this // message right after the identity message, we temporarily // divert the message stream from session to ourselves. if (m_options.SocketType == ZmqSocketType.Pub || m_options.SocketType == ZmqSocketType.Xpub) { m_decoder.SetMsgSink(this); } ActivateOut(); } else if (m_greetingBytesRead < 10) { var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); BeginRead(greetingSegment, PreambleSize - m_greetingBytesRead); } else { // The peer is using versioned protocol. // Send the rest of the greeting. m_outpos[m_outsize++] = 1; // Protocol version m_outpos[m_outsize++] = (byte)m_options.SocketType; m_handshakeState = HandshakeState.SendingRestOfGreeting; BeginWrite(m_outpos, m_outsize); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; case HandshakeState.SendingRestOfGreeting: switch (action) { case Action.OutCompleted: bytesSent = EndWrite(socketError, bytesTransferred); if (bytesSent == -1) { Error(); } else { m_outpos.AdvanceOffset(bytesSent); m_outsize -= bytesSent; if (m_outsize > 0) { BeginWrite(m_outpos, m_outsize); } else { var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); m_handshakeState = HandshakeState.ReceivingRestOfGreeting; BeginRead(greetingSegment, GreetingSize - m_greetingBytesRead); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; case HandshakeState.ReceivingRestOfGreeting: switch (action) { case Action.InCompleted: bytesReceived = EndRead(socketError, bytesTransferred); if (bytesReceived == -1) { Error(); } else { m_greetingBytesRead += bytesReceived; if (m_greetingBytesRead < GreetingSize) { var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead); BeginRead(greetingSegment, GreetingSize); } else { if (m_greeting[VersionPos] == 0) { // ZMTP/1.0 framing. m_encoder = new V1Encoder(Config.OutBatchSize, m_options.Endian); m_encoder.SetMsgSource(m_session); m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian); m_decoder.SetMsgSink(m_session); } else { // v1 framing protocol. m_encoder = new V2Encoder(Config.OutBatchSize, m_session, m_options.Endian); m_decoder = new V2Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_session, m_options.Endian); } // handshake is done Activate(); } } break; case Action.ActivateIn: case Action.ActivateOut: // nothing to do break; default: Debug.Assert(false); break; } break; default: Debug.Assert(false); break; } }
/// <summary> /// Processes the data in the buffer previously allocated using /// get_buffer function. size argument specifies the number of bytes /// actually filled into the buffer. Function returns number of /// bytes actually processed. /// </summary> public int ProcessBuffer(ByteArraySegment data, int size) { // Check if we had an error in previous attempt. if (State < 0) { return -1; } // In case of zero-copy simply adjust the pointers, no copying // is required. Also, run the state machine in case all the data // were processed. if (data != null && data.Equals(m_readPos)) { m_readPos.AdvanceOffset(size); m_toRead -= size; while (m_toRead == 0) { if (!Next()) { if (State < 0) { return -1; } return size; } } return size; } int pos = 0; while (true) { // Try to get more space in the message to fill in. // If none is available, return. while (m_toRead == 0) { if (!Next()) { if (State < 0) { return -1; } return pos; } } // If there are no more data in the buffer, return. if (pos == size) return pos; // Copy the data from buffer to the message. int toCopy = Math.Min(m_toRead, size - pos); data.CopyTo(pos, m_readPos, 0, toCopy); m_readPos.AdvanceOffset(toCopy); pos += toCopy; m_toRead -= toCopy; } }
public void GetData(ref ByteArraySegment data, ref int size, ref int offset) { ByteArraySegment buffer = data ?? new ByteArraySegment(m_buf); int bufferSize = data == null ? m_buffersize : size; int pos = 0; while (pos < bufferSize) { // If there are no more data to return, run the state machine. // If there are still no data, return what we already have // in the buffer. if (m_toWrite == 0) { // If we are to encode the beginning of a new message, // adjust the message offset. if (m_beginning) { if (offset == -1) { offset = pos; } } if (!Next()) break; } // If there are no data in the buffer yet and we are able to // fill whole buffer in a single go, let's use zero-copy. // There's no disadvantage to it as we cannot stuck multiple // messages into the buffer anyway. Note that subsequent // write(s) are non-blocking, thus each single write writes // at most SO_SNDBUF bytes at once not depending on how large // is the chunk returned from here. // As a consequence, large messages being sent won't block // other engines running in the same I/O thread for excessive // amounts of time. if (pos == 0 && data == null && m_toWrite >= bufferSize) { data = m_writePos; size = m_toWrite; m_writePos = null; m_toWrite = 0; return; } // Copy data to the buffer. If the buffer is full, return. int toCopy = Math.Min(m_toWrite, bufferSize - pos); if (toCopy != 0) { m_writePos.CopyTo(0, buffer, pos, toCopy); pos += toCopy; m_writePos.AdvanceOffset(toCopy); m_toWrite -= toCopy; } } data = buffer; size = pos; }
public void CopyTo([NotNull] ByteArraySegment otherSegment, int toCopy) { CopyTo(0, otherSegment, 0, toCopy); }
// Processes the data in the buffer previously allocated using // get_buffer function. size_ argument specifies nemuber of bytes // actually filled into the buffer. Function returns number of // bytes actually processed. public int ProcessBuffer(ByteArraySegment data, int size) { // Check if we had an error in previous attempt. if (State < 0) { return(-1); } // In case of zero-copy simply adjust the pointers, no copying // is required. Also, run the state machine in case all the data // were processed. if (data != null && data.Equals(m_readPos)) { m_readPos.AdvanceOffset(size); m_toRead -= size; while (m_toRead == 0) { if (!Next()) { if (State < 0) { return(-1); } return(size); } } return(size); } int pos = 0; while (true) { // Try to get more space in the message to fill in. // If none is available, return. while (m_toRead == 0) { if (!Next()) { if (State < 0) { return(-1); } return(pos); } } // If there are no more data in the buffer, return. if (pos == size) { return(pos); } // Copy the data from buffer to the message. int toCopy = Math.Min(m_toRead, size - pos); data.CopyTo(pos, m_readPos, 0, toCopy); m_readPos.AdvanceOffset(toCopy); pos += toCopy; m_toRead -= toCopy; } }
public ByteArraySegment([NotNull] ByteArraySegment otherSegment, int offset) { m_innerBuffer = otherSegment.m_innerBuffer; Offset = otherSegment.Offset + offset; }
public ByteArraySegment(ByteArraySegment otherSegment) { m_innerBuffer = otherSegment.m_innerBuffer; Offset = otherSegment.Offset; }