static int s_self_handle_pipe (self_t *self) { // Get just the command off the pipe char *command = zstr_recv (self->pipe); if (!command) return -1; // Interrupted if (self->verbose) zsys_info ("zbeacon: API command=%s", command); if (streq (command, "VERBOSE")) self->verbose = true; else if (streq (command, "CONFIGURE")) { int port; int rc = zsock_recv (self->pipe, "i", &port); assert (rc == 0); s_self_configure (self, port); } else if (streq (command, "PUBLISH")) { zframe_destroy (&self->transmit); zsock_recv (self->pipe, "fi", &self->transmit, &self->interval); assert (zframe_size (self->transmit) <= UDP_FRAME_MAX); if (self->interval == 0) self->interval = INTERVAL_DFLT; // Start broadcasting immediately self->ping_at = zclock_mono (); } else if (streq (command, "SILENCE")) zframe_destroy (&self->transmit); else if (streq (command, "SUBSCRIBE")) { zframe_destroy (&self->filter); self->filter = zframe_recv (self->pipe); assert (zframe_size (self->filter) <= UDP_FRAME_MAX); } else if (streq (command, "UNSUBSCRIBE")) zframe_destroy (&self->filter); else if (streq (command, "$TERM")) self->terminated = true; else { zsys_error ("zbeacon: - invalid command: %s", command); assert (false); } zstr_free (&command); return 0; }
static void check_for_mailbox_messages (client_t *self) { if (*self->address) { zsock_send (self->server->mailbox, "ss", "QUERY", self->address); // TODO: break into async reply back to server with client // ID number that server can route to correct client, if it // exists... we need some kind of internal async messaging // to cover all different cases // - engine_send_event (client, event, args) // - stream return // - mailbox to client // - service request to client // -> can each client have a DEALER socket? // -> lookup/route on client unique name? // -> server/client path? centralized for process? // -> do we need lookup, or can we use ROUTER sockets? // -> perhaps using ID? // <<general model for internal messaging>> // requirements, route by name, detect lost route? // credit based flow control // can send mlm_msg_t's all over the place zsock_recv (self->server->mailbox, "p", &self->msg); if (self->msg) engine_set_next_event (self, mailbox_message_event); } }
int zhttp_client_execute (zhttp_client_t *self) { #ifdef HAVE_LIBCURL int response_code; zchunk_t *data; void *arg; zhttp_client_fn *handler; int rc; int events = zsock_events (self); while (zsock_has_in (self)) { rc = zsock_recv (self, "icpp", &response_code, &data, &handler, &arg); if (rc < 0) return rc; handler (arg, response_code, data); events = zsock_events (self); } return 0; #else return -1; #endif }
zlist_t * zyre_peers (zyre_t *self) { zlist_t *peers; zstr_send (self->actor, "PEERS"); zsock_recv (self->actor, "p", &peers); return peers; }
zlist_t * zyre_own_groups (zyre_t *self) { zlist_t *groups; zstr_send (self->actor, "OWN GROUPS"); zsock_recv (self->actor, "p", &groups); return groups; }
zlist_t * zyre_peer_groups (zyre_t *self) { zlist_t *groups; zstr_send (self->actor, "PEER GROUPS"); zsock_recv (self->actor, "p", &groups); return groups; }
// -------------------------------------------------------------------------- // Receive the response for one of the requests. Blocks until a response is ready. // Use userp to identify the request. int zhttp_client_recv (zhttp_client_t *self, int *response_code, zchunk_t **data, void **userp) { #ifdef HAVE_LIBCURL return zsock_recv (self, "icp", response_code, data, userp); #else return -1; #endif }
JNIEXPORT jint JNICALL Java_org_zeromq_czmq_Zsock__1_1recv (JNIEnv *env, jclass c, jlong self, jstring picture) { char *picture_ = (char *) (*env)->GetStringUTFChars (env, picture, NULL); jint recv_ = (jint) zsock_recv ((zsock_t *) (intptr_t) self, picture_); (*env)->ReleaseStringUTFChars (env, picture, picture_); return recv_; }
static zchunk_t * recv_http_request(void* server) { zchunk_t *routing_id; char *request; int rc = zsock_recv (server, "cs", &routing_id, &request); assert (rc == 0); while (strlen (request) == 0) { zchunk_destroy (&routing_id); zstr_free (&request); zsock_recv (server, "cs", &routing_id, &request); assert (rc == 0); } zstr_free (&request); return routing_id; }
zlist_t * zyre_peers_by_group (zyre_t *self, const char *group) { zlist_t *peers; zstr_sendm (self->actor, "GROUP PEERS"); zstr_send (self->actor, group); zsock_recv (self->actor, "p", &peers); return peers; }
static void server_configuration (server_t *self, zconfig_t *config) { int dummy; mlm_msgq_cfg_configure (self->service_queue_cfg, config); zsock_send (self->mailbox, "sp", "CONFIGURE", config); // Wait for the mailbox to reconfigure itself so that the zconfig object // is not in use after we return zsock_recv (self->mailbox, "i", &dummy); }
char * zyre_peer_address (zyre_t *self, const char *peer) { assert (self); char *address; zstr_sendm (self->actor, "PEER ENDPOINT"); zstr_send (self->actor, peer); zsock_recv (self->actor, "s", &address); return address; }
void zhttp_client_test (bool verbose) { #if defined(HAVE_LIBCURL) && defined(ZMQ_STREAM) printf (" * zhttp_client: "); zsock_t *server = zsock_new_stream (NULL); int port = zsock_bind (server, "tcp://127.0.0.1:*"); char url[255]; sprintf (url, "http://127.0.0.1:%d", port); // @selftest // Simple create/destroy test zhttp_client_t *self = zhttp_client_new (verbose); assert (self); // Send the get request zlistx_t *headers = zlistx_new (); zlistx_add_end (headers, "Host: zeromq.org"); zhttp_client_get (self, url, headers, NULL); zlistx_destroy (&headers); // Receive request on the server zchunk_t *routing_id; char *request; int rc = zsock_recv (server, "cs", &routing_id, &request); assert (rc == 0); // Send the response char* response = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nHello"; zsock_send (server, "cs", routing_id, response); // Receive the response on the http client int code; zchunk_t *data; zhttp_client_recv (self, &code, &data, NULL); assert (zchunk_streq (data, "Hello")); // Sending another request, without being answer // Checking the client ability to stop while request are inprogres zhttp_client_get (self, url, NULL, NULL); zchunk_destroy (&data); zchunk_destroy (&routing_id); zstr_free (&request); zhttp_client_destroy (&self); zsock_destroy (&server); // @end printf ("OK\n"); #endif }
static int s_stream_engine_handle_command (stream_engine_t *self) { char *method = zstr_recv (self->cmdpipe); if (!method) return -1; // Interrupted; exit zloop if (self->verbose) zsys_debug ("mlm_stream_simple: API command=%s", method); if (streq (method, "VERBOSE")) self->verbose = true; // Start verbose logging else if (streq (method, "$TERM")) self->terminated = true; // Shutdown the engine else if (streq (method, "COMPILE")) { void *client; char *pattern; zsock_recv (self->cmdpipe, "ps", &client, &pattern); s_stream_engine_compile (self, client, pattern); zstr_free (&pattern); } else if (streq (method, "CANCEL")) { void *client; zsock_recv (self->cmdpipe, "p", &client); s_stream_engine_cancel (self, client); } // Cleanup pipe if any argument frames are still waiting to be eaten if (zsock_rcvmore (self->cmdpipe)) { zsys_error ("mlm_stream_simple: trailing API command frames (%s)", method); zmsg_t *more = zmsg_recv (self->cmdpipe); zmsg_print (more); zmsg_destroy (&more); } zstr_free (&method); return self->terminated? -1: 0; }
STATIC mp_uint_t sock_read(mp_obj_t self_in, void *buf, mp_uint_t max_len, int *errcode) { socket_obj_t *socket = self_in; if (socket->ctx == -1) { // already closed *errcode = EBADF; return MP_STREAM_ERROR; } ssize_t recv_len = zsock_recv(socket->ctx, buf, max_len, 0); if (recv_len == -1) { *errcode = errno; return MP_STREAM_ERROR; } return recv_len; }
void zdir_test (bool verbose) { printf (" * zdir: "); // @selftest // need to create a file in the test directory we're watching // in order to ensure the directory exists zfile_t *initfile = zfile_new ("./zdir-test-dir", "initial_file"); assert (initfile); zfile_output (initfile); fprintf (zfile_handle (initfile), "initial file\n"); zfile_close (initfile); zfile_destroy (&initfile); zdir_t *older = zdir_new ("zdir-test-dir", NULL); assert (older); if (verbose) { printf ("\n"); zdir_dump (older, 0); } zdir_t *newer = zdir_new (".", NULL); assert (newer); zlist_t *patches = zdir_diff (older, newer, "/"); assert (patches); while (zlist_size (patches)) { zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (patches); zdir_patch_destroy (&patch); } zlist_destroy (&patches); zdir_destroy (&older); zdir_destroy (&newer); zdir_t *nosuch = zdir_new ("does-not-exist", NULL); assert (nosuch == NULL); // zdir_watch test: zactor_t *watch = zactor_new (zdir_watch, NULL); assert (watch); int synced; if (verbose) { zsock_send (watch, "s", "VERBOSE"); synced = zsock_wait(watch); assert ( synced == 0); } zclock_sleep (1001); // wait for initial file to become 'stable' zsock_send (watch, "si", "TIMEOUT", 100); synced = zsock_wait(watch); assert (synced == 0); zsock_send (watch, "ss", "SUBSCRIBE", "zdir-test-dir"); synced = zsock_wait(watch); assert(synced == 0); zsock_send (watch, "ss", "UNSUBSCRIBE", "zdir-test-dir"); synced = zsock_wait(watch); assert(synced == 0); zsock_send (watch, "ss", "SUBSCRIBE", "zdir-test-dir"); synced = zsock_wait(watch); assert(synced == 0); zfile_t *newfile = zfile_new ("zdir-test-dir", "test_abc"); zfile_output (newfile); fprintf (zfile_handle (newfile), "test file\n"); zfile_close (newfile); zpoller_t *watch_poll = zpoller_new (watch, NULL); // poll for a certain timeout before giving up and failing the test. void* polled = zpoller_wait(watch_poll, 1001); assert (polled == watch); // wait for notification of the file being added char *path; int rc = zsock_recv (watch, "sp", &path, &patches); assert (rc == 0); assert (streq (path, "zdir-test-dir")); freen (path); assert (zlist_size (patches) == 1); zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (patches); assert (streq (zdir_patch_path (patch), "zdir-test-dir")); zfile_t *patch_file = zdir_patch_file (patch); assert (streq (zfile_filename (patch_file, ""), "zdir-test-dir/test_abc")); zdir_patch_destroy (&patch); zlist_destroy (&patches); // remove the file zfile_remove (newfile); zfile_destroy (&newfile); // poll for a certain timeout before giving up and failing the test. polled = zpoller_wait(watch_poll, 1001); assert (polled == watch); // wait for notification of the file being removed rc = zsock_recv (watch, "sp", &path, &patches); assert (rc == 0); assert (streq (path, "zdir-test-dir")); freen (path); assert (zlist_size (patches) == 1); patch = (zdir_patch_t *) zlist_pop (patches); assert (streq (zdir_patch_path (patch), "zdir-test-dir")); patch_file = zdir_patch_file (patch); assert (streq (zfile_filename (patch_file, ""), "zdir-test-dir/test_abc")); zdir_patch_destroy (&patch); zlist_destroy (&patches); zpoller_destroy (&watch_poll); zactor_destroy (&watch); // clean up by removing the test directory. zdir_t *testdir = zdir_new ("zdir-test-dir", NULL); zdir_remove (testdir, true); zdir_destroy (&testdir); #if defined (__WINDOWS__) zsys_shutdown(); #endif // @end printf ("OK\n"); }
int main (int argc, char *argv []) { puts (PRODUCT); puts (COPYRIGHT); puts (NOWARRANTY); int argn = 1; if (argn < argc && streq (argv [argn], "-h")) { puts ("syntax: hydrad [-v] [-z] [ [-t] [-i] [-n HOSTNAME] directory ]"); puts (" -- defaults to .hydra in current directory"); puts (" -v = run Hydra protocol in verbose mode"); puts (" -z = run Zyre discovery in verbose mode"); puts (" -t = create some test posts"); puts (" -i = run over ipc:// without networking"); puts (" -n HOSTNAME = specify a custom hostname for hydrad to use"); exit (0); } bool verbose = false; bool zverbose = false; bool testmode = false; bool localhost = false; bool lookforvalue = false; char *directory = ".hydra"; char *hostname = NULL; while (argn < argc && (*argv [argn] == '-' || lookforvalue)) { if (streq (argv [argn], "-v")) verbose = true; else if (streq (argv [argn], "-z")) zverbose = true; else if (streq (argv [argn], "-t")) testmode = true; else if (streq (argv [argn], "-i")) localhost = true; else if (streq (argv [argn], "-n")) lookforvalue = true; else if (lookforvalue) { hostname = argv [argn]; lookforvalue = false; } else { puts ("Invalid option, run hydrad -h to see options"); exit (0); } argn++; } if (argn < argc) directory = argv [argn]; hydra_t *hydra = hydra_new (directory); if (!hydra) exit (0); if (testmode) { // Provision the Hydra server with some test posts in a tree char *post_id; zactor_t *server = zactor_new (hydra_server, NULL); zsock_send (server, "ssssss", "POST", "This is a string", "", "text/plain", "string", "Hello, World"); zsock_recv (server, "s", &post_id); zsock_send (server, "ssssss", "POST", "This is a disk file", post_id, "text/zpl", "file", "hydra.cfg"); zstr_free (&post_id); zsock_recv (server, "s", &post_id); zsock_send (server, "sssssb", "POST", "This is a blob of data", post_id, "*/*", "chunk", "ABCDEFGHIJ", 10); zstr_free (&post_id); zsock_recv (server, "s", &post_id); zstr_free (&post_id); zactor_destroy (&server); } if (verbose) hydra_set_animate (hydra); if (zverbose) hydra_set_verbose (hydra); if (localhost) hydra_set_local_ipc (hydra); if (hostname) hydra_set_hostname (hydra, hostname); hydra_start (hydra); while (!zsys_interrupted) sleep (1); hydra_destroy (&hydra); return 0; }
static void handler (zsock_t *pipe, void *args) { curl_global_init(CURL_GLOBAL_ALL); CURLM *multi = curl_multi_init (); CURLSH *share = curl_share_init (); curl_share_setopt (share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); curl_share_setopt (share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); curl_share_setopt (share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); long verbose = (*(bool *) args) ? 1L : 0L; long timeout = 30; CURLMcode code; SOCKET pipefd = zsock_fd (pipe); struct curl_waitfd waitfd = {pipefd, CURL_WAIT_POLLIN}; // List to hold pending curl handles, in case we are destroy the client // while request are inprogress zlistx_t *pending_handles = zlistx_new (); zlistx_set_destructor (pending_handles, (zlistx_destructor_fn *) curl_destructor); zsock_signal (pipe, 0); bool terminated = false; while (!terminated) { int events = zsock_events (pipe); if ((events & ZMQ_POLLIN) == 0) { code = curl_multi_wait (multi, &waitfd, 1, 1000, NULL); assert (code == CURLM_OK); } events = zsock_events (pipe); if (events & ZMQ_POLLIN) { char* command = zstr_recv (pipe); if (!command) break; // Interrupted // All actors must handle $TERM in this way if (streq (command, "$TERM")) terminated = true; else if (streq (command, "GET")) { char *url; zlistx_t *headers; void *userp; int rc = zsock_recv (pipe, "slp", &url, &headers, &userp); assert (rc == 0); zchunk_t *data = zchunk_new (NULL, 100); assert (data); struct curl_slist *curl_headers = zlistx_to_slist (headers); CURL *curl = curl_easy_init (); zlistx_add_end (pending_handles, curl); http_request *request = (http_request *) zmalloc (sizeof (http_request)); assert (request); request->userp = userp; request->curl = curl; request->data = data; request->headers = curl_headers; curl_easy_setopt (curl, CURLOPT_SHARE, share); curl_easy_setopt (curl, CURLOPT_TIMEOUT, timeout); curl_easy_setopt (curl, CURLOPT_VERBOSE, verbose); curl_easy_setopt (curl, CURLOPT_HTTPHEADER, curl_headers); curl_easy_setopt (curl, CURLOPT_URL, url); curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt (curl, CURLOPT_WRITEDATA, data); curl_easy_setopt (curl, CURLOPT_PRIVATE, request); code = curl_multi_add_handle (multi, curl); assert (code == CURLM_OK); zlistx_destroy (&headers); zstr_free (&url); } else { puts ("E: invalid message to actor"); assert (false); } zstr_free (&command); } int still_running; code = curl_multi_perform (multi, &still_running); assert (code == CURLM_OK); int msgq = 0; struct CURLMsg *msg = curl_multi_info_read(multi, &msgq); while (msg) { if(msg->msg == CURLMSG_DONE) { CURL *curl = msg->easy_handle; http_request *request; curl_easy_getinfo(curl, CURLINFO_PRIVATE, &request); long response_code_long; curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response_code_long); int response_code = (int)response_code_long; int rc = zsock_send (pipe, "icp", response_code, request->data, request->userp); assert (rc == 0); curl_multi_remove_handle (multi, curl); // Remove curl from the pending handles and delete it void *handle = zlistx_find (pending_handles, curl); assert (handle); rc = zlistx_delete (pending_handles, handle); assert (rc == 0); } msg = curl_multi_info_read(multi, &msgq); } } zlistx_destroy (&pending_handles); curl_share_cleanup (share); curl_multi_cleanup (multi); curl_global_cleanup (); }
/// // Receive a 'picture' message to the socket (or actor). See zsock_send for // the format and meaning of the picture. Returns the picture elements into // a series of pointers as provided by the caller: // // i = int * (stores signed integer) // 4 = uint32_t * (stores 32-bit unsigned integer) // 8 = uint64_t * (stores 64-bit unsigned integer) // s = char ** (allocates new string) // b = byte **, size_t * (2 arguments) (allocates memory) // c = zchunk_t ** (creates zchunk) // f = zframe_t ** (creates zframe) // U = zuuid_t * (creates a zuuid with the data) // h = zhashx_t ** (creates zhashx) // p = void ** (stores pointer) // m = zmsg_t ** (creates a zmsg with the remaing frames) // z = null, asserts empty frame (0 arguments) // u = uint * (stores unsigned integer, deprecated) // // Note that zsock_recv creates the returned objects, and the caller must // destroy them when finished with them. The supplied pointers do not need // to be initialized. Returns 0 if successful, or -1 if it failed to recv // a message, in which case the pointers are not modified. When message // frames are truncated (a short message), sets return values to zero/null. // If an argument pointer is NULL, does not store any value (skips it). // An 'n' picture matches an empty frame; if the message does not match, // the method will return -1. int QmlZsock::recv (const QString &picture) { return zsock_recv (self, picture.toUtf8().data()); };
int main (int argc, char *argv []) { puts (PRODUCT); puts (COPYRIGHT); puts (NOWARRANTY); int argn = 1; bool verbose = false; if (argn < argc && streq (argv [argn], "-h")) { puts ("syntax: hydrad [ directory ]"); puts (" -- defaults to .hydra in current directory"); exit (0); } if (argn < argc && streq (argv [argn], "-v")) { verbose = true; argn++; } // By default, current node runs in .hydra directory; create this if // it's missing (don't create directory passed as argument); char *workdir = ".hydra"; if (argn < argc) workdir = argv [argn++]; else zsys_dir_create (workdir); // ---------------------------------------------------------------------- // This code eventually goes into a reusable hydra actor class // Switch to working directory zsys_info ("hydrad: data store in %s directory", workdir); if (zsys_dir_change (workdir)) { zsys_error ("hydrad: cannot access %s: %s", workdir, strerror (errno)); return 1; } // Check we are the only process currently running here if (zsys_run_as ("hydrad.lock", NULL, NULL)) { zsys_error ("hydrad: cannot start process safely, exiting"); return 1; } // Get node identity from config file, or generate new identity zconfig_t *config = zconfig_load ("hydra.cfg"); if (!config) { // Set defaults for Hydra service config = zconfig_new ("root", NULL); zconfig_put (config, "/server/timeout", "5000"); zconfig_put (config, "/server/background", "0"); zconfig_put (config, "/server/verbose", "0"); } char *identity = zconfig_resolve (config, "/hydra/identity", NULL); if (!identity) { zuuid_t *uuid = zuuid_new (); zconfig_put (config, "/hydra/identity", zuuid_str (uuid)); zconfig_put (config, "/hydra/nickname", "Anonymous"); zconfig_save (config, "hydra.cfg"); zuuid_destroy (&uuid); } // Create store structure, if necessary zsys_dir_create ("content"); zsys_dir_create ("posts"); // Start server and bind to ephemeral TCP port. We can run many // servers on the same box, for testing. zactor_t *server = zactor_new (hydra_server, NULL); if (verbose) zstr_send (server, "VERBOSE"); // Bind Hydra service to ephemeral port and get that port number char *command; int port_nbr; zsock_send (server, "ss", "CONFIGURE", "hydra.cfg"); zsock_send (server, "ss", "BIND", "tcp://*:*"); zsock_send (server, "s", "PORT"); zsock_recv (server, "si", &command, &port_nbr); zsys_info ("hydrad: TCP server started on port=%d", port_nbr); assert (streq (command, "PORT")); free (command); // We're going to use Zyre for discovery and presence, and our own // Hydra protocol for content exchange zyre_t *zyre = zyre_new (NULL); if (verbose) zyre_set_verbose (zyre); char *hostname = zsys_hostname (); char *endpoint = zsys_sprintf ("tcp://%s:%d", hostname, port_nbr); zyre_set_header (zyre, "X-HYDRA", "%s", endpoint); zstr_free (&endpoint); zstr_free (&hostname); if (zyre_start (zyre)) { zsys_info ("hydrad: can't start Zyre discovery service"); zactor_destroy (&server); zyre_destroy (&zyre); return 1; } // When we get a new peer, handle it zpoller_t *poller = zpoller_new (zyre_socket (zyre), NULL); while (!zpoller_terminated (poller)) { void *which = zpoller_wait (poller, -1); if (which == zyre_socket (zyre)) { zyre_event_t *event = zyre_event_new (zyre); if (zyre_event_type (event) == ZYRE_EVENT_ENTER) { zsys_debug ("hydrad: new peer name=%s endpoint=%s", zyre_event_name (event), zyre_event_header (event, "X-HYDRA")); s_handle_peer (zyre_event_header (event, "X-HYDRA"), verbose); } zyre_event_destroy (&event); } else break; } zsys_info ("hydrad: shutting down..."); zpoller_destroy (&poller); // Shutdown all services zactor_destroy (&server); zyre_destroy (&zyre); zconfig_destroy (&config); return 0; }
Z K2(zsockrecv){PC(x); TC(y,-KS); R kj(zsock_recv(VSK(x), ys));}
void zsock_test (bool verbose) { printf (" * zsock: "); // @selftest zsock_t *writer = zsock_new_push ("@tcp://127.0.0.1:5560"); assert (writer); assert (zsock_resolve (writer) != writer); assert (streq (zsock_type_str (writer), "PUSH")); int rc; #if (ZMQ_VERSION >= ZMQ_MAKE_VERSION (3,2,0)) // Check unbind rc = zsock_unbind (writer, "tcp://127.0.0.1:%d", 5560); assert (rc == 0); // In some cases and especially when running under Valgrind, doing // a bind immediately after an unbind causes an EADDRINUSE error. // Even a short sleep allows the OS to release the port for reuse. zclock_sleep (100); // Bind again rc = zsock_bind (writer, "tcp://127.0.0.1:%d", 5560); assert (rc == 5560); assert (streq (zsock_endpoint (writer), "tcp://127.0.0.1:5560")); #endif zsock_t *reader = zsock_new_pull (">tcp://127.0.0.1:5560"); assert (reader); assert (zsock_resolve (reader) != reader); assert (streq (zsock_type_str (reader), "PULL")); zstr_send (writer, "Hello, World"); zmsg_t *msg = zsock_recv (reader); assert (msg); char *string = zmsg_popstr (msg); assert (streq (string, "Hello, World")); free (string); zmsg_destroy (&msg); // Test binding to ephemeral ports, sequential and random int port = zsock_bind (writer, "tcp://127.0.0.1:*"); assert (port >= DYNAMIC_FIRST && port <= DYNAMIC_LAST); port = zsock_bind (writer, "tcp://127.0.0.1:*[50000-]"); assert (port >= 50000 && port <= DYNAMIC_LAST); port = zsock_bind (writer, "tcp://127.0.0.1:*[-50001]"); assert (port >= DYNAMIC_FIRST && port <= 50001); port = zsock_bind (writer, "tcp://127.0.0.1:*[60000-60010]"); assert (port >= 60000 && port <= 60010); port = zsock_bind (writer, "tcp://127.0.0.1:!"); assert (port >= DYNAMIC_FIRST && port <= DYNAMIC_LAST); port = zsock_bind (writer, "tcp://127.0.0.1:![50000-]"); assert (port >= 50000 && port <= DYNAMIC_LAST); port = zsock_bind (writer, "tcp://127.0.0.1:![-50001]"); assert (port >= DYNAMIC_FIRST && port <= 50001); port = zsock_bind (writer, "tcp://127.0.0.1:![60000-60010]"); assert (port >= 60000 && port <= 60010); // Test zsock_endpoint method rc = zsock_bind (writer, "inproc://test.%s", "writer"); assert (rc == 0); assert (streq (zsock_endpoint (writer), "inproc://test.writer")); // Test error state when connecting to an invalid socket type // ('txp://' instead of 'tcp://', typo intentional) rc = zsock_connect (reader, "txp://127.0.0.1:5560"); assert (rc == -1); rc = zsock_signal (writer, 123); assert (rc == 0); rc = zsock_wait (reader); assert (rc == 123); zsock_destroy (&reader); zsock_destroy (&writer); // Test zsock_attach method zsock_t *server = zsock_new (ZMQ_DEALER); rc = zsock_attach (server, "@inproc://myendpoint,tcp://127.0.0.1:5556,inproc://others", true); assert (rc == 0); rc = zsock_attach (server, "", false); assert (rc == 0); rc = zsock_attach (server, NULL, true); assert (rc == 0); rc = zsock_attach (server, ">a,@b, c,, ", false); assert (rc == -1); zsock_destroy (&server); // @end printf ("OK\n"); }