Commit 7832addd authored by Pieter Hintjens's avatar Pieter Hintjens

Updated security mechanisms to use variable-length commands

RFC23, RFC24, RFC26 now use variable-length command names that
end in null octet (valid C strings) instead of fixed-length
space padded strings.
parent dd14d4e0
......@@ -138,7 +138,7 @@ int zmq::curve_client_t::encode (msg_t *msg_)
uint8_t *message = static_cast <uint8_t *> (msg_->data ());
memcpy (message, "MESSAGE ", 8);
memcpy (message, "MESSAGE\0", 8);
memcpy (message + 8, &cn_nonce, 8);
memcpy (message + 16, message_box + crypto_box_BOXZEROBYTES,
mlen - crypto_box_BOXZEROBYTES);
......@@ -161,7 +161,7 @@ int zmq::curve_client_t::decode (msg_t *msg_)
}
const uint8_t *message = static_cast <uint8_t *> (msg_->data ());
if (memcmp (message, "MESSAGE ", 8)) {
if (memcmp (message, "MESSAGE\0", 8)) {
errno = EPROTO;
return -1;
}
......@@ -235,11 +235,11 @@ int zmq::curve_client_t::hello_msg (msg_t *msg_)
errno_assert (rc == 0);
uint8_t *hello = static_cast <uint8_t *> (msg_->data ());
memcpy (hello, "HELLO ", 8);
memcpy (hello, "HELLO\0", 6);
// CurveZMQ major and minor version numbers
memcpy (hello + 8, "\1\0", 2);
memcpy (hello + 6, "\1\0", 2);
// Anti-amplification padding
memset (hello + 10, 0, 70);
memset (hello + 8, 0, 72);
// Client public connection key
memcpy (hello + 80, cn_public, crypto_box_PUBLICKEYBYTES);
// Short nonce, prefixed by "CurveZMQHELLO---"
......@@ -260,7 +260,7 @@ int zmq::curve_client_t::process_welcome (msg_t *msg_)
}
const uint8_t * welcome = static_cast <uint8_t *> (msg_->data ());
if (memcmp (welcome, "WELCOME ", 8)) {
if (memcmp (welcome, "WELCOME\0", 8)) {
errno = EPROTO;
return -1;
}
......@@ -346,18 +346,18 @@ int zmq::curve_client_t::initiate_msg (msg_t *msg_)
mlen, initiate_nonce, cn_server, cn_secret);
zmq_assert (rc == 0);
rc = msg_->init_size (112 + mlen - crypto_box_BOXZEROBYTES);
rc = msg_->init_size (113 + mlen - crypto_box_BOXZEROBYTES);
errno_assert (rc == 0);
uint8_t *initiate = static_cast <uint8_t *> (msg_->data ());
memcpy (initiate, "INITIATE", 8);
memcpy (initiate, "INITIATE\0", 9);
// Cookie provided by the server in the WELCOME command
memcpy (initiate + 8, cn_cookie, 96);
memcpy (initiate + 9, cn_cookie, 96);
// Short nonce, prefixed by "CurveZMQINITIATE"
memcpy (initiate + 104, &cn_nonce, 8);
memcpy (initiate + 105, &cn_nonce, 8);
// Box [C + vouch + metadata](C'->S')
memcpy (initiate + 112, initiate_box + crypto_box_BOXZEROBYTES,
memcpy (initiate + 113, initiate_box + crypto_box_BOXZEROBYTES,
mlen - crypto_box_BOXZEROBYTES);
cn_nonce++;
......@@ -367,18 +367,18 @@ int zmq::curve_client_t::initiate_msg (msg_t *msg_)
int zmq::curve_client_t::process_ready (msg_t *msg_)
{
if (msg_->size () < 32) {
if (msg_->size () < 30) {
errno = EPROTO;
return -1;
}
const uint8_t *ready = static_cast <uint8_t *> (msg_->data ());
if (memcmp (ready, "READY ", 8)) {
if (memcmp (ready, "READY\0", 6)) {
errno = EPROTO;
return -1;
}
const size_t clen = (msg_->size () - 16) + crypto_box_BOXZEROBYTES;
const size_t clen = (msg_->size () - 14) + crypto_box_BOXZEROBYTES;
uint8_t ready_nonce [crypto_box_NONCEBYTES];
uint8_t ready_plaintext [crypto_box_ZEROBYTES + 256];
......@@ -386,10 +386,10 @@ int zmq::curve_client_t::process_ready (msg_t *msg_)
memset (ready_box, 0, crypto_box_BOXZEROBYTES);
memcpy (ready_box + crypto_box_BOXZEROBYTES,
ready + 16, clen - crypto_box_BOXZEROBYTES);
ready + 14, clen - crypto_box_BOXZEROBYTES);
memcpy (ready_nonce, "CurveZMQREADY---", 16);
memcpy (ready_nonce + 16, ready + 8, 8);
memcpy (ready_nonce + 16, ready + 6, 8);
int rc = crypto_box_open_afternm (ready_plaintext, ready_box,
clen, ready_nonce, cn_precom);
......
......@@ -141,7 +141,7 @@ int zmq::curve_server_t::encode (msg_t *msg_)
uint8_t *message = static_cast <uint8_t *> (msg_->data ());
memcpy (message, "MESSAGE ", 8);
memcpy (message, "MESSAGE\0", 8);
memcpy (message + 8, &cn_nonce, 8);
memcpy (message + 16, message_box + crypto_box_BOXZEROBYTES,
mlen - crypto_box_BOXZEROBYTES);
......@@ -164,7 +164,7 @@ int zmq::curve_server_t::decode (msg_t *msg_)
}
const uint8_t *message = static_cast <uint8_t *> (msg_->data ());
if (memcmp (message, "MESSAGE ", 8)) {
if (memcmp (message, "MESSAGE\0", 8)) {
errno = EPROTO;
return -1;
}
......@@ -236,13 +236,13 @@ int zmq::curve_server_t::process_hello (msg_t *msg_)
}
const uint8_t * const hello = static_cast <uint8_t *> (msg_->data ());
if (memcmp (hello, "HELLO ", 8)) {
if (memcmp (hello, "HELLO\0", 6)) {
errno = EPROTO;
return -1;
}
const uint8_t major = hello [8];
const uint8_t minor = hello [9];
const uint8_t major = hello [6];
const uint8_t minor = hello [7];
if (major != 1 || minor != 0) {
errno = EPROTO;
......@@ -327,7 +327,7 @@ int zmq::curve_server_t::welcome_msg (msg_t *msg_)
errno_assert (rc == 0);
uint8_t * const welcome = static_cast <uint8_t *> (msg_->data ());
memcpy (welcome, "WELCOME ", 8);
memcpy (welcome, "WELCOME\0", 8);
memcpy (welcome + 8, welcome_nonce + 8, 16);
memcpy (welcome + 24, welcome_ciphertext + crypto_box_BOXZEROBYTES, 144);
......@@ -336,13 +336,13 @@ int zmq::curve_server_t::welcome_msg (msg_t *msg_)
int zmq::curve_server_t::process_initiate (msg_t *msg_)
{
if (msg_->size () < 224) {
if (msg_->size () < 225) {
errno = EPROTO;
return -1;
}
const uint8_t *initiate = static_cast <uint8_t *> (msg_->data ());
if (memcmp (initiate, "INITIATE", 8)) {
if (memcmp (initiate, "INITIATE\0", 9)) {
errno = EPROTO;
return -1;
}
......@@ -353,10 +353,10 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
// Open Box [C' + s'](t)
memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES);
memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 24, 80);
memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80);
memcpy (cookie_nonce, "COOKIE--", 8);
memcpy (cookie_nonce + 8, initiate + 8, 16);
memcpy (cookie_nonce + 8, initiate + 9, 16);
int rc = crypto_secretbox_open (cookie_plaintext, cookie_box,
sizeof cookie_box,
......@@ -375,7 +375,7 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
return -1;
}
const size_t clen = (msg_->size () - 112) + crypto_box_BOXZEROBYTES;
const size_t clen = (msg_->size () - 113) + crypto_box_BOXZEROBYTES;
uint8_t initiate_nonce [crypto_box_NONCEBYTES];
uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 96 + 256];
......@@ -384,10 +384,10 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
// Open Box [C + vouch + metadata](C'->S')
memset (initiate_box, 0, crypto_box_BOXZEROBYTES);
memcpy (initiate_box + crypto_box_BOXZEROBYTES,
initiate + 112, clen - crypto_box_BOXZEROBYTES);
initiate + 113, clen - crypto_box_BOXZEROBYTES);
memcpy (initiate_nonce, "CurveZMQINITIATE", 16);
memcpy (initiate_nonce + 16, initiate + 104, 8);
memcpy (initiate_nonce + 16, initiate + 105, 8);
rc = crypto_box_open (initiate_plaintext, initiate_box,
clen, initiate_nonce, cn_client, cn_secret);
......@@ -475,16 +475,16 @@ int zmq::curve_server_t::ready_msg (msg_t *msg_)
mlen, ready_nonce, cn_precom);
zmq_assert (rc == 0);
rc = msg_->init_size (16 + mlen - crypto_box_BOXZEROBYTES);
rc = msg_->init_size (14 + mlen - crypto_box_BOXZEROBYTES);
errno_assert (rc == 0);
uint8_t *ready = static_cast <uint8_t *> (msg_->data ());
memcpy (ready, "READY ", 8);
memcpy (ready, "READY\0", 6);
// Short nonce, prefixed by "CurveZMQREADY---"
memcpy (ready + 8, &cn_nonce, 8);
memcpy (ready + 6, &cn_nonce, 8);
// Box [metadata](S'->C')
memcpy (ready + 16, ready_box + crypto_box_BOXZEROBYTES,
memcpy (ready + 14, ready_box + crypto_box_BOXZEROBYTES,
mlen - crypto_box_BOXZEROBYTES);
cn_nonce++;
......
......@@ -52,7 +52,7 @@ const char *zmq::mechanism_t::socket_type_string (int socket_type) const
static const char *names [] = {"PAIR", "PUB", "SUB", "REQ", "REP",
"DEALER", "ROUTER", "PULL", "PUSH",
"XPUB", "XSUB", "STREAM"};
zmq_assert (socket_type >= ZMQ_PAIR && socket_type <= ZMQ_STREAM);
zmq_assert (socket_type >= 0 && socket_type <= 10);
return names [socket_type];
}
......
......@@ -54,8 +54,8 @@ int zmq::null_mechanism_t::next_handshake_message (msg_t *msg_)
unsigned char *ptr = command_buffer;
// Add mechanism string
memcpy (ptr, "READY ", 8);
ptr += 8;
memcpy (ptr, "READY\0", 6);
ptr += 6;
// Add socket type property
const char *socket_type = socket_type_string (options.type);
......@@ -91,13 +91,13 @@ int zmq::null_mechanism_t::process_handshake_message (msg_t *msg_)
static_cast <unsigned char *> (msg_->data ());
size_t bytes_left = msg_->size ();
if (bytes_left < 8 || memcmp (ptr, "READY ", 8)) {
if (bytes_left < 6 || memcmp (ptr, "READY\0", 6)) {
errno = EPROTO;
return -1;
}
ptr += 8;
bytes_left -= 8;
ptr += 6;
bytes_left -= 6;
int rc = parse_metadata (ptr, bytes_left);
if (rc == 0) {
......
......@@ -295,9 +295,9 @@ int zmq::plain_mechanism_t::ready_command (msg_t *msg_) const
unsigned char *ptr = command_buffer;
// Add mechanism string
memcpy (ptr, "READY ", 8);
ptr += 8;
// Add command name
memcpy (ptr, "READY\0", 6);
ptr += 6;
// Add socket type property
const char *socket_type = socket_type_string (options.type);
......@@ -325,11 +325,13 @@ int zmq::plain_mechanism_t::process_ready_command (msg_t *msg_)
const unsigned char *ptr = static_cast <unsigned char *> (msg_->data ());
size_t bytes_left = msg_->size ();
if (bytes_left < 8 || memcmp (ptr, "READY ", 8)) {
if (bytes_left < 6 || memcmp (ptr, "READY\0", 6)) {
errno = EPROTO;
return -1;
}
return parse_metadata (ptr + 8, bytes_left - 8);
ptr += 6;
bytes_left -= 6;
return parse_metadata (ptr, bytes_left);
}
void zmq::plain_mechanism_t::send_zap_request (const std::string &username,
......
......@@ -67,4 +67,4 @@ noinst_PROGRAMS += test_raw_sock
test_raw_sock_SOURCES = test_raw_sock.cpp
# Run the test cases
TESTS = $(noinst_PROGRAMS)
TESTS = $(noinst_PROGRAMS)
\ No newline at end of file
......@@ -104,7 +104,7 @@ int main (void)
// Second frame contains the rest of greeting along with
// the Ready command
rc = zmq_recv (router, buffer, 255, 0);
assert (rc == 99);
assert (rc == 97);
// First two bytes are major and minor version numbers.
assert (buffer [0] == 3); // ZMTP/3.0
......@@ -112,21 +112,20 @@ int main (void)
// Mechanism is "NULL"
assert (memcmp (buffer + 2, "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22) == 0);
assert (memcmp (buffer + 54, "\0\53READY ", 10) == 0);
assert (memcmp (buffer + 64, "\13Socket-Type\0\0\0\6DEALER", 22) == 0);
assert (memcmp (buffer + 86, "\10Identity\0\0\0\0", 13) == 0);
assert (memcmp (buffer + 54, "\0\51READY\0", 8) == 0);
assert (memcmp (buffer + 62, "\13Socket-Type\0\0\0\6DEALER", 22) == 0);
assert (memcmp (buffer + 84, "\10Identity\0\0\0\0", 13) == 0);
// Announce we are ready
memcpy (buffer, "\0\53", 2);
memcpy (buffer + 2, "READY ", 8);
memcpy (buffer + 10, "\13Socket-Type\0\0\0\6ROUTER", 22);
memcpy (buffer + 32, "\10Identity\0\0\0\0", 13);
memcpy (buffer, "\0\51READY\0", 8);
memcpy (buffer + 8, "\13Socket-Type\0\0\0\6STREAM", 22);
memcpy (buffer + 30, "\10Identity\0\0\0\0", 13);
// Send Ready command
rc = zmq_msg_send (&identity, router, ZMQ_SNDMORE);
assert (rc > 0);
rc = zmq_send (router, buffer, 45, 0);
assert (rc == 45);
rc = zmq_send (router, buffer, 43, 0);
assert (rc == 43);
// Now we expect the data from the DEALER socket
// First frame is, again, the identity of the connection
......
......@@ -19,106 +19,44 @@
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include "testutil.hpp"
static void *
zap_handler (void *zap)
{
int rc, more;
size_t optlen;
zmq_msg_t version, seqno, domain, mechanism, username, password;
zmq_msg_t status_code, status_text, user_id;
// Version
rc = zmq_msg_init (&version);
assert (rc == 0);
rc = zmq_msg_recv (&version, zap, 0);
assert (rc == 3 && memcmp (zmq_msg_data (&version), "1.0", 3) == 0);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Sequence number
rc = zmq_msg_init (&seqno);
assert (rc == 0);
rc = zmq_msg_recv (&seqno, zap, 0);
assert (rc != -1);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Domain
rc = zmq_msg_init (&domain);
assert (rc == 0);
rc = zmq_msg_recv (&domain, zap, 0);
assert (rc != -1);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Mechanism
rc = zmq_msg_init (&mechanism);
assert (rc == 0);
rc = zmq_msg_recv (&mechanism, zap, 0);
assert (rc == 5 && memcmp (zmq_msg_data (&mechanism), "PLAIN", 5) == 0);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Username
rc = zmq_msg_init (&username);
assert (rc == 0);
rc = zmq_msg_recv (&username, zap, 0);
bool username_ok = (rc == 5 && memcmp (zmq_msg_data (&username), "admin", 5) == 0);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Password
rc = zmq_msg_init (&password);
assert (rc == 0);
rc = zmq_msg_recv (&password, zap, 0);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 0);
bool password_ok = (rc == 8 && memcmp (zmq_msg_data (&password), "password", 8) == 0);
rc = zmq_msg_send (&version, zap, ZMQ_SNDMORE);
assert (rc == 3);
rc = zmq_msg_send (&seqno, zap, ZMQ_SNDMORE);
assert (rc != -1);
rc = zmq_msg_init_size (&status_code, 3);
assert (rc == 0);
memcpy (zmq_msg_data (&status_code), username_ok && password_ok? "200": "400", 3);
rc = zmq_msg_send (&status_code, zap, ZMQ_SNDMORE);
assert (rc == 3);
rc = zmq_msg_init (&status_text);
assert (rc == 0);
rc = zmq_msg_send (&status_text, zap, ZMQ_SNDMORE);
assert (rc == 0);
rc = zmq_msg_init (&user_id);
assert (rc == 0);
rc = zmq_msg_send (&user_id, zap, 0);
assert (rc == 0);
rc = zmq_msg_close (&domain);
assert (rc == 0);
rc = zmq_msg_close (&mechanism);
assert (rc == 0);
rc = zmq_msg_close (&username);
assert (rc == 0);
rc = zmq_msg_close (&password);
assert (rc == 0);
rc = zmq_close (zap);
char *version = s_recv (zap);
char *sequence = s_recv (zap);
char *domain = s_recv (zap);
char *mechanism = s_recv (zap);
char *username = s_recv (zap);
char *password = s_recv (zap);
assert (streq (version, "1.0"));
assert (streq (mechanism, "PLAIN"));
s_sendmore (zap, version);
s_sendmore (zap, sequence);
if (streq (username, "admin")
&& streq (password, "password")) {
s_sendmore (zap, "200");
s_sendmore (zap, "OK");
s_send (zap, "anonymous");
}
else {
s_sendmore (zap, "400");
s_sendmore (zap, "Invalid username or password");
s_send (zap, "");
}
free (version);
free (sequence);
free (domain);
free (mechanism);
free (username);
free (password);
int rc = zmq_close (zap);
assert (rc == 0);
return NULL;
......
......@@ -20,93 +20,34 @@
#include "platform.hpp"
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include "testutil.hpp"
static void *
zap_handler (void *zap)
{
int rc, more;
size_t optlen;
zmq_msg_t version, seqno, domain, mechanism, key;
zmq_msg_t status_code, status_text, user_id;
// Version
rc = zmq_msg_init (&version);
assert (rc == 0);
rc = zmq_msg_recv (&version, zap, 0);
assert (rc == 3 && memcmp (zmq_msg_data (&version), "1.0", 3) == 0);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Sequence number
rc = zmq_msg_init (&seqno);
assert (rc == 0);
rc = zmq_msg_recv (&seqno, zap, 0);
assert (rc != -1);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Domain
rc = zmq_msg_init (&domain);
assert (rc == 0);
rc = zmq_msg_recv (&domain, zap, 0);
assert (rc != -1);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Mechanism
rc = zmq_msg_init (&mechanism);
assert (rc == 0);
rc = zmq_msg_recv (&mechanism, zap, 0);
assert (rc == 5 && memcmp (zmq_msg_data (&mechanism), "CURVE", 5) == 0);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 1);
// Key
rc = zmq_msg_init (&key);
assert (rc == 0);
rc = zmq_msg_recv (&key, zap, 0);
optlen = sizeof more;
rc = zmq_getsockopt (zap, ZMQ_RCVMORE, &more, &optlen);
assert (rc == 0 && more == 0);
// Send response
rc = zmq_msg_send (&version, zap, ZMQ_SNDMORE);
assert (rc == 3);
rc = zmq_msg_send (&seqno, zap, ZMQ_SNDMORE);
assert (rc != -1);
rc = zmq_msg_init_size (&status_code, 3);
assert (rc == 0);
memcpy (zmq_msg_data (&status_code), "200", 3);
rc = zmq_msg_send (&status_code, zap, ZMQ_SNDMORE);
assert (rc == 3);
rc = zmq_msg_init (&status_text);
assert (rc == 0);
rc = zmq_msg_send (&status_text, zap, ZMQ_SNDMORE);
assert (rc == 0);
rc = zmq_msg_init (&user_id);
assert (rc == 0);
rc = zmq_msg_send (&user_id, zap, 0);
assert (rc == 0);
rc = zmq_msg_close (&domain);
assert (rc == 0);
rc = zmq_msg_close (&mechanism);
assert (rc == 0);
rc = zmq_msg_close (&key);
assert (rc == 0);
char *version = s_recv (zap);
char *sequence = s_recv (zap);
char *domain = s_recv (zap);
char *mechanism = s_recv (zap);
char *client_key = s_recv (zap);
assert (streq (version, "1.0"));
assert (streq (mechanism, "CURVE"));
s_sendmore (zap, version);
s_sendmore (zap, sequence);
s_sendmore (zap, "200");
s_sendmore (zap, "OK");
s_send (zap, "anonymous");
free (version);
free (sequence);
free (domain);
free (mechanism);
free (client_key);
rc = zmq_close (zap);
int rc = zmq_close (zap);
assert (rc == 0);
return NULL;
......@@ -115,7 +56,7 @@ zap_handler (void *zap)
int main (void)
{
#ifndef HAVE_LIBSODIUM
printf("Libsodium not availabile - skipping test.\n");
printf("libsodium not installed, skipping CURVE test\n");
return 0;
#endif
int rc;
......
......@@ -101,7 +101,7 @@ test_stream_to_dealer (void)
// Second frame contains the rest of greeting along with
// the Ready command
rc = zmq_recv (stream, buffer, 255, 0);
assert (rc == 99);
assert (rc == 97);
// First two bytes are major and minor version numbers.
assert (buffer [0] == 3); // ZMTP/3.0
......@@ -109,21 +109,20 @@ test_stream_to_dealer (void)
// Mechanism is "NULL"
assert (memcmp (buffer + 2, "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22) == 0);
assert (memcmp (buffer + 54, "\0\53READY ", 10) == 0);
assert (memcmp (buffer + 64, "\13Socket-Type\0\0\0\6DEALER", 22) == 0);
assert (memcmp (buffer + 86, "\10Identity\0\0\0\0", 13) == 0);
assert (memcmp (buffer + 54, "\0\51READY\0", 8) == 0);
assert (memcmp (buffer + 62, "\13Socket-Type\0\0\0\6DEALER", 22) == 0);
assert (memcmp (buffer + 84, "\10Identity\0\0\0\0", 13) == 0);
// Announce we are ready
memcpy (buffer, "\0\53", 2);
memcpy (buffer + 2, "READY ", 8);
memcpy (buffer + 10, "\13Socket-Type\0\0\0\6STREAM", 22);
memcpy (buffer + 32, "\10Identity\0\0\0\0", 13);
memcpy (buffer, "\0\51READY\0", 8);
memcpy (buffer + 8, "\13Socket-Type\0\0\0\6STREAM", 22);
memcpy (buffer + 30, "\10Identity\0\0\0\0", 13);
// Send Ready command
rc = zmq_msg_send (&identity, stream, ZMQ_SNDMORE);
assert (rc > 0);
rc = zmq_send (stream, buffer, 45, 0);
assert (rc == 45);
rc = zmq_send (stream, buffer, 43, 0);
assert (rc == 43);
// Now we expect the data from the DEALER socket
// First frame is, again, the identity of the connection
......
......@@ -76,4 +76,36 @@ bounce (void *server, void *client)
assert (memcmp (buffer, content, 32) == 0);
}
// Receive 0MQ string from socket and convert into C string
// Caller must free returned string. Returns NULL if the context
// is being terminated.
char *
s_recv (void *socket) {
char buffer [256];
int size = zmq_recv (socket, buffer, 255, 0);
if (size == -1)
return NULL;
if (size > 255)
size = 255;
buffer [size] = 0;
return strdup (buffer);
}
// Convert C string to 0MQ string and send to socket
int
s_send (void *socket, const char *string) {
int size = zmq_send (socket, string, strlen (string), 0);
return size;
}
// Sends string as 0MQ string, as multipart non-terminal
int
s_sendmore (void *socket, const char *string) {
int size = zmq_send (socket, string, strlen (string), ZMQ_SNDMORE);
return size;
}
#define streq(s1,s2) (!strcmp ((s1), (s2)))
#define strneq(s1,s2) (strcmp ((s1), (s2)))
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment