int zyre_peer_send (zyre_peer_t *self, zre_msg_t **msg_p) { assert (self); zre_msg_t *msg = *msg_p; assert (msg); if (self->connected) { self->sent_sequence += 1; zre_msg_set_sequence (msg, self->sent_sequence); if (self->verbose) zsys_info ("(%s) send %s to peer=%s sequence=%d", self->origin, zre_msg_command (msg), self->name? self->name: "-", zre_msg_sequence (msg)); if (zre_msg_send (msg, self->mailbox)) { if (errno == EAGAIN) { if (self->verbose) zsys_info ("(%s) disconnect from peer (EAGAIN): name=%s", self->origin, self->name); zyre_peer_disconnect (self); return -1; } // Can't get any other error here assert (false); } } zre_msg_destroy (msg_p); return 0; }
void zyre_group_send (zyre_group_t *self, zre_msg_t **msg_p) { assert (self); zhash_foreach (self->peers, (zhash_foreach_fn *) s_peer_send, *msg_p); zre_msg_destroy (msg_p); }
void zyre_peer_test (bool verbose) { printf (" * zyre_peer: "); zsock_t *mailbox = zsock_new_dealer ("@tcp://127.0.0.1:5551"); zhash_t *peers = zhash_new (); zuuid_t *you = zuuid_new (); zuuid_t *me = zuuid_new (); zyre_peer_t *peer = zyre_peer_new (peers, you); assert (!zyre_peer_connected (peer)); zyre_peer_connect (peer, me, "tcp://127.0.0.1:5551"); assert (zyre_peer_connected (peer)); zyre_peer_set_name (peer, "peer"); assert (streq (zyre_peer_name (peer), "peer")); zre_msg_t *msg = zre_msg_new (ZRE_MSG_HELLO); zre_msg_set_endpoint (msg, "tcp://127.0.0.1:5552"); int rc = zyre_peer_send (peer, &msg); assert (rc == 0); msg = zre_msg_recv (mailbox); assert (msg); if (verbose) zre_msg_print (msg); zre_msg_destroy (&msg); // Destroying container destroys all peers it contains zhash_destroy (&peers); zuuid_destroy (&me); zuuid_destroy (&you); zsock_destroy (&mailbox); printf ("OK\n"); }
int zre_peer_send (zre_peer_t *self, zre_msg_t **msg_p) { assert (self); if (self->connected) { zre_msg_sequence_set (*msg_p, ++(self->sent_sequence)); if (zre_msg_send (msg_p, self->mailbox) && errno == EAGAIN) { zre_peer_disconnect (self); return -1; } } else zre_msg_destroy (msg_p); return 0; }
void zyre_group_test (bool verbose) { printf (" * zyre_group: "); zsock_t *mailbox = zsock_new (ZMQ_DEALER); zsock_bind (mailbox, "tcp://127.0.0.1:5552"); zhash_t *groups = zhash_new (); zyre_group_t *group = zyre_group_new ("tests", groups); zhash_t *peers = zhash_new (); zuuid_t *you = zuuid_new (); zuuid_t *me = zuuid_new (); zyre_peer_t *peer = zyre_peer_new (peers, you); assert (!zyre_peer_connected (peer)); zyre_peer_connect (peer, me, "tcp://127.0.0.1:5552"); assert (zyre_peer_connected (peer)); zyre_group_join (group, peer); zre_msg_t *msg = zre_msg_new (ZRE_MSG_HELLO); zre_msg_set_endpoint (msg, "tcp://127.0.0.1:5552"); zyre_group_send (group, &msg); msg = zre_msg_recv (mailbox); assert (msg); if (verbose) zre_msg_print (msg); zre_msg_destroy (&msg); zuuid_destroy (&me); zuuid_destroy (&you); zhash_destroy (&peers); zhash_destroy (&groups); zsock_destroy (&mailbox); printf ("OK\n"); }
zre_msg_t * zre_msg_decode (zmsg_t **msg_p, int socket_type) { assert (msg_p); zmsg_t *msg = *msg_p; if (msg == NULL) return NULL; zre_msg_t *self = zre_msg_new (0); // If message came from a router socket, first frame is routing_id if (socket_type == ZMQ_ROUTER) { self->routing_id = zmsg_pop (msg); // If message was not valid, forget about it if (!self->routing_id || !zmsg_next (msg)) { zre_msg_destroy (&self); return (NULL); // Malformed or empty } } // Read and parse command in frame zframe_t *frame = zmsg_pop (msg); if (!frame) goto empty; // Malformed or empty // Get and check protocol signature self->needle = zframe_data (frame); self->ceiling = self->needle + zframe_size (frame); uint16_t signature; GET_NUMBER2 (signature); if (signature != (0xAAA0 | 1)) goto empty; // Invalid signature // Get message id and parse per message type GET_NUMBER1 (self->id); switch (self->id) { case ZRE_MSG_HELLO: GET_NUMBER2 (self->sequence); GET_STRING (self->ipaddress); GET_NUMBER2 (self->mailbox); { size_t list_size; GET_NUMBER4 (list_size); self->groups = zlist_new (); zlist_autofree (self->groups); while (list_size--) { char *string; GET_LONGSTR (string); zlist_append (self->groups, string); free (string); } } GET_NUMBER1 (self->status); { size_t hash_size; GET_NUMBER4 (hash_size); self->headers = zhash_new (); zhash_autofree (self->headers); while (hash_size--) { char *key, *value; GET_STRING (key); GET_LONGSTR (value); zhash_insert (self->headers, key, value); free (key); free (value); } } break; case ZRE_MSG_WHISPER: GET_NUMBER2 (self->sequence); // Get zero or more remaining frames, leaving current // frame untouched self->content = zmsg_new (); while (zmsg_size (msg)) zmsg_add (self->content, zmsg_pop (msg)); break; case ZRE_MSG_SHOUT: GET_NUMBER2 (self->sequence); GET_STRING (self->group); // Get zero or more remaining frames, leaving current // frame untouched self->content = zmsg_new (); while (zmsg_size (msg)) zmsg_add (self->content, zmsg_pop (msg)); break; case ZRE_MSG_JOIN: GET_NUMBER2 (self->sequence); GET_STRING (self->group); GET_NUMBER1 (self->status); break; case ZRE_MSG_LEAVE: GET_NUMBER2 (self->sequence); GET_STRING (self->group); GET_NUMBER1 (self->status); break; case ZRE_MSG_PING: GET_NUMBER2 (self->sequence); break; case ZRE_MSG_PING_OK: GET_NUMBER2 (self->sequence); break; default: goto malformed; } // Successful return zframe_destroy (&frame); zmsg_destroy (msg_p); return self; // Error returns malformed: printf ("E: malformed message '%d'\n", self->id); empty: zframe_destroy (&frame); zmsg_destroy (msg_p); zre_msg_destroy (&self); return (NULL); }
static int zyre_node_recv_peer (zyre_node_t *self) { // Router socket tells us the identity of this peer zre_msg_t *msg = zre_msg_recv (self->inbox); if (msg == NULL) return 0; // Interrupted // First frame is sender identity, holding binary UUID zuuid_t *uuid = zuuid_new (); zuuid_set (uuid, zframe_data (zre_msg_address (msg))); // On HELLO we may create the peer if it's unknown // On other commands the peer must already exist zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, zuuid_str (uuid)); if (zre_msg_id (msg) == ZRE_MSG_HELLO) { peer = zyre_node_require_peer (self, uuid, zre_msg_ipaddress (msg), zre_msg_mailbox (msg)); assert (peer); zyre_peer_set_ready (peer, true); } // Ignore command if peer isn't ready if (peer == NULL || !zyre_peer_ready (peer)) { zre_msg_destroy (&msg); zuuid_destroy (&uuid); return 0; } if (!zyre_peer_check_message (peer, msg)) { zclock_log ("W: [%s] lost messages from %s", zuuid_str (self->uuid), zuuid_str (uuid)); assert (false); } // Now process each command if (zre_msg_id (msg) == ZRE_MSG_HELLO) { // Tell the caller about the peer zstr_sendm (self->pipe, "ENTER"); zstr_sendm (self->pipe, zuuid_str (uuid)); zframe_t *headers = zhash_pack (zre_msg_headers (msg)); zframe_send (&headers, self->pipe, 0); // Join peer to listed groups char *name = zre_msg_groups_first (msg); while (name) { zyre_node_join_peer_group (self, peer, name); name = zre_msg_groups_next (msg); } // Hello command holds latest status of peer zyre_peer_set_status (peer, zre_msg_status (msg)); // Store peer headers for future reference zyre_peer_set_headers (peer, zre_msg_headers (msg)); // If peer is a ZRE/LOG collector, connect to it char *collector = zre_msg_headers_string (msg, "X-ZRELOG", NULL); if (collector) zyre_log_connect (self->log, collector); } else if (zre_msg_id (msg) == ZRE_MSG_WHISPER) { // Pass up to caller API as WHISPER event zstr_sendm (self->pipe, "WHISPER"); zstr_sendm (self->pipe, zuuid_str (uuid)); zmsg_t *content = zmsg_dup (zre_msg_content (msg)); zmsg_send (&content, self->pipe); } else if (zre_msg_id (msg) == ZRE_MSG_SHOUT) { // Pass up to caller as SHOUT event zstr_sendm (self->pipe, "SHOUT"); zstr_sendm (self->pipe, zuuid_str (uuid)); zstr_sendm (self->pipe, zre_msg_group (msg)); zmsg_t *content = zmsg_dup (zre_msg_content (msg)); zmsg_send (&content, self->pipe); } else if (zre_msg_id (msg) == ZRE_MSG_PING) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_PING_OK); zyre_peer_send (peer, &msg); } else if (zre_msg_id (msg) == ZRE_MSG_JOIN) { zyre_node_join_peer_group (self, peer, zre_msg_group (msg)); assert (zre_msg_status (msg) == zyre_peer_status (peer)); } else if (zre_msg_id (msg) == ZRE_MSG_LEAVE) { zyre_node_leave_peer_group (self, peer, zre_msg_group (msg)); assert (zre_msg_status (msg) == zyre_peer_status (peer)); } zuuid_destroy (&uuid); zre_msg_destroy (&msg); // Activity from peer resets peer timers zyre_peer_refresh (peer); return 0; }
static int zyre_node_recv_api (zyre_node_t *self) { // Get the whole message off the pipe in one go zmsg_t *request = zmsg_recv (self->pipe); char *command = zmsg_popstr (request); if (!command) return -1; // Interrupted if (streq (command, "SET")) { char *name = zmsg_popstr (request); char *value = zmsg_popstr (request); zhash_update (self->headers, name, value); zstr_free (&name); zstr_free (&value); } else if (streq (command, "START")) { zyre_node_start (self); zstr_send (self->pipe, "OK"); } else if (streq (command, "STOP")) { zyre_node_stop (self); zstr_send (self->pipe, "OK"); } else if (streq (command, "WHISPER")) { // Get peer to send message to char *identity = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, identity); // Send frame on out to peer's mailbox, drop message // if peer doesn't exist (may have been destroyed) if (peer) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_content (msg, request); zyre_peer_send (peer, &msg); request = NULL; } zstr_free (&identity); } else if (streq (command, "SHOUT")) { // Get group to send message to char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_group (msg, name); zre_msg_set_content (msg, request); zyre_group_send (group, &msg); request = NULL; } zstr_free (&name); } else if (streq (command, "JOIN")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (!group) { // Only send if we're not already in group group = zyre_group_new (name, self->own_groups); zre_msg_t *msg = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); zyre_log_info (self->log, ZRE_LOG_MSG_EVENT_JOIN, NULL, name); } zstr_free (&name); } else if (streq (command, "LEAVE")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (group) { // Only send if we are actually in group zre_msg_t *msg = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); zhash_delete (self->own_groups, name); zyre_log_info (self->log, ZRE_LOG_MSG_EVENT_LEAVE, NULL, name); } zstr_free (&name); } else if (streq (command, "TERMINATE")) { self->terminated = true; zstr_send (self->pipe, "OK"); } zstr_free (&command); zmsg_destroy (&request); return 0; }
static void zyre_node_recv_peer (zyre_node_t *self) { // Router socket tells us the identity of this peer zre_msg_t *msg = zre_msg_recv (self->inbox); if (!msg) return; // Interrupted // First frame is sender identity byte *peerid_data = zframe_data (zre_msg_routing_id (msg)); size_t peerid_size = zframe_size (zre_msg_routing_id (msg)); // Identity must be [1] followed by 16-byte UUID if (peerid_size != ZUUID_LEN + 1) { zre_msg_destroy (&msg); return; } zuuid_t *uuid = zuuid_new (); zuuid_set (uuid, peerid_data + 1); // On HELLO we may create the peer if it's unknown // On other commands the peer must already exist zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, zuuid_str (uuid)); if (zre_msg_id (msg) == ZRE_MSG_HELLO) { if (peer) { // Remove fake peers if (zyre_peer_ready (peer)) { zyre_node_remove_peer (self, peer); assert (!(zyre_peer_t *) zhash_lookup (self->peers, zuuid_str (uuid))); } else if (streq (zyre_peer_endpoint (peer), self->endpoint)) { // We ignore HELLO, if peer has same endpoint as current node zre_msg_destroy (&msg); zuuid_destroy (&uuid); return; } } peer = zyre_node_require_peer (self, uuid, zre_msg_endpoint (msg)); assert (peer); zyre_peer_set_ready (peer, true); } // Ignore command if peer isn't ready if (peer == NULL || !zyre_peer_ready (peer)) { zre_msg_destroy (&msg); zuuid_destroy (&uuid); return; } if (zyre_peer_messages_lost (peer, msg)) { zsys_warning ("(%s) messages lost from %s", self->name, zyre_peer_name (peer)); zyre_node_remove_peer (self, peer); zre_msg_destroy (&msg); zuuid_destroy (&uuid); return; } // Now process each command if (zre_msg_id (msg) == ZRE_MSG_HELLO) { // Store properties from HELLO command into peer zyre_peer_set_name (peer, zre_msg_name (msg)); zyre_peer_set_headers (peer, zre_msg_headers (msg)); // Tell the caller about the peer zstr_sendm (self->outbox, "ENTER"); zstr_sendm (self->outbox, zyre_peer_identity (peer)); zstr_sendm (self->outbox, zyre_peer_name (peer)); zframe_t *headers = zhash_pack (zyre_peer_headers (peer)); zframe_send (&headers, self->outbox, ZFRAME_MORE); zstr_send (self->outbox, zre_msg_endpoint (msg)); if (self->verbose) zsys_info ("(%s) ENTER name=%s endpoint=%s", self->name, zyre_peer_name (peer), zyre_peer_endpoint (peer)); // Join peer to listed groups const char *name = zre_msg_groups_first (msg); while (name) { zyre_node_join_peer_group (self, peer, name); name = zre_msg_groups_next (msg); } // Now take peer's status from HELLO, after joining groups zyre_peer_set_status (peer, zre_msg_status (msg)); } else if (zre_msg_id (msg) == ZRE_MSG_WHISPER) { // Pass up to caller API as WHISPER event zstr_sendm (self->outbox, "WHISPER"); zstr_sendm (self->outbox, zuuid_str (uuid)); zstr_sendm (self->outbox, zyre_peer_name (peer)); zmsg_t *content = zmsg_dup (zre_msg_content (msg)); zmsg_send (&content, self->outbox); } else if (zre_msg_id (msg) == ZRE_MSG_SHOUT) { // Pass up to caller as SHOUT event zstr_sendm (self->outbox, "SHOUT"); zstr_sendm (self->outbox, zuuid_str (uuid)); zstr_sendm (self->outbox, zyre_peer_name (peer)); zstr_sendm (self->outbox, zre_msg_group (msg)); zmsg_t *content = zmsg_dup (zre_msg_content (msg)); zmsg_send (&content, self->outbox); } else if (zre_msg_id (msg) == ZRE_MSG_PING) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_PING_OK); zyre_peer_send (peer, &msg); } else if (zre_msg_id (msg) == ZRE_MSG_JOIN) { zyre_node_join_peer_group (self, peer, zre_msg_group (msg)); assert (zre_msg_status (msg) == zyre_peer_status (peer)); } else if (zre_msg_id (msg) == ZRE_MSG_LEAVE) { zyre_node_leave_peer_group (self, peer, zre_msg_group (msg)); assert (zre_msg_status (msg) == zyre_peer_status (peer)); } zuuid_destroy (&uuid); zre_msg_destroy (&msg); // Activity from peer resets peer timers zyre_peer_refresh (peer, self->evasive_timeout, self->expired_timeout); }
static void zyre_node_recv_api (zyre_node_t *self) { // Get the whole message off the pipe in one go zmsg_t *request = zmsg_recv (self->pipe); if (!request) return; // Interrupted char *command = zmsg_popstr (request); if (streq (command, "UUID")) zstr_send (self->pipe, zuuid_str (self->uuid)); else if (streq (command, "NAME")) zstr_send (self->pipe, self->name); else if (streq (command, "SET NAME")) { free (self->name); self->name = zmsg_popstr (request); assert (self->name); } else if (streq (command, "SET HEADER")) { char *name = zmsg_popstr (request); char *value = zmsg_popstr (request); zhash_update (self->headers, name, value); zstr_free (&name); zstr_free (&value); } else if (streq (command, "SET VERBOSE")) self->verbose = true; else if (streq (command, "SET PORT")) { char *value = zmsg_popstr (request); self->beacon_port = atoi (value); zstr_free (&value); } else if (streq (command, "SET EVASIVE TIMEOUT")) { char *value = zmsg_popstr (request); self->evasive_timeout = atoi (value); zstr_free (&value); } else if (streq (command, "SET EXPIRED TIMEOUT")) { char *value = zmsg_popstr (request); self->expired_timeout = atoi (value); zstr_free (&value); } else if (streq (command, "SET INTERVAL")) { char *value = zmsg_popstr (request); self->interval = atol (value); zstr_free (&value); } else if (streq (command, "SET ENDPOINT")) { zyre_node_gossip_start (self); char *endpoint = zmsg_popstr (request); if (zsock_bind (self->inbox, "%s", endpoint) != -1) { zstr_free (&self->endpoint); self->endpoint = endpoint; zsock_signal (self->pipe, 0); } else { zstr_free (&endpoint); zsock_signal (self->pipe, 1); } } else if (streq (command, "GOSSIP BIND")) { zyre_node_gossip_start (self); zstr_free (&self->gossip_bind); self->gossip_bind = zmsg_popstr (request); zstr_sendx (self->gossip, "BIND", self->gossip_bind, NULL); } else if (streq (command, "GOSSIP CONNECT")) { zyre_node_gossip_start (self); zstr_free (&self->gossip_connect); self->gossip_connect = zmsg_popstr (request); zstr_sendx (self->gossip, "CONNECT", self->gossip_connect, NULL); } else if (streq (command, "START")) zsock_signal (self->pipe, zyre_node_start (self)); else if (streq (command, "STOP")) zsock_signal (self->pipe, zyre_node_stop (self)); else if (streq (command, "WHISPER")) { // Get peer to send message to char *identity = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, identity); // Send frame on out to peer's mailbox, drop message // if peer doesn't exist (may have been destroyed) if (peer) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_content (msg, &request); zyre_peer_send (peer, &msg); } zstr_free (&identity); } else if (streq (command, "SHOUT")) { // Get group to send message to char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_group (msg, name); zre_msg_set_content (msg, &request); zyre_group_send (group, &msg); } zstr_free (&name); } else if (streq (command, "JOIN")) { char *name = zmsg_popstr (request); if (!zlist_exists (self->own_groups, name)) { void *item; // Only send if we're not already in group zlist_append (self->own_groups, name); zre_msg_t *msg = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); for (item = zhash_first (self->peers); item != NULL; item = zhash_next (self->peers)) zyre_node_send_peer (zhash_cursor (self->peers), item, msg); zre_msg_destroy (&msg); if (self->verbose) zsys_info ("(%s) JOIN group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "LEAVE")) { char *name = zmsg_popstr (request); if (zlist_exists (self->own_groups, name)) { void *item; // Only send if we are actually in group zre_msg_t *msg = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); for (item = zhash_first (self->peers); item != NULL; item = zhash_next (self->peers)) zyre_node_send_peer (zhash_cursor (self->peers), item, msg); zre_msg_destroy (&msg); zlist_remove (self->own_groups, name); if (self->verbose) zsys_info ("(%s) LEAVE group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "PEERS")) zsock_send (self->pipe, "p", zhash_keys (self->peers)); else if (streq (command, "GROUP PEERS")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) zsock_send (self->pipe, "p", zyre_group_peers (group)); else zsock_send (self->pipe, "p", NULL); zstr_free (&name); } else if (streq (command, "PEER ENDPOINT")) { char *uuid = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, uuid); assert (peer); zsock_send (self->pipe, "s", zyre_peer_endpoint (peer)); zstr_free (&uuid); } else if (streq (command, "PEER NAME")) { char *uuid = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, uuid); assert (peer); zsock_send (self->pipe, "s", zyre_peer_name (peer)); zstr_free (&uuid); } else if (streq (command, "PEER HEADER")) { char *uuid = zmsg_popstr (request); char *key = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, uuid); if (!peer) zstr_send (self->pipe, ""); else zstr_send (self->pipe, zyre_peer_header (peer, key, NULL)); zstr_free (&uuid); zstr_free (&key); } else if (streq (command, "PEER GROUPS")) zsock_send (self->pipe, "p", zhash_keys (self->peer_groups)); else if (streq (command, "OWN GROUPS")) zsock_send (self->pipe, "p", zlist_dup (self->own_groups)); else if (streq (command, "DUMP")) zyre_node_dump (self); else if (streq (command, "$TERM")) self->terminated = true; else { zsys_error ("invalid command '%s'", command); assert (false); } zstr_free (&command); zmsg_destroy (&request); }
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; }
static int zyre_node_recv_api (zyre_node_t *self) { // Get the whole message off the pipe in one go zmsg_t *request = zmsg_recv (self->pipe); char *command = zmsg_popstr (request); if (!command) return -1; // Interrupted if (streq (command, "SET NAME")) { free (self->name); self->name = zmsg_popstr (request); assert (self->name); } else if (streq (command, "SET HEADER")) { char *name = zmsg_popstr (request); char *value = zmsg_popstr (request); zhash_update (self->headers, name, value); zstr_free (&name); zstr_free (&value); } else if (streq (command, "SET VERBOSE")) self->verbose = true; else if (streq (command, "SET PORT")) { char *value = zmsg_popstr (request); self->beacon_port = atoi (value); zstr_free (&value); } else if (streq (command, "SET INTERVAL")) { char *value = zmsg_popstr (request); self->interval = atol (value); zstr_free (&value); } else if (streq (command, "UUID")) zstr_send (self->pipe, zuuid_str (self->uuid)); else if (streq (command, "NAME")) zstr_send (self->pipe, self->name); else if (streq (command, "BIND")) { char *endpoint = zmsg_popstr (request); zsock_signal (self->pipe, zyre_node_bind (self, endpoint)); zstr_free (&endpoint); } else if (streq (command, "CONNECT")) { char *endpoint = zmsg_popstr (request); zsock_signal (self->pipe, zyre_node_connect (self, endpoint)); zstr_free (&endpoint); } else if (streq (command, "START")) zsock_signal (self->pipe, zyre_node_start (self)); else if (streq (command, "STOP")) zsock_signal (self->pipe, zyre_node_stop (self)); else if (streq (command, "WHISPER")) { // Get peer to send message to char *identity = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, identity); // Send frame on out to peer's mailbox, drop message // if peer doesn't exist (may have been destroyed) if (peer) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_content (msg, &request); zyre_peer_send (peer, &msg); } zstr_free (&identity); } else if (streq (command, "SHOUT")) { // Get group to send message to char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_group (msg, name); zre_msg_set_content (msg, &request); zyre_group_send (group, &msg); } zstr_free (&name); } else if (streq (command, "JOIN")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (!group) { // Only send if we're not already in group group = zyre_group_new (name, self->own_groups); zre_msg_t *msg = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); if (self->verbose) zsys_info ("(%s) JOIN group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "LEAVE")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (group) { // Only send if we are actually in group zre_msg_t *msg = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); zhash_delete (self->own_groups, name); if (self->verbose) zsys_info ("(%s) LEAVE group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "DUMP")) zyre_node_dump (self); else if (streq (command, "$TERM")) self->terminated = true; else { zsys_error ("invalid command '%s'\n", command); assert (false); } zstr_free (&command); zmsg_destroy (&request); return 0; }
int zre_msg_test (bool verbose) { printf (" * zre_msg: "); // @selftest // Simple create/destroy test zre_msg_t *self = zre_msg_new (0); assert (self); zre_msg_destroy (&self); // Create pair of sockets we can send through zctx_t *ctx = zctx_new (); assert (ctx); void *output = zsocket_new (ctx, ZMQ_DEALER); assert (output); zsocket_bind (output, "inproc://selftest"); void *input = zsocket_new (ctx, ZMQ_ROUTER); assert (input); zsocket_connect (input, "inproc://selftest"); // Encode/send/decode and verify each message type int instance; zre_msg_t *copy; self = zre_msg_new (ZRE_MSG_HELLO); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_ipaddress (self, "Life is short but Now lasts for ever"); zre_msg_set_mailbox (self, 123); zre_msg_groups_append (self, "Name: %s", "Brutus"); zre_msg_groups_append (self, "Age: %d", 43); zre_msg_set_status (self, 123); zre_msg_headers_insert (self, "Name", "Brutus"); zre_msg_headers_insert (self, "Age", "%d", 43); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_ipaddress (self), "Life is short but Now lasts for ever")); assert (zre_msg_mailbox (self) == 123); assert (zre_msg_groups_size (self) == 2); assert (streq (zre_msg_groups_first (self), "Name: Brutus")); assert (streq (zre_msg_groups_next (self), "Age: 43")); assert (zre_msg_status (self) == 123); assert (zre_msg_headers_size (self) == 2); assert (streq (zre_msg_headers_string (self, "Name", "?"), "Brutus")); assert (zre_msg_headers_number (self, "Age", 0) == 43); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_WHISPER); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zmsg_t *whisper_content = zmsg_new (); zre_msg_set_content (self, &whisper_content); zmsg_addstr (zre_msg_content (self), "Hello, World"); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (zmsg_size (zre_msg_content (self)) == 1); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_SHOUT); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zmsg_t *shout_content = zmsg_new (); zre_msg_set_content (self, &shout_content); zmsg_addstr (zre_msg_content (self), "Hello, World"); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zmsg_size (zre_msg_content (self)) == 1); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_JOIN); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_LEAVE); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_PING); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_PING_OK); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); } zctx_destroy (&ctx); // @end printf ("OK\n"); return 0; }
static int agent_recv_from_peer (agent_t *self) { // Router socket tells us the identity of this peer zre_msg_t *msg = zre_msg_recv (self->inbox); if (msg == NULL) return 0; // Interrupted char *identity = zframe_strdup (zre_msg_address (msg)); // On HELLO we may create the peer if it's unknown // On other commands the peer must already exist zre_peer_t *peer = (zre_peer_t *) zhash_lookup (self->peers, identity); if (zre_msg_id (msg) == ZRE_MSG_HELLO) { peer = s_require_peer ( self, identity, zre_msg_ipaddress (msg), zre_msg_mailbox (msg)); assert (peer); zre_peer_ready_set (peer, true); } // Ignore command if peer isn't ready if (peer == NULL || !zre_peer_ready (peer)) { free(identity); zre_msg_destroy (&msg); return 0; } if (!zre_peer_check_message (peer, msg)) { zclock_log ("W: [%s] lost messages from %s", self->identity, identity); assert (false); } // Now process each command if (zre_msg_id (msg) == ZRE_MSG_HELLO) { // Join peer to listed groups char *name = zre_msg_groups_first (msg); while (name) { s_join_peer_group (self, peer, name); name = zre_msg_groups_next (msg); } // Hello command holds latest status of peer zre_peer_status_set (peer, zre_msg_status (msg)); // Store peer headers for future reference zre_peer_headers_set (peer, zre_msg_headers (msg)); // If peer is a ZRE/LOG collector, connect to it char *collector = zre_msg_headers_string (msg, "X-ZRELOG", NULL); if (collector) zre_log_connect (self->log, collector); // If peer is a FileMQ publisher, connect to it char *publisher = zre_msg_headers_string (msg, "X-FILEMQ", NULL); if (publisher) fmq_client_connect (self->fmq_client, publisher); } else if (zre_msg_id (msg) == ZRE_MSG_WHISPER) { // Pass up to caller API as WHISPER event zframe_t *cookie = zre_msg_content (msg); zstr_sendm (self->pipe, "WHISPER"); zstr_sendm (self->pipe, identity); zframe_send (&cookie, self->pipe, ZFRAME_REUSE); // let msg free the frame } else if (zre_msg_id (msg) == ZRE_MSG_SHOUT) { // Pass up to caller as SHOUT event zframe_t *cookie = zre_msg_content (msg); zstr_sendm (self->pipe, "SHOUT"); zstr_sendm (self->pipe, identity); zstr_sendm (self->pipe, zre_msg_group (msg)); zframe_send (&cookie, self->pipe, ZFRAME_REUSE); // let msg free the frame } else if (zre_msg_id (msg) == ZRE_MSG_PING) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_PING_OK); zre_peer_send (peer, &msg); } else if (zre_msg_id (msg) == ZRE_MSG_JOIN) { s_join_peer_group (self, peer, zre_msg_group (msg)); assert (zre_msg_status (msg) == zre_peer_status (peer)); } else if (zre_msg_id (msg) == ZRE_MSG_LEAVE) { s_leave_peer_group (self, peer, zre_msg_group (msg)); assert (zre_msg_status (msg) == zre_peer_status (peer)); } free (identity); zre_msg_destroy (&msg); // Activity from peer resets peer timers zre_peer_refresh (peer); return 0; }
static int agent_recv_from_api (agent_t *self) { // Get the whole message off the pipe in one go zmsg_t *request = zmsg_recv (self->pipe); char *command = zmsg_popstr (request); if (!command) return -1; // Interrupted if (streq (command, "WHISPER")) { // Get peer to send message to char *identity = zmsg_popstr (request); zre_peer_t *peer = (zre_peer_t *) zhash_lookup (self->peers, identity); // Send frame on out to peer's mailbox, drop message // if peer doesn't exist (may have been destroyed) if (peer) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_content_set (msg, zmsg_pop (request)); zre_peer_send (peer, &msg); } free (identity); } else if (streq (command, "SHOUT")) { // Get group to send message to char *name = zmsg_popstr (request); zre_group_t *group = (zre_group_t *) zhash_lookup (self->peer_groups, name); if (group) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_group_set (msg, name); zre_msg_content_set (msg, zmsg_pop (request)); zre_group_send (group, &msg); } free (name); } else if (streq (command, "JOIN")) { char *name = zmsg_popstr (request); zre_group_t *group = (zre_group_t *) zhash_lookup (self->own_groups, name); if (!group) { // Only send if we're not already in group group = zre_group_new (name, self->own_groups); zre_msg_t *msg = zre_msg_new (ZRE_MSG_JOIN); zre_msg_group_set (msg, name); // Update status before sending command zre_msg_status_set (msg, ++(self->status)); zhash_foreach (self->peers, s_peer_send, msg); zre_msg_destroy (&msg); zre_log_info (self->log, ZRE_LOG_MSG_EVENT_JOIN, NULL, name); } free (name); } else if (streq (command, "LEAVE")) { char *name = zmsg_popstr (request); zre_group_t *group = (zre_group_t *) zhash_lookup (self->own_groups, name); if (group) { // Only send if we are actually in group zre_msg_t *msg = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_group_set (msg, name); // Update status before sending command zre_msg_status_set (msg, ++(self->status)); zhash_foreach (self->peers, s_peer_send, msg); zre_msg_destroy (&msg); zhash_delete (self->own_groups, name); zre_log_info (self->log, ZRE_LOG_MSG_EVENT_LEAVE, NULL, name); } free (name); } else if (streq (command, "SET")) { char *name = zmsg_popstr (request); char *value = zmsg_popstr (request); zhash_update (self->headers, name, value); free (name); free (value); } else if (streq (command, "PUBLISH")) { char *logical = zmsg_popstr (request); char *physical = zmsg_popstr (request); // Virtual filename must start with slash assert (logical [0] == '/'); // We create symbolic link pointing to real file char *symlink = malloc (strlen (logical) + 3); sprintf (symlink, "%s.ln", logical + 1); fmq_file_t *file = fmq_file_new (self->fmq_outbox, symlink); int rc = fmq_file_output (file); assert (rc == 0); fprintf (fmq_file_handle (file), "%s\n", physical); fmq_file_destroy (&file); free (symlink); free (logical); free (physical); } else if (streq (command, "RETRACT")) { char *logical = zmsg_popstr (request); // Logical filename must start with slash assert (logical [0] == '/'); // We create symbolic link pointing to real file char *symlink = malloc (strlen (logical) + 3); sprintf (symlink, "%s.ln", logical + 1); fmq_file_t *file = fmq_file_new (self->fmq_outbox, symlink); fmq_file_remove (file); free (symlink); free (logical); } free (command); zmsg_destroy (&request); return 0; }
int zre_msg_send (zre_msg_t **self_p, void *output) { assert (output); assert (self_p); assert (*self_p); // Calculate size of serialized data zre_msg_t *self = *self_p; 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++; // Size is one octet if (self->groups) { // Add up size of list contents char *groups = (char *) zlist_first (self->groups); while (groups) { frame_size += 1 + 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++; // Size is one octet 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); size_t string_size; int frame_flags = 0; 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 != NULL) { PUT_NUMBER1 (zlist_size (self->groups)); char *groups = (char *) zlist_first (self->groups); while (groups) { PUT_STRING (groups); groups = (char *) zlist_next (self->groups); } } else PUT_NUMBER1 (0); // Empty string array PUT_NUMBER1 (self->status); if (self->headers != NULL) { PUT_NUMBER1 (zhash_size (self->headers)); zhash_foreach (self->headers, s_headers_write, self); } else PUT_NUMBER1 (0); // Empty dictionary break; case ZRE_MSG_WHISPER: PUT_NUMBER2 (self->sequence); frame_flags = ZFRAME_MORE; break; case ZRE_MSG_SHOUT: PUT_NUMBER2 (self->sequence); if (self->group) { PUT_STRING (self->group); } else PUT_NUMBER1 (0); // Empty string frame_flags = ZFRAME_MORE; 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; } // If we're sending to a ROUTER, we send the address first if (zsocket_type (output) == ZMQ_ROUTER) { assert (self->address); if (zframe_send (&self->address, output, ZFRAME_MORE)) { zframe_destroy (&frame); zre_msg_destroy (self_p); return -1; } } // Now send the data frame if (zframe_send (&frame, output, frame_flags)) { zframe_destroy (&frame); zre_msg_destroy (self_p); return -1; } // Now send any frame fields, in order switch (self->id) { case ZRE_MSG_WHISPER: // If content isn't set, send an empty frame if (!self->content) self->content = zframe_new (NULL, 0); if (zframe_send (&self->content, output, 0)) { zframe_destroy (&frame); zre_msg_destroy (self_p); return -1; } break; case ZRE_MSG_SHOUT: // If content isn't set, send an empty frame if (!self->content) self->content = zframe_new (NULL, 0); if (zframe_send (&self->content, output, 0)) { zframe_destroy (&frame); zre_msg_destroy (self_p); return -1; } break; } // Destroy zre_msg object zre_msg_destroy (self_p); return 0; }
zre_msg_t * zre_msg_recv (void *input) { assert (input); zre_msg_t *self = zre_msg_new (0); zframe_t *frame = NULL; size_t string_size; size_t list_size; size_t hash_size; // Read valid message frame from socket; we loop over any // garbage data we might receive from badly-connected peers while (true) { // If we're reading from a ROUTER socket, get address if (zsocket_type (input) == ZMQ_ROUTER) { zframe_destroy (&self->address); self->address = zframe_recv (input); if (!self->address) goto empty; // Interrupted if (!zsocket_rcvmore (input)) goto malformed; } // Read and parse command in frame frame = zframe_recv (input); if (!frame) goto empty; // Interrupted // Get and check protocol signature self->needle = zframe_data (frame); self->ceiling = self->needle + zframe_size (frame); uint16_t signature; GET_NUMBER2 (signature); if (signature == (0xAAA0 | 1)) break; // Valid signature // Protocol assertion, drop message while (zsocket_rcvmore (input)) { zframe_destroy (&frame); frame = zframe_recv (input); } zframe_destroy (&frame); } // Get message id and parse per message type GET_NUMBER1 (self->id); switch (self->id) { case ZRE_MSG_HELLO: GET_NUMBER2 (self->sequence); free (self->ipaddress); GET_STRING (self->ipaddress); GET_NUMBER2 (self->mailbox); GET_NUMBER1 (list_size); self->groups = zlist_new (); zlist_autofree (self->groups); while (list_size--) { char *string; GET_STRING (string); zlist_append (self->groups, string); free (string); } GET_NUMBER1 (self->status); GET_NUMBER1 (hash_size); self->headers = zhash_new (); zhash_autofree (self->headers); while (hash_size--) { char *string; GET_STRING (string); char *value = strchr (string, '='); if (value) *value++ = 0; zhash_insert (self->headers, string, value); free (string); } break; case ZRE_MSG_WHISPER: GET_NUMBER2 (self->sequence); // Get next frame, leave current untouched if (!zsocket_rcvmore (input)) goto malformed; self->content = zframe_recv (input); break; case ZRE_MSG_SHOUT: GET_NUMBER2 (self->sequence); free (self->group); GET_STRING (self->group); // Get next frame, leave current untouched if (!zsocket_rcvmore (input)) goto malformed; self->content = zframe_recv (input); break; case ZRE_MSG_JOIN: GET_NUMBER2 (self->sequence); free (self->group); GET_STRING (self->group); GET_NUMBER1 (self->status); break; case ZRE_MSG_LEAVE: GET_NUMBER2 (self->sequence); free (self->group); GET_STRING (self->group); GET_NUMBER1 (self->status); break; case ZRE_MSG_PING: GET_NUMBER2 (self->sequence); break; case ZRE_MSG_PING_OK: GET_NUMBER2 (self->sequence); break; default: goto malformed; } // Successful return zframe_destroy (&frame); return self; // Error returns malformed: printf ("E: malformed message '%d'\n", self->id); empty: zframe_destroy (&frame); zre_msg_destroy (&self); return (NULL); }
int zre_msg_test (bool verbose) { printf (" * zre_msg: "); // @selftest // Simple create/destroy test zre_msg_t *self = zre_msg_new (0); assert (self); zre_msg_destroy (&self); // Create pair of sockets we can send through zctx_t *ctx = zctx_new (); assert (ctx); void *output = zsocket_new (ctx, ZMQ_DEALER); assert (output); zsocket_bind (output, "inproc://selftest"); void *input = zsocket_new (ctx, ZMQ_ROUTER); assert (input); zsocket_connect (input, "inproc://selftest"); // Encode/send/decode and verify each message type self = zre_msg_new (ZRE_MSG_HELLO); zre_msg_set_sequence (self, 123); zre_msg_set_ipaddress (self, "Life is short but Now lasts for ever"); zre_msg_set_mailbox (self, 123); zre_msg_groups_append (self, "Name: %s", "Brutus"); zre_msg_groups_append (self, "Age: %d", 43); zre_msg_set_status (self, 123); zre_msg_headers_insert (self, "Name", "Brutus"); zre_msg_headers_insert (self, "Age", "%d", 43); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_ipaddress (self), "Life is short but Now lasts for ever")); assert (zre_msg_mailbox (self) == 123); assert (zre_msg_groups_size (self) == 2); assert (streq (zre_msg_groups_first (self), "Name: Brutus")); assert (streq (zre_msg_groups_next (self), "Age: 43")); assert (zre_msg_status (self) == 123); assert (zre_msg_headers_size (self) == 2); assert (streq (zre_msg_headers_string (self, "Name", "?"), "Brutus")); assert (zre_msg_headers_number (self, "Age", 0) == 43); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_sequence (self, 123); zre_msg_set_content (self, zframe_new ("Captcha Diem", 12)); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (zframe_streq (zre_msg_content (self), "Captcha Diem")); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_content (self, zframe_new ("Captcha Diem", 12)); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zframe_streq (zre_msg_content (self), "Captcha Diem")); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_PING); zre_msg_set_sequence (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_PING_OK); zre_msg_set_sequence (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); zctx_destroy (&ctx); // @end printf ("OK\n"); return 0; }