Merge pull request #1032 from hurtonm/master

PLAIN: Implement ERROR handling in client
This commit is contained in:
Pieter Hintjens 2014-05-13 19:14:36 +02:00
commit 3338c76bac
2 changed files with 70 additions and 36 deletions

View File

@ -30,6 +30,7 @@
zmq::plain_client_t::plain_client_t (const options_t &options_) : zmq::plain_client_t::plain_client_t (const options_t &options_) :
mechanism_t (options_), mechanism_t (options_),
error_command_received (false),
state (sending_hello) state (sending_hello)
{ {
} }
@ -62,38 +63,45 @@ int zmq::plain_client_t::next_handshake_command (msg_t *msg_)
int zmq::plain_client_t::process_handshake_command (msg_t *msg_) int zmq::plain_client_t::process_handshake_command (msg_t *msg_)
{ {
int rc = 0; const unsigned char *cmd_data =
static_cast <unsigned char *> (msg_->data ());
const size_t data_size = msg_->size ();
switch (state) { int rc = 0;
case waiting_for_welcome: if (data_size >= 8 && !memcmp (cmd_data, "\7WELCOME", 8))
rc = process_welcome (msg_); rc = process_welcome (cmd_data, data_size);
if (rc == 0) else
state = sending_initiate; if (data_size >= 6 && !memcmp (cmd_data, "\5READY", 6))
break; rc = process_ready (cmd_data, data_size);
case waiting_for_ready: else
rc = process_ready (msg_); if (data_size >= 6 && !memcmp (cmd_data, "\5ERROR", 6))
if (rc == 0) rc = process_error (cmd_data, data_size);
state = ready; else {
break; // Temporary support for security debugging
default: puts ("PLAIN I: invalid handshake command");
// Temporary support for security debugging errno = EPROTO;
puts ("PLAIN I: invalid handshake command"); rc = -1;
errno = EPROTO;
rc = -1;
break;
} }
if (rc == 0) { if (rc == 0) {
rc = msg_->close (); rc = msg_->close ();
errno_assert (rc == 0); errno_assert (rc == 0);
rc = msg_->init (); rc = msg_->init ();
errno_assert (rc == 0); errno_assert (rc == 0);
} }
return rc; return rc;
} }
zmq::mechanism_t::status_t zmq::plain_client_t::status () const zmq::mechanism_t::status_t zmq::plain_client_t::status () const
{ {
return state == ready? mechanism_t::ready: mechanism_t::handshaking; if (state == ready)
return mechanism_t::ready;
else
if (error_command_received)
return mechanism_t::error;
else
return mechanism_t::handshaking;
} }
int zmq::plain_client_t::produce_hello (msg_t *msg_) const int zmq::plain_client_t::produce_hello (msg_t *msg_) const
@ -125,17 +133,18 @@ int zmq::plain_client_t::produce_hello (msg_t *msg_) const
return 0; return 0;
} }
int zmq::plain_client_t::process_welcome (msg_t *msg_) int zmq::plain_client_t::process_welcome (
const unsigned char *cmd_data, size_t data_size)
{ {
const unsigned char *ptr = static_cast <unsigned char *> (msg_->data ()); if (state != waiting_for_welcome) {
const size_t bytes_left = msg_->size ();
if (bytes_left != 8 || memcmp (ptr, "\x07WELCOME", 8)) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send WELCOME");
errno = EPROTO; errno = EPROTO;
return -1; return -1;
} }
if (data_size != 8) {
errno = EPROTO;
return -1;
}
state = sending_initiate;
return 0; return 0;
} }
@ -170,16 +179,35 @@ int zmq::plain_client_t::produce_initiate (msg_t *msg_) const
return 0; return 0;
} }
int zmq::plain_client_t::process_ready (msg_t *msg_) int zmq::plain_client_t::process_ready (
const unsigned char *cmd_data, size_t data_size)
{ {
const unsigned char *ptr = static_cast <unsigned char *> (msg_->data ()); if (state != waiting_for_ready) {
const size_t bytes_left = msg_->size ();
if (bytes_left < 6 || memcmp (ptr, "\x05READY", 6)) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send READY");
errno = EPROTO; errno = EPROTO;
return -1; return -1;
} }
return parse_metadata (ptr + 6, bytes_left - 6); const int rc = parse_metadata (cmd_data + 6, data_size - 6);
if (rc == 0)
state = ready;
return rc;
}
int zmq::plain_client_t::process_error (
const unsigned char *cmd_data, size_t data_size)
{
if (state != waiting_for_welcome && state != waiting_for_ready) {
errno = EPROTO;
return -1;
}
if (data_size == 6) {
errno = EPROTO;
return -1;
}
const size_t size = static_cast <size_t> (cmd_data [6]);
if (6 + 1 + size != data_size) {
errno = EPROTO;
return -1;
}
error_command_received = true;
return 0;
} }

View File

@ -42,6 +42,8 @@ namespace zmq
private: private:
bool error_command_received;
enum state_t { enum state_t {
sending_hello, sending_hello,
waiting_for_welcome, waiting_for_welcome,
@ -55,8 +57,12 @@ namespace zmq
int produce_hello (msg_t *msg_) const; int produce_hello (msg_t *msg_) const;
int produce_initiate (msg_t *msg_) const; int produce_initiate (msg_t *msg_) const;
int process_welcome (msg_t *msg); int process_welcome (
int process_ready (msg_t *msg_); const unsigned char *cmd_data, size_t data_size);
int process_ready (
const unsigned char *cmd_data, size_t data_size);
int process_error (
const unsigned char *cmd_data, size_t data_size);
}; };
} }