private void Unplug() { Debug.Assert(m_plugged); m_plugged = false; // remove handle from proactor. if (m_ioEnabled) { m_ioObject.RemoveSocket(m_handle); m_ioEnabled = false; } // Disconnect from I/O threads poller object. m_ioObject.Unplug(); m_state = State.Closed; // Disconnect from session object. if (m_encoder != null) { m_encoder.SetMsgSource(null); } if (m_decoder != null) { m_decoder.SetMsgSink(null); } m_session = null; }
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; } }
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; } }