2011-07-26 00:43:57 +02:00
|
|
|
/*
|
2013-03-12 13:17:00 +01:00
|
|
|
Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
This file is part of 0MQ.
|
|
|
|
|
|
|
|
0MQ is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
0MQ is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "platform.hpp"
|
|
|
|
#if defined ZMQ_HAVE_WINDOWS
|
|
|
|
#include "windows.hpp"
|
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <new>
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
#include "stream_engine.hpp"
|
2011-07-26 00:43:57 +02:00
|
|
|
#include "io_thread.hpp"
|
2011-09-15 10:00:23 +02:00
|
|
|
#include "session_base.hpp"
|
2012-09-05 02:01:19 +02:00
|
|
|
#include "v1_encoder.hpp"
|
|
|
|
#include "v1_decoder.hpp"
|
2013-03-12 15:26:07 +01:00
|
|
|
#include "v2_encoder.hpp"
|
|
|
|
#include "v2_decoder.hpp"
|
2012-10-29 00:03:36 -07:00
|
|
|
#include "raw_decoder.hpp"
|
|
|
|
#include "raw_encoder.hpp"
|
2011-07-26 00:43:57 +02:00
|
|
|
#include "config.hpp"
|
|
|
|
#include "err.hpp"
|
2011-07-29 09:37:43 +02:00
|
|
|
#include "ip.hpp"
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
#include "likely.hpp"
|
|
|
|
#include "wire.hpp"
|
2011-07-26 00:43:57 +02:00
|
|
|
|
2012-08-04 11:41:33 +01:00
|
|
|
zmq::stream_engine_t::stream_engine_t (fd_t fd_, const options_t &options_, const std::string &endpoint_) :
|
2011-07-28 08:06:21 +02:00
|
|
|
s (fd_),
|
2011-07-26 00:43:57 +02:00
|
|
|
inpos (NULL),
|
|
|
|
insize (0),
|
2012-09-04 19:44:20 +02:00
|
|
|
decoder (NULL),
|
2011-07-26 00:43:57 +02:00
|
|
|
outpos (NULL),
|
|
|
|
outsize (0),
|
2012-09-04 19:44:20 +02:00
|
|
|
encoder (NULL),
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
handshaking (true),
|
|
|
|
greeting_bytes_read (0),
|
2011-07-26 00:43:57 +02:00
|
|
|
session (NULL),
|
|
|
|
options (options_),
|
2012-11-17 10:06:09 +00:00
|
|
|
endpoint (endpoint_),
|
2012-09-21 12:53:31 +01:00
|
|
|
plugged (false),
|
2013-02-01 17:32:28 +09:00
|
|
|
terminating (false),
|
2013-03-18 02:00:00 +01:00
|
|
|
io_error (false),
|
|
|
|
congested (false),
|
|
|
|
identity_received (false),
|
|
|
|
identity_sent (false),
|
|
|
|
rx_initialized (false),
|
|
|
|
tx_initialized (false),
|
|
|
|
subscription_required (false),
|
2012-09-21 12:53:31 +01:00
|
|
|
socket (NULL)
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2013-03-18 02:00:00 +01:00
|
|
|
int rc = tx_msg.init ();
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
|
2012-04-29 17:13:18 +02:00
|
|
|
// Put the socket into non-blocking mode.
|
2011-07-29 09:37:43 +02:00
|
|
|
unblock_socket (s);
|
2011-07-28 08:06:21 +02:00
|
|
|
// Set the socket buffer limits for the underlying socket.
|
|
|
|
if (options.sndbuf) {
|
2013-03-18 02:00:00 +01:00
|
|
|
rc = setsockopt (s, SOL_SOCKET, SO_SNDBUF,
|
2011-07-28 08:06:21 +02:00
|
|
|
(char*) &options.sndbuf, sizeof (int));
|
|
|
|
#ifdef ZMQ_HAVE_WINDOWS
|
|
|
|
wsa_assert (rc != SOCKET_ERROR);
|
|
|
|
#else
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if (options.rcvbuf) {
|
2013-03-18 02:00:00 +01:00
|
|
|
rc = setsockopt (s, SOL_SOCKET, SO_RCVBUF,
|
2011-07-28 08:06:21 +02:00
|
|
|
(char*) &options.rcvbuf, sizeof (int));
|
|
|
|
#ifdef ZMQ_HAVE_WINDOWS
|
|
|
|
wsa_assert (rc != SOCKET_ERROR);
|
|
|
|
#else
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-06-06 15:08:00 +02:00
|
|
|
#ifdef SO_NOSIGPIPE
|
2011-07-28 08:06:21 +02:00
|
|
|
// Make sure that SIGPIPE signal is not generated when writing to a
|
|
|
|
// connection that was already closed by the peer.
|
|
|
|
int set = 1;
|
2011-07-29 09:37:43 +02:00
|
|
|
int rc = setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof (int));
|
2011-07-28 08:06:21 +02:00
|
|
|
errno_assert (rc == 0);
|
|
|
|
#endif
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
zmq::stream_engine_t::~stream_engine_t ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
|
|
|
zmq_assert (!plugged);
|
|
|
|
|
2011-07-28 08:06:21 +02:00
|
|
|
if (s != retired_fd) {
|
|
|
|
#ifdef ZMQ_HAVE_WINDOWS
|
2013-03-12 15:26:07 +01:00
|
|
|
int rc = closesocket (s);
|
|
|
|
wsa_assert (rc != SOCKET_ERROR);
|
2011-07-28 08:06:21 +02:00
|
|
|
#else
|
2013-03-12 15:26:07 +01:00
|
|
|
int rc = close (s);
|
2011-07-28 08:06:21 +02:00
|
|
|
errno_assert (rc == 0);
|
|
|
|
#endif
|
2013-03-12 15:26:07 +01:00
|
|
|
s = retired_fd;
|
2011-07-28 08:06:21 +02:00
|
|
|
}
|
2012-09-04 19:44:20 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
int rc = tx_msg.close ();
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
|
2012-09-04 19:44:20 +02:00
|
|
|
if (encoder != NULL)
|
|
|
|
delete encoder;
|
|
|
|
if (decoder != NULL)
|
|
|
|
delete decoder;
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 10:00:23 +02:00
|
|
|
void zmq::stream_engine_t::plug (io_thread_t *io_thread_,
|
|
|
|
session_base_t *session_)
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
|
|
|
zmq_assert (!plugged);
|
|
|
|
plugged = true;
|
|
|
|
|
|
|
|
// Connect to session object.
|
|
|
|
zmq_assert (!session);
|
|
|
|
zmq_assert (session_);
|
|
|
|
session = session_;
|
2012-09-21 12:53:31 +01:00
|
|
|
socket = session-> get_socket ();
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
// Connect to I/O threads poller object.
|
|
|
|
io_object_t::plug (io_thread_);
|
|
|
|
handle = add_fd (s);
|
2013-03-18 02:00:00 +01:00
|
|
|
io_error = false;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
2012-10-30 12:18:13 +01:00
|
|
|
if (options.raw_sock) {
|
2012-10-29 00:03:36 -07:00
|
|
|
// no handshaking for raw sock, instantiate raw encoder and decoders
|
2013-03-18 02:00:00 +01:00
|
|
|
encoder = new (std::nothrow) raw_encoder_t (out_batch_size);
|
2012-10-29 00:03:36 -07:00
|
|
|
alloc_assert (encoder);
|
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
decoder = new (std::nothrow) raw_decoder_t (in_batch_size);
|
2012-10-29 00:03:36 -07:00
|
|
|
alloc_assert (decoder);
|
|
|
|
|
|
|
|
// disable handshaking for raw socket
|
|
|
|
handshaking = false;
|
2012-10-30 12:18:13 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-10-29 00:03:36 -07:00
|
|
|
// Send the 'length' and 'flags' fields of the identity message.
|
|
|
|
// The 'length' field is encoded in the long format.
|
2013-03-12 15:56:10 +01:00
|
|
|
outpos = greeting_send;
|
2012-10-29 00:03:36 -07:00
|
|
|
outpos [outsize++] = 0xff;
|
|
|
|
put_uint64 (&outpos [outsize], options.identity_size + 1);
|
|
|
|
outsize += 8;
|
|
|
|
outpos [outsize++] = 0x7f;
|
|
|
|
}
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
2011-07-26 00:43:57 +02:00
|
|
|
set_pollin (handle);
|
|
|
|
set_pollout (handle);
|
|
|
|
// Flush all the data that may have been already received downstream.
|
|
|
|
in_event ();
|
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
void zmq::stream_engine_t::unplug ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
|
|
|
zmq_assert (plugged);
|
|
|
|
plugged = false;
|
|
|
|
|
|
|
|
// Cancel all fd subscriptions.
|
2013-03-18 02:00:00 +01:00
|
|
|
if (!io_error)
|
2012-11-10 23:05:10 +01:00
|
|
|
rm_fd (handle);
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
// Disconnect from I/O threads poller object.
|
|
|
|
io_object_t::unplug ();
|
|
|
|
|
|
|
|
session = NULL;
|
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
void zmq::stream_engine_t::terminate ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2013-02-01 17:32:28 +09:00
|
|
|
if (!terminating && encoder && encoder->has_data ()) {
|
|
|
|
// Give io_thread a chance to send in the buffer
|
|
|
|
terminating = true;
|
|
|
|
return;
|
|
|
|
}
|
2011-07-26 00:43:57 +02:00
|
|
|
unplug ();
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
void zmq::stream_engine_t::in_event ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2013-03-18 02:00:00 +01:00
|
|
|
assert (!io_error);
|
|
|
|
|
2012-12-23 17:47:44 +01:00
|
|
|
// If still handshaking, receive and process the greeting message.
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
if (unlikely (handshaking))
|
|
|
|
if (!handshake ())
|
|
|
|
return;
|
|
|
|
|
2012-09-04 19:44:20 +02:00
|
|
|
zmq_assert (decoder);
|
2013-03-18 02:00:00 +01:00
|
|
|
|
|
|
|
// If there has been an I/O error, stop polling.
|
|
|
|
if (congested) {
|
|
|
|
rm_fd (handle);
|
|
|
|
io_error = true;
|
|
|
|
return;
|
|
|
|
}
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
// If there's no data to process in the buffer...
|
|
|
|
if (!insize) {
|
|
|
|
|
|
|
|
// Retrieve the buffer and read as much data as possible.
|
|
|
|
// Note that buffer can be arbitrarily large. However, we assume
|
|
|
|
// the underlying TCP layer has fixed buffer size and thus the
|
|
|
|
// number of bytes read will be always limited.
|
2012-09-04 19:44:20 +02:00
|
|
|
decoder->get_buffer (&inpos, &insize);
|
2013-03-18 02:00:00 +01:00
|
|
|
const int bytes_read = read (inpos, insize);
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
// Check whether the peer has closed the connection.
|
2013-03-18 02:00:00 +01:00
|
|
|
if (bytes_read == -1) {
|
|
|
|
error ();
|
|
|
|
return;
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
// Adjust input size
|
|
|
|
insize = static_cast <size_t> (bytes_read);
|
2012-10-30 12:18:13 +01:00
|
|
|
}
|
2011-07-26 00:43:57 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
int rc = 0;
|
|
|
|
size_t processed = 0;
|
2011-07-26 00:43:57 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
while (insize > 0) {
|
|
|
|
rc = decoder->decode (inpos, insize, processed);
|
|
|
|
zmq_assert (processed <= insize);
|
2011-07-26 00:43:57 +02:00
|
|
|
inpos += processed;
|
|
|
|
insize -= processed;
|
2013-03-18 02:00:00 +01:00
|
|
|
if (rc == 0 || rc == -1)
|
|
|
|
break;
|
|
|
|
rc = write_msg (decoder->msg ());
|
|
|
|
if (rc == -1)
|
|
|
|
break;
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
// Tear down the connection if we have failed to decode input data
|
|
|
|
// or the session has rejected the message.
|
|
|
|
if (rc == -1) {
|
|
|
|
if (errno != EAGAIN) {
|
2012-04-29 17:13:18 +02:00
|
|
|
error ();
|
2013-03-18 02:00:00 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
congested = true;
|
|
|
|
reset_pollin (handle);
|
2012-04-29 17:13:18 +02:00
|
|
|
}
|
2013-03-18 02:00:00 +01:00
|
|
|
|
|
|
|
session->flush ();
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
void zmq::stream_engine_t::out_event ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2013-03-18 02:00:00 +01:00
|
|
|
zmq_assert (!io_error);
|
|
|
|
|
2011-07-26 00:43:57 +02:00
|
|
|
// If write buffer is empty, try to read new data from the encoder.
|
|
|
|
if (!outsize) {
|
|
|
|
|
2012-11-02 11:11:14 +01:00
|
|
|
// Even when we stop polling as soon as there is no
|
|
|
|
// data to send, the poller may invoke out_event one
|
|
|
|
// more time due to 'speculative write' optimisation.
|
|
|
|
if (unlikely (encoder == NULL)) {
|
|
|
|
zmq_assert (handshaking);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-26 00:43:57 +02:00
|
|
|
outpos = NULL;
|
2013-03-18 02:00:00 +01:00
|
|
|
outsize = encoder->encode (&outpos, 0);
|
|
|
|
|
|
|
|
while (outsize < out_batch_size) {
|
|
|
|
if (read_msg (&tx_msg) == -1)
|
|
|
|
break;
|
|
|
|
encoder->load_msg (&tx_msg);
|
|
|
|
unsigned char *bufptr = outpos + outsize;
|
|
|
|
size_t n = encoder->encode (&bufptr, out_batch_size - outsize);
|
|
|
|
zmq_assert (n > 0);
|
|
|
|
if (outpos == NULL)
|
|
|
|
outpos = bufptr;
|
|
|
|
outsize += n;
|
|
|
|
}
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
// If there is no data to send, stop polling for output.
|
|
|
|
if (outsize == 0) {
|
|
|
|
reset_pollout (handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there are any data to write in write buffer, write as much as
|
|
|
|
// possible to the socket. Note that amount of data to write can be
|
2013-03-12 15:26:07 +01:00
|
|
|
// arbitrarily large. However, we assume that underlying TCP layer has
|
2011-07-26 00:43:57 +02:00
|
|
|
// limited transmission buffer and thus the actual number of bytes
|
|
|
|
// written should be reasonably modest.
|
|
|
|
int nbytes = write (outpos, outsize);
|
|
|
|
|
2012-04-29 17:13:18 +02:00
|
|
|
// IO error has occurred. We stop waiting for output events.
|
|
|
|
// The engine is not terminated until we detect input error;
|
2013-03-12 15:26:07 +01:00
|
|
|
// this is necessary to prevent losing incoming messages.
|
2011-07-26 00:43:57 +02:00
|
|
|
if (nbytes == -1) {
|
2012-04-29 17:13:18 +02:00
|
|
|
reset_pollout (handle);
|
2013-02-01 17:32:28 +09:00
|
|
|
if (unlikely (terminating))
|
|
|
|
terminate ();
|
2011-07-26 00:43:57 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
outpos += nbytes;
|
|
|
|
outsize -= nbytes;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
|
|
|
// If we are still handshaking and there are no data
|
|
|
|
// to send, stop polling for output.
|
|
|
|
if (unlikely (handshaking))
|
|
|
|
if (outsize == 0)
|
|
|
|
reset_pollout (handle);
|
2013-02-01 17:32:28 +09:00
|
|
|
|
|
|
|
if (unlikely (terminating))
|
|
|
|
if (outsize == 0)
|
|
|
|
terminate ();
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
void zmq::stream_engine_t::activate_out ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2013-03-18 02:00:00 +01:00
|
|
|
if (unlikely (io_error))
|
|
|
|
return;
|
|
|
|
|
2011-07-26 00:43:57 +02:00
|
|
|
set_pollout (handle);
|
|
|
|
|
|
|
|
// Speculative write: The assumption is that at the moment new message
|
|
|
|
// was sent by the user the socket is probably available for writing.
|
|
|
|
// Thus we try to write the data to socket avoiding polling for POLLOUT.
|
|
|
|
// Consequently, the latency should be better in request/reply scenarios.
|
|
|
|
out_event ();
|
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
void zmq::stream_engine_t::activate_in ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2013-03-18 02:00:00 +01:00
|
|
|
zmq_assert (congested);
|
|
|
|
zmq_assert (session != NULL);
|
|
|
|
zmq_assert (decoder != NULL);
|
|
|
|
|
|
|
|
int rc = write_msg (decoder->msg ());
|
|
|
|
if (rc == -1) {
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
session->flush ();
|
|
|
|
else
|
|
|
|
error ();
|
2012-04-29 17:13:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
while (insize > 0) {
|
|
|
|
size_t processed = 0;
|
|
|
|
rc = decoder->decode (inpos, insize, processed);
|
|
|
|
zmq_assert (processed <= insize);
|
|
|
|
inpos += processed;
|
|
|
|
insize -= processed;
|
|
|
|
if (rc == 0 || rc == -1)
|
|
|
|
break;
|
|
|
|
rc = write_msg (decoder->msg ());
|
|
|
|
if (rc == -1)
|
|
|
|
break;
|
|
|
|
}
|
2011-07-26 00:43:57 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
if (rc == -1 && errno == EAGAIN)
|
|
|
|
session->flush ();
|
|
|
|
else
|
|
|
|
if (rc == -1 || io_error)
|
|
|
|
error ();
|
|
|
|
else {
|
|
|
|
congested = false;
|
|
|
|
set_pollin (handle);
|
|
|
|
session->flush ();
|
|
|
|
|
|
|
|
// Speculative read.
|
|
|
|
in_event ();
|
|
|
|
}
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2012-09-05 16:37:20 +02:00
|
|
|
bool zmq::stream_engine_t::handshake ()
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
{
|
2012-09-05 16:37:20 +02:00
|
|
|
zmq_assert (handshaking);
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
zmq_assert (greeting_bytes_read < greeting_size);
|
|
|
|
|
2012-09-05 16:37:20 +02:00
|
|
|
// Receive the greeting.
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
while (greeting_bytes_read < greeting_size) {
|
2013-03-12 15:56:10 +01:00
|
|
|
const int n = read (greeting_recv + greeting_bytes_read,
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
greeting_size - greeting_bytes_read);
|
2012-09-05 16:37:20 +02:00
|
|
|
if (n == -1) {
|
|
|
|
error ();
|
|
|
|
return false;
|
|
|
|
}
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
if (n == 0)
|
2012-09-05 16:37:20 +02:00
|
|
|
return false;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
|
|
|
greeting_bytes_read += n;
|
|
|
|
|
2012-09-05 16:37:20 +02:00
|
|
|
// We have received at least one byte from the peer.
|
|
|
|
// If the first byte is not 0xff, we know that the
|
|
|
|
// peer is using unversioned protocol.
|
2013-03-12 15:56:10 +01:00
|
|
|
if (greeting_recv [0] != 0xff)
|
2012-09-05 16:37:20 +02:00
|
|
|
break;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
2012-09-05 16:37:20 +02:00
|
|
|
if (greeting_bytes_read < 10)
|
|
|
|
continue;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
2012-09-05 16:37:20 +02:00
|
|
|
// Inspect the right-most bit of the 10th byte (which coincides
|
|
|
|
// with the 'flags' field if a regular message was sent).
|
|
|
|
// Zero indicates this is a header of identity message
|
|
|
|
// (i.e. the peer is using the unversioned protocol).
|
2013-03-12 15:56:10 +01:00
|
|
|
if (!(greeting_recv [9] & 0x01))
|
2012-09-05 16:37:20 +02:00
|
|
|
break;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
2012-09-05 16:37:20 +02:00
|
|
|
// The peer is using versioned protocol.
|
|
|
|
// Send the rest of the greeting, if necessary.
|
2013-03-12 15:56:10 +01:00
|
|
|
if (outpos + outsize != greeting_send + greeting_size) {
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
if (outsize == 0)
|
|
|
|
set_pollout (handle);
|
2013-03-12 15:38:48 +01:00
|
|
|
outpos [outsize++] = ZMTP_2_1; // Protocol revision
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
outpos [outsize++] = options.type; // Socket type
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-12 15:26:07 +01:00
|
|
|
// Position of the revision field in the greeting.
|
|
|
|
const size_t revision_pos = 10;
|
2012-09-05 02:01:19 +02:00
|
|
|
|
2013-03-12 15:26:07 +01:00
|
|
|
// Is the peer using ZMTP/1.0 with no revision number?
|
|
|
|
// If so, we send and receive rest of identity message
|
2013-03-12 15:56:10 +01:00
|
|
|
if (greeting_recv [0] != 0xff || !(greeting_recv [9] & 0x01)) {
|
2013-03-12 15:26:07 +01:00
|
|
|
encoder = new (std::nothrow) v1_encoder_t (out_batch_size);
|
2012-09-05 02:01:19 +02:00
|
|
|
alloc_assert (encoder);
|
|
|
|
|
2013-03-12 15:26:07 +01:00
|
|
|
decoder = new (std::nothrow) v1_decoder_t (in_batch_size, options.maxmsgsize);
|
2012-09-05 02:01:19 +02:00
|
|
|
alloc_assert (decoder);
|
|
|
|
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
// 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.
|
|
|
|
const size_t header_size = options.identity_size + 1 >= 255 ? 10 : 2;
|
|
|
|
unsigned char tmp [10], *bufferp = tmp;
|
2013-03-18 02:00:00 +01:00
|
|
|
size_t buffer_size = encoder->encode (&bufferp, header_size);
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
zmq_assert (buffer_size == header_size);
|
|
|
|
|
|
|
|
// Make sure the decoder sees the data we have already received.
|
2013-03-12 15:56:10 +01:00
|
|
|
inpos = greeting_recv;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
insize = greeting_bytes_read;
|
2012-09-02 18:19:15 +02:00
|
|
|
|
|
|
|
// To allow for interoperability with peers that do not forward
|
2012-12-23 17:47:44 +01:00
|
|
|
// their subscriptions, we inject a phony subscription
|
2013-03-18 02:00:00 +01:00
|
|
|
// message into the incomming message stream.
|
2012-09-02 18:19:15 +02:00
|
|
|
if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB)
|
2013-03-18 02:00:00 +01:00
|
|
|
subscription_required = true;
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
}
|
2012-09-05 02:01:19 +02:00
|
|
|
else
|
2013-03-12 15:56:10 +01:00
|
|
|
if (greeting_recv [revision_pos] == ZMTP_1_0) {
|
2013-03-12 15:38:48 +01:00
|
|
|
encoder = new (std::nothrow) v1_encoder_t (
|
|
|
|
out_batch_size);
|
2012-09-05 02:01:19 +02:00
|
|
|
alloc_assert (encoder);
|
|
|
|
|
2013-03-12 15:38:48 +01:00
|
|
|
decoder = new (std::nothrow) v1_decoder_t (
|
|
|
|
in_batch_size, options.maxmsgsize);
|
2012-09-05 02:01:19 +02:00
|
|
|
alloc_assert (decoder);
|
|
|
|
}
|
2013-03-12 15:26:07 +01:00
|
|
|
else
|
2013-03-12 15:56:10 +01:00
|
|
|
if (greeting_recv [revision_pos] == ZMTP_2_0
|
|
|
|
|| greeting_recv [revision_pos] == ZMTP_2_1) {
|
2013-03-18 02:00:00 +01:00
|
|
|
encoder = new (std::nothrow) v2_encoder_t (out_batch_size);
|
2012-09-05 02:01:19 +02:00
|
|
|
alloc_assert (encoder);
|
|
|
|
|
2013-03-12 15:38:48 +01:00
|
|
|
decoder = new (std::nothrow) v2_decoder_t (
|
2013-03-18 02:00:00 +01:00
|
|
|
in_batch_size, options.maxmsgsize);
|
2012-09-05 02:01:19 +02:00
|
|
|
alloc_assert (decoder);
|
|
|
|
}
|
Extend ZTP/1.0 protocol
The new protocol adds support for protocol version and exchanges the
socket type, so that the library can reject a connection when the
sockets do not match.
The protocol was designed so that it's possible to detect and fully
support ZTP/1.0 peers.
When a new connection is set up, peers exchange greeting messages. The
greeting message encodes both the protocol verion and the socket type.
The format of the greeting message is as follows:
greeting = tag1, adaptation, tag2, version, length, socket_type
tag1 = BYTE / 0xff
adaptation = 8 BYTES
tag2 = BYTE / 0x7f
version = BYTE / 1
length = BYTE / 1
socket_type = BYTE
The protocol does not define the value of adaptation field.
When interoperability with ZTP/1.0 peers is required, the adaptaion
encodes, in network byte order, the length of identity message increased
by 1. When adaptaion consists of eight zeros, the current
implementatatio of 0MQ 2.x closes the connection.
This patch supports both ZTP/1.0 and new protocol.
2012-09-01 13:59:22 +02:00
|
|
|
|
|
|
|
// Start polling for output if necessary.
|
|
|
|
if (outsize == 0)
|
|
|
|
set_pollout (handle);
|
|
|
|
|
|
|
|
// Handshaking was successful.
|
|
|
|
// Switch into the normal message flow.
|
|
|
|
handshaking = false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
int zmq::stream_engine_t::read_msg (msg_t *msg_)
|
2012-09-02 18:19:15 +02:00
|
|
|
{
|
2013-03-18 02:00:00 +01:00
|
|
|
if (likely (tx_initialized || options.raw_sock))
|
|
|
|
return session->pull_msg (msg_);
|
2012-09-02 18:19:15 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
if (!identity_sent) {
|
|
|
|
int rc = msg_->init_size (options.identity_size);
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
memcpy (msg_->data (), options.identity, options.identity_size);
|
|
|
|
identity_sent = true;
|
|
|
|
tx_initialized = true;
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-02 18:19:15 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
tx_initialized = true;
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-02 18:19:15 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
int zmq::stream_engine_t::write_msg (msg_t *msg_)
|
|
|
|
{
|
|
|
|
if (likely (rx_initialized || options.raw_sock))
|
|
|
|
return session->push_msg (msg_);
|
|
|
|
|
|
|
|
if (!identity_received) {
|
|
|
|
if (options.recv_identity) {
|
|
|
|
msg_->set_flags (msg_t::identity);
|
|
|
|
int rc = session->push_msg (msg_);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int rc = msg_->close ();
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
rc = msg_->init ();
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
identity_received = true;
|
|
|
|
}
|
2012-09-02 18:19:15 +02:00
|
|
|
|
2013-03-18 02:00:00 +01:00
|
|
|
// Inject the subscription message, so that also
|
|
|
|
// ZMQ 2.x peers receive published messages.
|
|
|
|
if (subscription_required) {
|
|
|
|
int rc = msg_->init_size (1);
|
|
|
|
errno_assert (rc == 0);
|
|
|
|
*(unsigned char*) msg_->data () = 1;
|
|
|
|
rc = session->push_msg (msg_);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
|
|
|
subscription_required = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
rx_initialized = true;
|
|
|
|
return 0;
|
2012-09-02 18:19:15 +02:00
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
void zmq::stream_engine_t::error ()
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
|
|
|
zmq_assert (session);
|
2012-11-17 11:29:47 +00:00
|
|
|
socket->event_disconnected (endpoint, s);
|
2013-03-18 02:00:00 +01:00
|
|
|
session->flush ();
|
2011-07-26 00:43:57 +02:00
|
|
|
session->detach ();
|
|
|
|
unplug ();
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
int zmq::stream_engine_t::write (const void *data_, size_t size_)
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2011-07-28 08:06:21 +02:00
|
|
|
#ifdef ZMQ_HAVE_WINDOWS
|
|
|
|
|
2011-07-26 00:43:57 +02:00
|
|
|
int nbytes = send (s, (char*) data_, (int) size_, 0);
|
|
|
|
|
|
|
|
// If not a single byte can be written to the socket in non-blocking mode
|
|
|
|
// we'll get an error (this may happen during the speculative write).
|
|
|
|
if (nbytes == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Signalise peer failure.
|
2012-05-27 23:26:14 +02:00
|
|
|
if (nbytes == SOCKET_ERROR && (
|
2011-07-26 00:43:57 +02:00
|
|
|
WSAGetLastError () == WSAENETDOWN ||
|
|
|
|
WSAGetLastError () == WSAENETRESET ||
|
|
|
|
WSAGetLastError () == WSAEHOSTUNREACH ||
|
|
|
|
WSAGetLastError () == WSAECONNABORTED ||
|
|
|
|
WSAGetLastError () == WSAETIMEDOUT ||
|
|
|
|
WSAGetLastError () == WSAECONNRESET))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
wsa_assert (nbytes != SOCKET_ERROR);
|
2012-05-27 22:51:56 +02:00
|
|
|
return nbytes;
|
2011-07-28 08:06:21 +02:00
|
|
|
|
|
|
|
#else
|
2011-07-26 00:43:57 +02:00
|
|
|
|
2011-07-28 08:06:21 +02:00
|
|
|
ssize_t nbytes = send (s, data_, size_, 0);
|
|
|
|
|
|
|
|
// Several errors are OK. When speculative write is being done we may not
|
|
|
|
// be able to write a single byte from the socket. Also, SIGSTOP issued
|
|
|
|
// by a debugging tool can result in EINTR error.
|
|
|
|
if (nbytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK ||
|
|
|
|
errno == EINTR))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Signalise peer failure.
|
2012-09-29 11:14:44 +02:00
|
|
|
if (nbytes == -1) {
|
|
|
|
errno_assert (errno != EACCES
|
|
|
|
&& errno != EBADF
|
|
|
|
&& errno != EDESTADDRREQ
|
|
|
|
&& errno != EFAULT
|
|
|
|
&& errno != EINVAL
|
|
|
|
&& errno != EISCONN
|
|
|
|
&& errno != EMSGSIZE
|
|
|
|
&& errno != ENOMEM
|
|
|
|
&& errno != ENOTSOCK
|
|
|
|
&& errno != EOPNOTSUPP);
|
2011-07-28 08:06:21 +02:00
|
|
|
return -1;
|
2012-09-29 11:14:44 +02:00
|
|
|
}
|
2011-07-28 08:06:21 +02:00
|
|
|
|
2012-09-29 13:28:25 +02:00
|
|
|
return static_cast <int> (nbytes);
|
2011-07-28 08:06:21 +02:00
|
|
|
|
|
|
|
#endif
|
2011-07-26 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
2011-08-16 12:44:34 +02:00
|
|
|
int zmq::stream_engine_t::read (void *data_, size_t size_)
|
2011-07-26 00:43:57 +02:00
|
|
|
{
|
2011-07-28 08:06:21 +02:00
|
|
|
#ifdef ZMQ_HAVE_WINDOWS
|
|
|
|
|
2011-07-26 00:43:57 +02:00
|
|
|
int nbytes = recv (s, (char*) data_, (int) size_, 0);
|
|
|
|
|
|
|
|
// If not a single byte can be read from the socket in non-blocking mode
|
|
|
|
// we'll get an error (this may happen during the speculative read).
|
|
|
|
if (nbytes == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Connection failure.
|
2012-05-27 23:26:14 +02:00
|
|
|
if (nbytes == SOCKET_ERROR && (
|
2011-07-26 00:43:57 +02:00
|
|
|
WSAGetLastError () == WSAENETDOWN ||
|
|
|
|
WSAGetLastError () == WSAENETRESET ||
|
|
|
|
WSAGetLastError () == WSAECONNABORTED ||
|
|
|
|
WSAGetLastError () == WSAETIMEDOUT ||
|
|
|
|
WSAGetLastError () == WSAECONNRESET ||
|
|
|
|
WSAGetLastError () == WSAECONNREFUSED ||
|
|
|
|
WSAGetLastError () == WSAENOTCONN))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
wsa_assert (nbytes != SOCKET_ERROR);
|
|
|
|
|
|
|
|
// Orderly shutdown by the other peer.
|
|
|
|
if (nbytes == 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-05-27 22:51:56 +02:00
|
|
|
return nbytes;
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
ssize_t nbytes = recv (s, data_, size_, 0);
|
|
|
|
|
|
|
|
// Several errors are OK. When speculative read is being done we may not
|
2011-07-28 08:06:21 +02:00
|
|
|
// be able to read a single byte from the socket. Also, SIGSTOP issued
|
2011-07-26 00:43:57 +02:00
|
|
|
// by a debugging tool can result in EINTR error.
|
|
|
|
if (nbytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK ||
|
|
|
|
errno == EINTR))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Signalise peer failure.
|
2012-09-29 11:14:44 +02:00
|
|
|
if (nbytes == -1) {
|
|
|
|
errno_assert (errno != EBADF
|
|
|
|
&& errno != EFAULT
|
|
|
|
&& errno != EINVAL
|
|
|
|
&& errno != ENOMEM
|
|
|
|
&& errno != ENOTSOCK);
|
2011-07-26 00:43:57 +02:00
|
|
|
return -1;
|
2012-09-29 11:14:44 +02:00
|
|
|
}
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
// Orderly shutdown by the peer.
|
|
|
|
if (nbytes == 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-09-29 13:28:25 +02:00
|
|
|
return static_cast <int> (nbytes);
|
2011-07-26 00:43:57 +02:00
|
|
|
|
|
|
|
#endif
|
2011-07-28 08:06:21 +02:00
|
|
|
}
|