static void s_broker_client_msg(broker_t *self, zframe_t *sender, zmsg_t *msg) { assert(zmsg_size(msg) >= 2); zframe_t *service_frame = zmsg_pop(msg); service_t *service = s_service_require(self, service_frame); zmsg_wrap(msg, zframe_dup(sender)); if (zframe_size(service_frame) >= 4 && memcmp(zframe_data(service_frame), "mmi.", 4) == 0){ char *return_code; if (zframe_streq(service_frame, "mmi.service")){ char *name = zframe_strdup(zmsg_last(msg)); service_t *service = (service_t *)zhash_lookup(self->services, name); return_code = service && service->workers ? "200" : "404"; free(name); } else return_code = "501"; zframe_reset(zmsg_last(msg), return_code, strlen(return_code)); zframe_t *client = zmsg_unwrap(msg); zmsg_prepend(msg, &service_frame); zmsg_pushstr(msg, MDPC_CLIENT); zmsg_wrap(msg, client); zmsg_send(&msg, self->socket); } else s_service_dispatch(service, msg); zframe_destroy(&service_frame); }
int zgossip_msg_send (zgossip_msg_t **self_p, void *output) { assert (self_p); assert (*self_p); assert (output); // Save routing_id if any, as encode will destroy it zgossip_msg_t *self = *self_p; zframe_t *routing_id = self->routing_id; self->routing_id = NULL; // Encode zgossip_msg message to a single zmsg zmsg_t *msg = zgossip_msg_encode (&self); // If we're sending to a ROUTER, send the routing_id first if (zsocket_type (zsock_resolve (output)) == ZMQ_ROUTER) { assert (routing_id); zmsg_prepend (msg, &routing_id); } else zframe_destroy (&routing_id); if (msg && zmsg_send (&msg, output) == 0) return 0; else return -1; // Failed to encode, or send }
// Send a message to the next available executor. Will attempt // to send to all available executors until send succeeds, or // returns -1 if all fail. int broker_send_to_executor (broker_t *self, zmsg_t *msg) { int rc = -1; while (rc != 0 && zlist_size (self->executor_lb)) { zframe_t *executor_addr = (zframe_t *) zlist_pop (self->executor_lb); zmsg_prepend (msg, &executor_addr); // [executor] [context] [request] rc = zmsg_send (&msg, self->executors); if (rc != 0) { zframe_t *addr_discard = zmsg_pop (msg); zframe_destroy (&addr_discard); } } return rc; }
void zmsg_test (bool verbose) { printf (" * zmsg: "); int rc = 0; // @selftest // Create two PAIR sockets and connect over inproc zsock_t *output = zsock_new_pair ("@inproc://zmsg.test"); assert (output); zsock_t *input = zsock_new_pair (">inproc://zmsg.test"); assert (input); // Test send and receive of single-frame message zmsg_t *msg = zmsg_new (); assert (msg); zframe_t *frame = zframe_new ("Hello", 5); assert (frame); zmsg_prepend (msg, &frame); assert (zmsg_size (msg) == 1); assert (zmsg_content_size (msg) == 5); rc = zmsg_send (&msg, output); assert (msg == NULL); assert (rc == 0); msg = zmsg_recv (input); assert (msg); assert (zmsg_size (msg) == 1); assert (zmsg_content_size (msg) == 5); zmsg_destroy (&msg); // Test send and receive of multi-frame message msg = zmsg_new (); assert (msg); rc = zmsg_addmem (msg, "Frame0", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame1", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame2", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame3", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame4", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame5", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame6", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame7", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame8", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame9", 6); assert (rc == 0); zmsg_t *copy = zmsg_dup (msg); assert (copy); rc = zmsg_send (©, output); assert (rc == 0); rc = zmsg_send (&msg, output); assert (rc == 0); copy = zmsg_recv (input); assert (copy); assert (zmsg_size (copy) == 10); assert (zmsg_content_size (copy) == 60); zmsg_destroy (©); msg = zmsg_recv (input); assert (msg); assert (zmsg_size (msg) == 10); assert (zmsg_content_size (msg) == 60); // create empty file for null test FILE *file = fopen ("zmsg.test", "w"); assert (file); fclose (file); file = fopen ("zmsg.test", "r"); zmsg_t *null_msg = zmsg_load (NULL, file); assert (null_msg == NULL); fclose (file); remove ("zmsg.test"); // Save to a file, read back file = fopen ("zmsg.test", "w"); assert (file); rc = zmsg_save (msg, file); assert (rc == 0); fclose (file); file = fopen ("zmsg.test", "r"); rc = zmsg_save (msg, file); assert (rc == -1); fclose (file); zmsg_destroy (&msg); file = fopen ("zmsg.test", "r"); msg = zmsg_load (NULL, file); assert (msg); fclose (file); remove ("zmsg.test"); assert (zmsg_size (msg) == 10); assert (zmsg_content_size (msg) == 60); // Remove all frames except first and last int frame_nbr; for (frame_nbr = 0; frame_nbr < 8; frame_nbr++) { zmsg_first (msg); frame = zmsg_next (msg); zmsg_remove (msg, frame); zframe_destroy (&frame); } // Test message frame manipulation assert (zmsg_size (msg) == 2); frame = zmsg_last (msg); assert (zframe_streq (frame, "Frame9")); assert (zmsg_content_size (msg) == 12); frame = zframe_new ("Address", 7); assert (frame); zmsg_prepend (msg, &frame); assert (zmsg_size (msg) == 3); rc = zmsg_addstr (msg, "Body"); assert (rc == 0); assert (zmsg_size (msg) == 4); frame = zmsg_pop (msg); zframe_destroy (&frame); assert (zmsg_size (msg) == 3); char *body = zmsg_popstr (msg); assert (streq (body, "Frame0")); free (body); zmsg_destroy (&msg); // Test encoding/decoding msg = zmsg_new (); assert (msg); byte *blank = (byte *) zmalloc (100000); assert (blank); rc = zmsg_addmem (msg, blank, 0); assert (rc == 0); rc = zmsg_addmem (msg, blank, 1); assert (rc == 0); rc = zmsg_addmem (msg, blank, 253); assert (rc == 0); rc = zmsg_addmem (msg, blank, 254); assert (rc == 0); rc = zmsg_addmem (msg, blank, 255); assert (rc == 0); rc = zmsg_addmem (msg, blank, 256); assert (rc == 0); rc = zmsg_addmem (msg, blank, 65535); assert (rc == 0); rc = zmsg_addmem (msg, blank, 65536); assert (rc == 0); rc = zmsg_addmem (msg, blank, 65537); assert (rc == 0); free (blank); assert (zmsg_size (msg) == 9); byte *buffer; size_t buffer_size = zmsg_encode (msg, &buffer); zmsg_destroy (&msg); msg = zmsg_decode (buffer, buffer_size); assert (msg); free (buffer); zmsg_destroy (&msg); // Test submessages msg = zmsg_new (); assert (msg); zmsg_t *submsg = zmsg_new (); zmsg_pushstr (msg, "matr"); zmsg_pushstr (submsg, "joska"); rc = zmsg_addmsg (msg, &submsg); assert (rc == 0); assert (submsg == NULL); submsg = zmsg_popmsg (msg); assert (submsg == NULL); // string "matr" is not encoded zmsg_t, so was discarded submsg = zmsg_popmsg (msg); assert (submsg); body = zmsg_popstr (submsg); assert (streq (body, "joska")); free (body); zmsg_destroy (&submsg); frame = zmsg_pop (msg); assert (frame == NULL); zmsg_destroy (&msg); // Test comparison of two messages msg = zmsg_new (); zmsg_addstr (msg, "One"); zmsg_addstr (msg, "Two"); zmsg_addstr (msg, "Three"); zmsg_t *msg_other = zmsg_new (); zmsg_addstr (msg_other, "One"); zmsg_addstr (msg_other, "Two"); zmsg_addstr (msg_other, "One-Hundred"); zmsg_t *msg_dup = zmsg_dup (msg); zmsg_t *empty_msg = zmsg_new (); zmsg_t *empty_msg_2 = zmsg_new (); assert (zmsg_eq (msg, msg_dup)); assert (!zmsg_eq (msg, msg_other)); assert (zmsg_eq (empty_msg, empty_msg_2)); assert (!zmsg_eq (msg, NULL)); assert (!zmsg_eq (NULL, empty_msg)); assert (!zmsg_eq (NULL, NULL)); zmsg_destroy (&msg); zmsg_destroy (&msg_other); zmsg_destroy (&msg_dup); zmsg_destroy (&empty_msg); zmsg_destroy (&empty_msg_2); // Test signal messages msg = zmsg_new_signal (0); assert (zmsg_signal (msg) == 0); zmsg_destroy (&msg); msg = zmsg_new_signal (-1); assert (zmsg_signal (msg) == 255); zmsg_destroy (&msg); // Now try methods on an empty message msg = zmsg_new (); assert (msg); assert (zmsg_size (msg) == 0); assert (zmsg_unwrap (msg) == NULL); assert (zmsg_first (msg) == NULL); assert (zmsg_last (msg) == NULL); assert (zmsg_next (msg) == NULL); assert (zmsg_pop (msg) == NULL); // Sending an empty message is valid and destroys the message assert (zmsg_send (&msg, output) == 0); assert (!msg); zsock_destroy (&input); zsock_destroy (&output); // @end printf ("OK\n"); }
static void * client_task (void *args) { bool verbose = *((bool *) args); char filename [256]; snprintf (filename, 255, TESTDIR "/client-%07d.cert", randof (10000000)); zcert_t *client_cert = zcert_new (); zcert_save_public (client_cert, filename); curve_client_t *client = curve_client_new (&client_cert); curve_client_set_verbose (client, verbose); zcert_t *server_cert = zcert_load (TESTDIR "/server.cert"); assert (server_cert); curve_client_connect (client, "tcp://127.0.0.1:9006", zcert_public_key (server_cert)); zcert_destroy (&server_cert); curve_client_sendstr (client, "Hello, World"); char *reply = curve_client_recvstr (client); assert (streq (reply, "Hello, World")); free (reply); // Try a multipart message zmsg_t *msg = zmsg_new (); zmsg_addstr (msg, "Hello, World"); zmsg_addstr (msg, "Second frame"); curve_client_send (client, &msg); msg = curve_client_recv (client); assert (zmsg_size (msg) == 2); zmsg_destroy (&msg); // Now send messages of increasing size, check they work int count; int size = 0; for (count = 0; count < 18; count++) { zframe_t *data = zframe_new (NULL, size); int byte_nbr; // Set data to sequence 0...255 repeated for (byte_nbr = 0; byte_nbr < size; byte_nbr++) zframe_data (data)[byte_nbr] = (byte) byte_nbr; msg = zmsg_new (); zmsg_prepend (msg, &data); curve_client_send (client, &msg); msg = curve_client_recv (client); data = zmsg_pop (msg); assert (data); assert (zframe_size (data) == size); for (byte_nbr = 0; byte_nbr < size; byte_nbr++) { assert (zframe_data (data)[byte_nbr] == (byte) byte_nbr); } zframe_destroy (&data); zmsg_destroy (&msg); size = size * 2 + 1; } // Signal end of test curve_client_sendstr (client, "END"); reply = curve_client_recvstr (client); free (reply); curve_client_destroy (&client); return NULL; }
void curve_client_test (bool verbose) { printf (" * curve_client: "); // @selftest // Create temporary directory for test files zsys_dir_create (TESTDIR); // We'll create two new certificates and save the client public // certificate on disk; in a real case we'd transfer this securely // from the client machine to the server machine. zcert_t *server_cert = zcert_new (); zcert_save (server_cert, TESTDIR "/server.cert"); // We'll run the server as a background task, and the // client in this foreground thread. zthread_new (server_task, &verbose); zcert_t *client_cert = zcert_new (); zcert_save_public (client_cert, TESTDIR "/client.cert"); curve_client_t *client = curve_client_new (&client_cert); curve_client_set_metadata (client, "Client", "CURVEZMQ/curve_client"); curve_client_set_metadata (client, "Identity", "E475DA11"); curve_client_set_verbose (client, verbose); curve_client_connect (client, "tcp://127.0.0.1:9005", (byte *)zcert_public_key (server_cert)); curve_client_sendstr (client, "Hello, World"); char *reply = curve_client_recvstr (client); assert (streq (reply, "Hello, World")); free (reply); // Try a multipart message zmsg_t *msg = zmsg_new (); zmsg_addstr (msg, "Hello, World"); zmsg_addstr (msg, "Second frame"); curve_client_send (client, &msg); msg = curve_client_recv (client); assert (zmsg_size (msg) == 2); zmsg_destroy (&msg); // Now send messages of increasing size, check they work int count; int size = 0; for (count = 0; count < 18; count++) { if (verbose) printf ("Testing message of size=%d...\n", size); zframe_t *data = zframe_new (NULL, size); int byte_nbr; // Set data to sequence 0...255 repeated for (byte_nbr = 0; byte_nbr < size; byte_nbr++) zframe_data (data)[byte_nbr] = (byte) byte_nbr; msg = zmsg_new (); zmsg_prepend (msg, &data); curve_client_send (client, &msg); msg = curve_client_recv (client); data = zmsg_pop (msg); assert (data); assert (zframe_size (data) == size); for (byte_nbr = 0; byte_nbr < size; byte_nbr++) { assert (zframe_data (data)[byte_nbr] == (byte) byte_nbr); } zframe_destroy (&data); zmsg_destroy (&msg); size = size * 2 + 1; } // Signal end of test curve_client_sendstr (client, "END"); reply = curve_client_recvstr (client); free (reply); zcert_destroy (&server_cert); zcert_destroy (&client_cert); curve_client_destroy (&client); // Delete all test files zdir_t *dir = zdir_new (TESTDIR, NULL); zdir_remove (dir, true); zdir_destroy (&dir); // @end // Ensure server thread has exited before we do zclock_sleep (100); printf ("OK\n"); }
/// // Push frame to the front of the message, i.e. before all other frames. // Message takes ownership of frame, will destroy it when message is sent. // Returns 0 on success, -1 on error. Deprecates zmsg_push, which did not // nullify the caller's frame reference. int QmlZmsg::prepend (QmlZframe *frameP) { return zmsg_prepend (self, &frameP->self); };
/// // Push frame to the front of the message, i.e. before all other frames. // Message takes ownership of frame, will destroy it when message is sent. // Returns 0 on success, -1 on error. Deprecates zmsg_push, which did not // nullify the caller's frame reference. int QZmsg::prepend (QZframe *frameP) { int rv = zmsg_prepend (self, &frameP->self); return rv; }
zmsg_t * zre_msg_encode (zre_msg_t *self, int socket_type) { assert (self); zmsg_t *msg = zmsg_new (); // If we're sending to a ROUTER, send the routing_id first if (socket_type == ZMQ_ROUTER) zmsg_prepend (msg, &self->routing_id); size_t frame_size = 2 + 1; // Signature and message ID switch (self->id) { case ZRE_MSG_HELLO: // sequence is a 2-byte integer frame_size += 2; // ipaddress is a string with 1-byte length frame_size++; // Size is one octet if (self->ipaddress) frame_size += strlen (self->ipaddress); // mailbox is a 2-byte integer frame_size += 2; // groups is an array of strings frame_size += 4; // Size is 4 octets if (self->groups) { // Add up size of list contents char *groups = (char *) zlist_first (self->groups); while (groups) { frame_size += 4 + strlen (groups); groups = (char *) zlist_next (self->groups); } } // status is a 1-byte integer frame_size += 1; // headers is an array of key=value strings frame_size += 4; // Size is 4 octets if (self->headers) { self->headers_bytes = 0; // Add up size of dictionary contents zhash_foreach (self->headers, s_headers_count, self); } frame_size += self->headers_bytes; break; case ZRE_MSG_WHISPER: // sequence is a 2-byte integer frame_size += 2; break; case ZRE_MSG_SHOUT: // sequence is a 2-byte integer frame_size += 2; // group is a string with 1-byte length frame_size++; // Size is one octet if (self->group) frame_size += strlen (self->group); break; case ZRE_MSG_JOIN: // sequence is a 2-byte integer frame_size += 2; // group is a string with 1-byte length frame_size++; // Size is one octet if (self->group) frame_size += strlen (self->group); // status is a 1-byte integer frame_size += 1; break; case ZRE_MSG_LEAVE: // sequence is a 2-byte integer frame_size += 2; // group is a string with 1-byte length frame_size++; // Size is one octet if (self->group) frame_size += strlen (self->group); // status is a 1-byte integer frame_size += 1; break; case ZRE_MSG_PING: // sequence is a 2-byte integer frame_size += 2; break; case ZRE_MSG_PING_OK: // sequence is a 2-byte integer frame_size += 2; break; default: printf ("E: bad message type '%d', not sent\n", self->id); // No recovery, this is a fatal application error assert (false); } // Now serialize message into the frame zframe_t *frame = zframe_new (NULL, frame_size); self->needle = zframe_data (frame); PUT_NUMBER2 (0xAAA0 | 1); PUT_NUMBER1 (self->id); switch (self->id) { case ZRE_MSG_HELLO: PUT_NUMBER2 (self->sequence); if (self->ipaddress) { PUT_STRING (self->ipaddress); } else PUT_NUMBER1 (0); // Empty string PUT_NUMBER2 (self->mailbox); if (self->groups) { PUT_NUMBER4 (zlist_size (self->groups)); char *groups = (char *) zlist_first (self->groups); while (groups) { PUT_LONGSTR (groups); groups = (char *) zlist_next (self->groups); } } else PUT_NUMBER4 (0); // Empty string array PUT_NUMBER1 (self->status); if (self->headers) { PUT_NUMBER4 (zhash_size (self->headers)); zhash_foreach (self->headers, s_headers_write, self); } else PUT_NUMBER4 (0); // Empty dictionary break; case ZRE_MSG_WHISPER: PUT_NUMBER2 (self->sequence); break; case ZRE_MSG_SHOUT: PUT_NUMBER2 (self->sequence); if (self->group) { PUT_STRING (self->group); } else PUT_NUMBER1 (0); // Empty string break; case ZRE_MSG_JOIN: PUT_NUMBER2 (self->sequence); if (self->group) { PUT_STRING (self->group); } else PUT_NUMBER1 (0); // Empty string PUT_NUMBER1 (self->status); break; case ZRE_MSG_LEAVE: PUT_NUMBER2 (self->sequence); if (self->group) { PUT_STRING (self->group); } else PUT_NUMBER1 (0); // Empty string PUT_NUMBER1 (self->status); break; case ZRE_MSG_PING: PUT_NUMBER2 (self->sequence); break; case ZRE_MSG_PING_OK: PUT_NUMBER2 (self->sequence); break; } // Now send the data frame if (zmsg_append (msg, &frame)) { zmsg_destroy (&msg); zre_msg_destroy (&self); return NULL; } // Now send the content field if set if (self->id == ZRE_MSG_WHISPER) { zframe_t *content_part = zmsg_pop (self->content); while (content_part) { zmsg_append (msg, &content_part); content_part = zmsg_pop (self->content); } } // Now send the content field if set if (self->id == ZRE_MSG_SHOUT) { zframe_t *content_part = zmsg_pop (self->content); while (content_part) { zmsg_append (msg, &content_part); content_part = zmsg_pop (self->content); } } // Destroy zre_msg object zre_msg_destroy (&self); return msg; }
void broker_run (broker_t *self) { // Only accepting requests when executors available. bool accepting_requests = false; while (1) { zsock_t *which = (zsock_t *) zpoller_wait (self->poller, 10); if (which == self->contexts) { puts ("[BROKER] which == self->contexts"); // [context] [request] zmsg_t *msg = zmsg_recv (self->contexts); assert (msg); if (0 != broker_send_to_executor (self, msg)) zlist_append (self->backlog, msg); // Remove contexts from poller if no executors if (zlist_size (self->executor_lb) == 0) { zpoller_remove (self->poller, self->contexts); accepting_requests = false; } } else if (which == self->executors) { puts ("[BROKER] which == self->executors"); // EITHER: // [executor] ["READY"] // [executor] [context] [response] zmsg_t *msg = zmsg_recv (self->executors); assert (msg); zframe_t *executor_addr = zmsg_pop (msg); assert (executor_addr); zframe_t *ctx_or_ready = zmsg_pop (msg); char *context_addr = zframe_strdup (ctx_or_ready); if (strcmp (context_addr, "READY") != 0) { // Forward the response to the correct context addr. // [context] [0] [response] zmsg_prepend (msg, &ctx_or_ready); zmsg_send (&msg, self->contexts); } else { // Got a READY message // Put the executor ID back in the available queue zlist_append (self->executor_lb, executor_addr); // We know at least one executor is now available, // so check and assign backlog tasks. broker_check_backlog (self); // If we now have executors but not accepting requests, // then start polling on the frontend socket. if (!accepting_requests && zlist_size (self->executor_lb)) { zpoller_add (self->poller, self->contexts); accepting_requests = true; } // Destroy the READY message. zmsg_destroy (&msg); } } else if (zpoller_terminated (self->poller)) break; } }
Z K2(zmsgprepend){PC(x); PC(y); zframe_t*f=(zframe_t*)(intptr_t)yj; R kj(zmsg_prepend(VSK(x), &f));}
int main(void) { zctx_t *ctx = zctx_new(); void *frontend = zsocket_new(ctx, ZMQ_ROUTER); void *backend = zsocket_new(ctx, ZMQ_ROUTER); zsocket_bind(frontend, "tcp://127.0.0.1:5555"); zsocket_bind(backend, "tcp://127.0.0.1:5556"); zlist_t *workers = zlist_new(); uint64_t heartbeat_at = zclock_time() + HEARTBEAT_INTERVAL; while (true){ zmq_pollitem_t items [] ={ {backend, 0, ZMQ_POLLIN, 0}, {frontend, 0, ZMQ_POLLIN, 0} }; int rc = zmq_poll(items, zlist_size(worker)?2:1); if (rc == -1) break; if (items[0].revents & ZMQ_POLLIN){ zmsg_t *msg = zmsg_recv(backend); if (!msg) break; zframe_t *identity = zmsg_unwrap(msg); worker_t *worker = s_worker_new(identity); s_worker_ready(worker, workers); if (zmsg_size(msg) == 1){ zframe_t *frame = zmsg_first(msg); if (memcmp(zframe_data(frame), PPP_READY, 1) && memcmp(zframe_data(frame), PPP_HEARTBEAT, 1)){ printf("E: invalid message from worker"); zmsg_dump(msg); } zmsg_destroy(&msg); } else zmsg_send(&msg, frontend); } if (items[1].revents & ZMQ_POLLIN){ zmsg_t *msg = zmsg_recv(frontend); if (!msg) break; zframe_t *identity = s_workers_next(workers); zmsg_prepend(msg, &identity); zmsg_send(&msg, backend); } if (zclock_time() >= heartbeat_at){ worker_t *worker = (worker_t *)zlist_first(workers); while (worker){ zframe_send(&worker->identity, backend, ZFRAME_REUSE + ZFRAME_MORE); zframe_t *frame = zframe_new(PPP_HEARTBEAT, 1); zframe_send(&frame, backend, 0); worker = (worker_t *)zlist_next(workers); } heartbeat_at = zclock_time() + HEARTBEAT_INTERVAL; } s_workers_purge(workers); } while (zlist_size(workers)){ worker_t *worker = (worker_t *)zlist_pop(workers); s_worker_destroy(&worker); } zlist_destroy(&workers); zctx_destroy(&ctx); return 0; }
END_TEST // -------------------------------------------------------------------------- /// Try to _pop () multiple different values. START_TEST(test_msg_pop) { sam_selftest_introduce ("test_msg_pop"); zmsg_t *zmsg = zmsg_new (); // data to be pop()'d char *nbr = "17"; char *str = "test"; char a = 'a'; zframe_t *char_frame = zframe_new (&a, sizeof (a)); void *ptr = (void *) 0xbadc0de; // compose zmsg out of // a number (i) int rc = zmsg_pushstr (zmsg, nbr); ck_assert_int_eq (rc, 0); // a char * (s) rc = zmsg_pushstr (zmsg, str); ck_assert_int_eq (rc, 0); // a frame * (f) zframe_t *frame_dup = zframe_dup (char_frame); rc = zmsg_prepend (zmsg, &frame_dup); ck_assert_int_eq (rc, 0); // a void * (p) rc = zmsg_pushmem (zmsg, &ptr, sizeof (ptr)); ck_assert_int_eq (rc, 0); // values to be filled int pic_nbr; char *pic_str; zframe_t *pic_frame; void *pic_ptr; // create message sam_msg_t *msg = sam_msg_new (&zmsg); ck_assert_int_eq (sam_msg_size (msg), 4); rc = sam_msg_pop (msg, "pfsi", &pic_ptr, &pic_frame, &pic_str, &pic_nbr); // test data ck_assert_int_eq (rc, 0); ck_assert_int_eq (sam_msg_size (msg), 0); ck_assert (zframe_eq (char_frame, pic_frame)); ck_assert_int_eq (pic_nbr, atoi (nbr)); ck_assert_str_eq (pic_str, str); ck_assert_ptr_eq (pic_ptr, ptr); // clean up zframe_destroy (&char_frame); sam_msg_destroy (&msg); }