/* Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file 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 . */ #include "testutil.hpp" static const int SERVER = 0; static const int CLIENT = 1; struct test_message_t { int turn; const char * text; }; // NOTE: messages are sent without null terminator. const test_message_t dialog [] = { {CLIENT, "i can haz cheez burger?"}, {SERVER, "y u no disonnect?"}, {CLIENT, ""}, }; const int steps = sizeof(dialog) / sizeof(dialog[0]); bool has_more (void* socket) { int more = 0; size_t more_size = sizeof(more); int rc = zmq_getsockopt (socket, ZMQ_RCVMORE, &more, &more_size); if (rc != 0) return false; return more != 0; } bool get_identity (void* socket, char* data, size_t* size) { int rc = zmq_getsockopt (socket, ZMQ_IDENTITY, data, size); return rc == 0; } int main(int, char**) { setup_test_environment(); void* context = zmq_ctx_new (); void* sockets [2]; int rc = 0; sockets [SERVER] = zmq_socket (context, ZMQ_STREAM); rc = zmq_bind (sockets [SERVER], "tcp://0.0.0.0:6666"); assert (rc == 0); sockets [CLIENT] = zmq_socket (context, ZMQ_STREAM); rc = zmq_connect (sockets [CLIENT], "tcp://localhost:6666"); assert (rc == 0); // wait for connect notification // Server: Grab the 1st frame (peer identity). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [SERVER], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [SERVER])); // Server: Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [SERVER], 0); assert (rc != -1); assert(zmq_msg_size (&data_frame) == 0); // Client: Grab the 1st frame (peer identity). rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [CLIENT])); // Client: Grab the 2nd frame (actual payload). rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&data_frame) == 0); // Send initial message. char blob_data [256]; size_t blob_size = sizeof(blob_data); rc = zmq_getsockopt (sockets [CLIENT], ZMQ_IDENTITY, blob_data, &blob_size); assert (rc != -1); assert(blob_size > 0); zmq_msg_t msg; rc = zmq_msg_init_size (&msg, blob_size); assert (rc == 0); memcpy (zmq_msg_data (&msg), blob_data, blob_size); rc = zmq_msg_send (&msg, sockets [dialog [0].turn], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_close (&msg); assert (rc == 0); rc = zmq_msg_init_size (&msg, strlen(dialog [0].text)); assert (rc == 0); memcpy (zmq_msg_data (&msg), dialog [0].text, strlen(dialog [0].text)); rc = zmq_msg_send (&msg, sockets [dialog [0].turn], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_close (&msg); assert (rc == 0); // TODO: make sure this loop doesn't loop forever if something is wrong // with the test (or the implementation). int step = 0; while (step < steps) { // Wait until something happens. zmq_pollitem_t items [] = { { sockets [SERVER], 0, ZMQ_POLLIN, 0 }, { sockets [CLIENT], 0, ZMQ_POLLIN, 0 }, }; int rc = zmq_poll (items, 2, 100); assert (rc >= 0); // Check for data received by the server. if (items [SERVER].revents & ZMQ_POLLIN) { assert (dialog [step].turn == CLIENT); // Grab the 1st frame (peer identity). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [SERVER], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [SERVER])); // Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [SERVER], 0); assert (rc != -1); // Make sure payload matches what we expect. const char * const data = (const char*)zmq_msg_data (&data_frame); const int size = zmq_msg_size (&data_frame); // 0-length frame is a disconnection notification. The server // should receive it as the last step in the dialogue. if (size == 0) { ++step; assert (step == steps); } else { assert ((size_t) size == strlen (dialog [step].text)); int cmp = memcmp (dialog [step].text, data, size); assert (cmp == 0); ++step; assert (step < steps); // Prepare the response. rc = zmq_msg_close (&data_frame); assert (rc == 0); rc = zmq_msg_init_size (&data_frame, strlen (dialog [step].text)); assert (rc == 0); memcpy (zmq_msg_data (&data_frame), dialog [step].text, zmq_msg_size (&data_frame)); // Send the response. rc = zmq_msg_send (&peer_frame, sockets [SERVER], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_send (&data_frame, sockets [SERVER], ZMQ_SNDMORE); assert (rc != -1); } // Release resources. rc = zmq_msg_close (&peer_frame); assert (rc == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); } // Check for data received by the client. if (items [CLIENT].revents & ZMQ_POLLIN) { assert (dialog [step].turn == SERVER); // Grab the 1st frame (peer identity). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [CLIENT])); // Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&data_frame) > 0); // Make sure payload matches what we expect. const char * const data = (const char*)zmq_msg_data (&data_frame); const int size = zmq_msg_size (&data_frame); assert ((size_t)size == strlen(dialog [step].text)); int cmp = memcmp(dialog [step].text, data, size); assert (cmp == 0); ++step; // Prepare the response (next line in the dialog). assert (step < steps); rc = zmq_msg_close (&data_frame); assert (rc == 0); rc = zmq_msg_init_size (&data_frame, strlen (dialog [step].text)); assert (rc == 0); memcpy (zmq_msg_data (&data_frame), dialog [step].text, zmq_msg_size (&data_frame)); // Send the response. rc = zmq_msg_send (&peer_frame, sockets [CLIENT], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_send (&data_frame, sockets [CLIENT], ZMQ_SNDMORE); assert (rc != -1); // Release resources. rc = zmq_msg_close (&peer_frame); assert (rc == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); } } assert (step == steps); rc = zmq_close (sockets [CLIENT]); assert (rc == 0); rc = zmq_close (sockets [SERVER]); assert (rc == 0); rc = zmq_ctx_term (context); assert (rc == 0); return 0; }