Пример #1
0
int
zloop_poller (zloop_t *self, zmq_pollitem_t *item, zloop_fn handler, void *arg)
{
    assert (self);

    if (item->socket
    &&  streq (zsys_sockname (zsock_type (item->socket)), "UNKNOWN"))
        return -1;

    s_poller_t *poller = s_poller_new (item, handler, arg);
    if (poller) {
        poller->list_handle = zlistx_add_end (self->pollers, poller);
        if (!poller->list_handle) {
            s_poller_destroy (&poller);
            return -1;
        }
        self->need_rebuild = true;
        if (self->verbose)
            zsys_debug ("zloop: register %s poller (%p, %d)",
                        item->socket ? zsys_sockname (zsock_type (item->socket)) : "FD",
                        item->socket, item->fd);
        return 0;
    }
    else
        return -1;
}
Пример #2
0
int
zloop_timer (zloop_t *self, size_t delay, size_t times, zloop_timer_fn handler, void *arg)
{
    assert (self);
    //  Catch excessive use of timers
    if (self->max_timers && zlistx_size (self->timers) == self->max_timers) {
        zsys_error ("zloop: timer limit reached (max=%d)", self->max_timers);
        return -1;
    }
    int timer_id = s_next_timer_id (self);
    s_timer_t *timer = s_timer_new (timer_id, delay, times, handler, arg);
    if (timer) {
        timer->list_handle = zlistx_add_end (self->timers, timer);
        if (!timer->list_handle) {
            s_timer_destroy (&timer);
            return -1;
        }
        if (self->verbose)
            zsys_debug ("zloop: register timer id=%d delay=%d times=%d",
                        timer_id, (int) delay, (int) times);
        return timer_id;
    }
    else
        return -1;
}
Пример #3
0
static void
server_connect (server_t *self, const char *endpoint)
{
    zsock_t *remote = zsock_new (ZMQ_DEALER);
    assert (remote);          //  No recovery if exhausted

    //  Never block on sending; we use an infinite HWM and buffer as many
    //  messages as needed in outgoing pipes. Note that the maximum number
    //  is the overall tuple set size.
    zsock_set_unbounded (remote);
    if (zsock_connect (remote, "%s", endpoint)) {
        zsys_warning ("bad zgossip endpoint '%s'", endpoint);
        zsock_destroy (&remote);
        return;
    }
    //  Send HELLO and then PUBLISH for each tuple we have
    zgossip_msg_t *gossip = zgossip_msg_new ();
    zgossip_msg_set_id (gossip, ZGOSSIP_MSG_HELLO);
    zgossip_msg_send (gossip, remote);
    
    tuple_t *tuple = (tuple_t *) zhashx_first (self->tuples);
    while (tuple) {
        zgossip_msg_set_id (gossip, ZGOSSIP_MSG_PUBLISH);
        zgossip_msg_set_key (gossip, tuple->key);
        zgossip_msg_set_value (gossip, tuple->value);
        zgossip_msg_send (gossip, remote);
        tuple = (tuple_t *) zhashx_next (self->tuples);
    }
    //  Now monitor this remote for incoming messages
    zgossip_msg_destroy (&gossip);
    engine_handle_socket (self, remote, remote_handler);
    zlistx_add_end (self->remotes, remote);
}
Пример #4
0
static void
prepare_xrap_offer_command (client_t *self)
{
    zlistx_add_end (self->replays,
        s_replay_new ("XRAP OFFER", self->args->method, self->args->route));
    xrap_traffic_set_method (self->message, self->args->method);
    xrap_traffic_set_route (self->message, self->args->route);
}
Пример #5
0
static void
store_service_offer (client_t *self)
{
    service_t *service = s_service_require (self, mlm_proto_address (self->message));
    assert (service);
    offer_t *offer = s_offer_new (self, mlm_proto_pattern (self->message));
    assert (offer);
    zlistx_add_end (service->offers, offer);
}
Пример #6
0
Файл: zloop.c Проект: skaes/czmq
void *
zloop_ticket (zloop_t *self, zloop_timer_fn handler, void *arg)
{
    assert (self);
    assert (self->ticket_delay > 0);
    s_ticket_t *ticket = s_ticket_new (self->ticket_delay, handler, arg);
    if (ticket) {
        ticket->list_handle = zlistx_add_end (self->tickets, ticket);
        assert (ticket->list_handle);
    }
    return ticket;
}
Пример #7
0
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
}
Пример #8
0
static void
store_stream_reader (client_t *self)
{
    stream_t *stream = s_stream_require (self, mlm_proto_stream (self->message));
    if (stream) {
        zlistx_add_end (self->readers, stream);
        zsock_send (stream->actor, "sps", "COMPILE", self, mlm_proto_pattern (self->message));
        mlm_proto_set_status_code (self->message, MLM_PROTO_SUCCESS);
    }
    else {
        engine_set_exception (self, exception_event);
        zsys_warning ("reader trying to talk to multiple streams");
    }
}
Пример #9
0
static void
s_stream_engine_compile (stream_engine_t *self, void *client, const char *pattern)
{
    selector_t *selector = (selector_t *) zlistx_first (self->selectors);
    while (selector) {
        if (streq (selector->pattern, pattern)) {
            void *compare = zlistx_first (selector->clients);
            while (compare) {
                if (compare == client)
                    break;      //  Duplicate client, ignore
               compare = zlistx_next (selector->clients);
            }
            //  Add client, if it's new
            if (!compare)
                zlistx_add_end (selector->clients, client);
            break;
        }
        selector = (selector_t *) zlistx_next (self->selectors);
    }
    //  Add selector, if it's new
    if (!selector)
        zlistx_add_end (self->selectors, s_selector_new (client, pattern));
}
Пример #10
0
server_connect (server_t *self, const char *endpoint)
#endif
{
    zsock_t *remote = zsock_new (ZMQ_DEALER);
    assert (remote);          //  No recovery if exhausted

#ifdef CZMQ_BUILD_DRAFT_API
    //  DRAFT-API: Security
    if (public_key){
        zcert_t *cert = zcert_new_from_txt (self->public_key, self->secret_key);
        zcert_apply(cert, remote);
        zsock_set_curve_serverkey (remote, public_key);
#ifndef ZMQ_CURVE
        // legacy ZMQ support
        // inline incase the underlying assert is removed
        bool ZMQ_CURVE = false;
#endif
        assert (zsock_mechanism (remote) == ZMQ_CURVE);
        zcert_destroy(&cert);
    }
#endif
    //  Never block on sending; we use an infinite HWM and buffer as many
    //  messages as needed in outgoing pipes. Note that the maximum number
    //  is the overall tuple set size.
    zsock_set_unbounded (remote);

    if (zsock_connect (remote, "%s", endpoint)) {
        zsys_warning ("bad zgossip endpoint '%s'", endpoint);
        zsock_destroy (&remote);
        return;
    }
    //  Send HELLO and then PUBLISH for each tuple we have
    zgossip_msg_t *gossip = zgossip_msg_new ();
    zgossip_msg_set_id (gossip, ZGOSSIP_MSG_HELLO);
    zgossip_msg_send (gossip, remote);

    tuple_t *tuple = (tuple_t *) zhashx_first (self->tuples);
    while (tuple) {
        zgossip_msg_set_id (gossip, ZGOSSIP_MSG_PUBLISH);
        zgossip_msg_set_key (gossip, tuple->key);
        zgossip_msg_set_value (gossip, tuple->value);
        zgossip_msg_send (gossip, remote);
        tuple = (tuple_t *) zhashx_next (self->tuples);
    }
    //  Now monitor this remote for incoming messages
    zgossip_msg_destroy (&gossip);
    engine_handle_socket (self, remote, remote_handler);
    zlistx_add_end (self->remotes, remote);
}
Пример #11
0
static void
write_message_to_service (client_t *self)
{
    mlm_msg_t *msg = mlm_msg_new (
        self->address,
        mlm_proto_address (self->message),
        mlm_proto_subject (self->message),
        mlm_proto_tracker (self->message),
        mlm_proto_timeout (self->message),
        mlm_proto_get_content (self->message));

    service_t *service = s_service_require (self, mlm_proto_address (self->message));
    assert (service);
    zlistx_add_end (service->queue, msg);
    s_service_dispatch (service);
}
Пример #12
0
static selector_t *
s_selector_new (void *client, const char *pattern)
{
    selector_t *self = (selector_t *) zmalloc (sizeof (selector_t));
    if (self) {
        self->rex = zrex_new (pattern);
        if (self->rex)
            self->pattern = strdup (pattern);
        if (self->pattern)
            self->clients = zlistx_new ();
        if (self->clients)
            zlistx_add_end (self->clients, client);
        else
            s_selector_destroy (&self);
    }
    return self;
}
Пример #13
0
Файл: zloop.c Проект: skaes/czmq
int
zloop_reader (zloop_t *self, zsock_t *sock, zloop_reader_fn handler, void *arg)
{
    assert (self);
    assert (sock);

    s_reader_t *reader = s_reader_new (sock, handler, arg);
    if (reader) {
        reader->list_handle = zlistx_add_end (self->readers, reader);
        assert (reader->list_handle);
        self->need_rebuild = true;
        if (self->verbose)
            zsys_debug ("zloop: register %s reader", zsock_type_str (sock));
        return 0;
    }
    else
        return -1;
}
Пример #14
0
Файл: zloop.c Проект: skaes/czmq
int
zloop_timer_end (zloop_t *self, int timer_id)
{
    assert (self);

    if (self->terminated)
        s_timer_remove (self, timer_id);
    else
        //  We cannot touch self->timers because we may be executing that
        //  from inside the poll loop. So, we hold the arg on the zombie
        //  list, and process that list when we're done executing timers.
        //  This hack lets us store an integer timer ID as a pointer
        zlistx_add_end (self->zombies, (byte *) NULL + timer_id);

    if (self->verbose)
        zsys_debug ("zloop: cancel timer id=%d", timer_id);

    return 0;
}
Пример #15
0
static ztrie_node_t *
s_ztrie_node_new (ztrie_node_t *parent, char *token, int token_len, zlistx_t *param_keys, int token_type)
{
    ztrie_node_t *self = (ztrie_node_t *) zmalloc (sizeof (ztrie_node_t));
    assert (self);

    //  Initialize properties
    self->token = s_strndup (token, token_len);
    self->token_type = token_type;
    self->token_len = token_len;
    self->endpoint = false;
    self->parameter_count = 0;
    self->parameter_names = NULL;
    self->parameter_values = NULL;
    if (param_keys && zlistx_size (param_keys) > 0) {
        self->parameter_count = zlistx_size (param_keys);
        self->parameter_names = (char **) malloc (sizeof (char *) * self->parameter_count);
        self->parameter_values = (char **) malloc (sizeof (char *) * self->parameter_count);
        char *key = (char *) zlistx_first (param_keys);
        int index;
        for (index = 0; index < zlistx_size (param_keys); index++) {
            self->parameter_names [index] = key;
            self->parameter_values [index] = NULL;
            key = (char *) zlistx_next (param_keys);
        }
    }
    if (self->token_type == NODE_TYPE_REGEX || self->token_type == NODE_TYPE_PARAM)
        self->regex = zrex_new (self->token);
    self->data = NULL;
    //  Initialize relationships
    self->parent = parent;
    if (self->parent) {
        zlistx_add_end (self->parent->children, self);
        //  Sort regexes to the end to avoid conlficts
        zlistx_sort (self->parent->children);
    }
    size_t parent_path_len = self->parent? self->parent->path_len: 0;
    self->path_len = parent_path_len + strlen (self->token) + 1; // +1 path delimiter
    self->children = zlistx_new ();
    zlistx_set_comparator (self->children, s_ztrie_node_compare);

    return self;
}
Пример #16
0
void
zhashx_comment (zhashx_t *self, const char *format, ...)
{
    if (format) {
        if (!self->comments) {
            self->comments = zlistx_new ();
            if (!self->comments)
                return;
            zlistx_set_destructor (self->comments, (czmq_destructor *) zstr_free);
        }
        va_list argptr;
        va_start (argptr, format);
        char *string = zsys_vprintf (format, argptr);
        va_end (argptr);
        if (string)
            zlistx_add_end (self->comments, string);
    }
    else
        zlistx_destroy (&self->comments);
}
Пример #17
0
zlistx_t *
zlistx_dup (zlistx_t *self)
{
    if (!self)
        return NULL;

    zlistx_t *copy = zlistx_new ();
    if (copy) {
        //  Copy item handlers
        copy->destructor = self->destructor;
        copy->duplicator = self->duplicator;
        copy->comparator = self->comparator;

        //  Copy nodes
        node_t *node;
        for (node = self->head->next; node != self->head; node = node->next)
            zlistx_add_end (copy, node->item);
    }
    return copy;
}
Пример #18
0
static int twps_create_ticket_printer(twps_server_t *self, zmsg_t *msg) {
    char *type = zmsg_popstr(msg);
    char *id = zmsg_popstr(msg);
    zstr_free(&id);
    char *path = zmsg_popstr(msg);
    char *model = zmsg_popstr(msg);
    wchar_t *manufacture = (wchar_t *) zmsg_popstr(msg);
    wchar_t *product = (wchar_t *) zmsg_popstr(msg);
    zactor_t *printer = NULL;
    if (streq(type, "HID")) {
        printer = zactor_new(ticket_hid_printer, path);
    }
#ifdef __WIN32__
    else if (streq(type, "SERIAL")) {
        printer = zactor_new(ticket_serial_printer, path);
    }
#endif
    if (printer != NULL) {
        if (self->verbose) {
            zstr_send(printer, "VERBOSE");
        }
        if (self->diagnostic)
            zstr_sendx(printer, "SETDIAGNOSTIC", NULL);
        zstr_sendx(printer, "START", TICKET_STORE_REP_ENDPOINT, NULL);
        zsock_wait(printer);
        zstr_sendx(printer, "SETPRINTERSTORE", PRINTER_STORE_REP_ENDPOINT, PRINTER_STORE_PUB_ENDPOINT, NULL);
        zsock_wait(printer);
        zsys_info("twps server: started ticket printer %s manufacturer|product|model %ls|%ls|%s", type, manufacture,
                  product, model);
        zlistx_add_end(self->ticket_printers, printer);
    } else {
        zsys_warning("twps server: printer not added %s, %s", type, path);
        zmsg_print(msg);
    }
    zstr_free(&type);
    zstr_free(&path);
    zstr_free(&model);
    zstr_free((char **) &manufacture);
    zstr_free((char **) &product);
    return 0;
}
Пример #19
0
zlistx_t *zhashx_values(zhashx_t *self) {
    assert(self);
    zlistx_t *values = zlistx_new ();
    if (!values)
        return NULL;

    zlistx_set_destructor (values, self->destructor);
    zlistx_set_duplicator (values, self->duplicator);

    uint index;
    size_t limit = primes [self->prime_index];
    for (index = 0; index < limit; index++) {
        item_t *item = self->items [index];
        while (item) {
            if (zlistx_add_end (values, (void *) item->value) == NULL) {
                zlistx_destroy (&values);
                return NULL;
            }
            item = item->next;
        }
     }

    return values;
}
Пример #20
0
static ztrie_node_t *
s_ztrie_parse_path (ztrie_t *self, const char *path, int mode)
{
    int state = 0;
    char *needle, *beginToken = NULL, *beginRegex = NULL;
    ztrie_node_t *parent = self->root;
    if (zlistx_size (self->params) > 0)
        zlistx_purge (self->params);

    int len = strlen (path);
    needle = (char *) path;
    char *needle_stop = needle + len;
    //  Ignore trailing delimiter
    if (needle[len-1] == self->delimiter)
        needle_stop -= 1;
    while (needle < needle_stop + 1) {
        //  It is valid not to have an delimiter at the end of the path
        if (*needle == self->delimiter || needle == needle_stop) {
            //  Token starts with delimiter ignore everything that comes before
            if (state == 0) {
                beginToken = needle + 1;
                state++;
                if (mode == MODE_INSERT || mode == MODE_LOOKUP)
                    // Increment so regexes are parsed which is only relevant
                    // during INSERT or LOOKUP. Using different states gives a small
                    // performance boost for matching.
                    state++;
            }
            //  Token ends with delimiter.
            else
            if (state < 3) {
                int matchType = zlistx_size (self->params) > 0? NODE_TYPE_PARAM:
                                    beginRegex? NODE_TYPE_REGEX: NODE_TYPE_STRING;
                char *matchToken = beginRegex? beginRegex: beginToken;
                int matchTokenLen = needle - matchToken - (beginRegex? 1: 0);
                //  Illegal token
                if (matchTokenLen == 0)
                    return NULL;
                ztrie_node_t *match = NULL;
                //  Asterisk nodes are only allowed at the end of a route
                if (needle == needle_stop && *matchToken == '*') {
                    if (zlistx_size (parent->children) == 0) {
                        matchType = NODE_TYPE_ASTERISK;
                        matchToken = needle - 1;
                        matchTokenLen = 1;
                    }
                    //  Asterisk must be a leaf in the tree
                    else
                        return NULL;
                }
                else {
                    matchType = zlistx_size (self->params) > 0? NODE_TYPE_PARAM:
                                        beginRegex? NODE_TYPE_REGEX: NODE_TYPE_STRING;
                    matchToken = beginRegex? beginRegex: beginToken;
                    matchTokenLen = needle - matchToken - (beginRegex? 1: 0);
                }

                //  In insert and lookup mode only do a string comparison
                if (mode == MODE_INSERT || mode == MODE_LOOKUP)
                    match = s_ztrie_compare_token (parent, matchToken, matchTokenLen);
                else
                //  Otherwise evaluate regexes
                if (mode == MODE_MATCH)
                    match = s_ztrie_matches_token (parent, matchToken, matchTokenLen);

                //  Mismatch behavior depends on mode
                if (!match) {
                    //  Append to common prefix
                    if (mode == MODE_INSERT) {
                        //  It's not allowed to append on asterisk
                        if (parent->token_type == NODE_TYPE_ASTERISK ||
                                (zlistx_size (parent->children) == 1 &&
                                ((ztrie_node_t *) (zlistx_first (parent->children)))->token_type == NODE_TYPE_ASTERISK))
                            return NULL;
                        parent = s_ztrie_node_new (parent, matchToken, matchTokenLen, self->params, matchType);
                    }
                    else
                    //  No match for path found
                    if (mode == MODE_MATCH || mode == MODE_LOOKUP)
                        return NULL;
                }
                //  If a match has been found it becomes the parent for next path token
                else {
                    parent = match;
                    //  In case a asterisk match has been made skip the rest of the route
                    if (parent->token_type == NODE_TYPE_ASTERISK)
                        break;
                }
                //  Cleanup for next token
                beginRegex = NULL;
                if (zlistx_size (self->params) > 0)
                    zlistx_purge (self->params);
                //  Token end equals token begin
                beginToken = needle + 1;
            }
        }
        else
        //  regex starts with '{'
        if (state == 2 && *needle == '{') {
            beginRegex = needle + 1;
            state++;
        }
        else
        //  in the middle of the regex. Found a named regex.
        if (state == 3 && (*needle == ':')) {
            zlistx_add_end (self->params, s_strndup (beginRegex, needle - beginRegex));
            beginRegex = needle + 1;

        }
        else
        // regex ends with {
        if (state == 3 && *needle == '}') {
            state--;
        }
        needle++;
    }

    //  In matching mode the discovered node must be an endpoint
    if (parent && mode == MODE_MATCH && !parent->endpoint)
        return NULL;

    return parent;
}
Пример #21
0
void
mlm_server_test (bool verbose)
{
    printf (" * mlm_server: ");
    if (verbose)
        printf ("\n");

    //  @selftest
    zactor_t *server = zactor_new (mlm_server, "mlm_server_test");
    if (verbose)
        zstr_send (server, "VERBOSE");
    zstr_sendx (server, "BIND", "tcp://127.0.0.1:*", NULL);
    zstr_sendx (server, "PORT", NULL);
    char *command, *port;
    int rc = zstr_recvx (server, &command, &port, NULL);
    assert (rc == 2);
    assert (streq (command, "PORT"));
    assert (strlen (port) > 0 && strlen (port) < 6);
    assert (!streq (port, "-1"));

    zsock_t *reader = zsock_new (ZMQ_DEALER);
    assert (reader);
    zsock_connect (reader, "tcp://127.0.0.1:%s", port);
    zsock_set_rcvtimeo (reader, 500);

    mlm_proto_t *proto = mlm_proto_new ();

    //  Server insists that connection starts properly
    mlm_proto_set_id (proto, MLM_PROTO_STREAM_WRITE);
    mlm_proto_send (proto, reader);
    zclock_sleep (500); //  to calm things down && make memcheck pass. Thanks @malanka
    mlm_proto_recv (proto, reader);
    zclock_sleep (500); //  detto as above
    assert (mlm_proto_id (proto) == MLM_PROTO_ERROR);
    assert (mlm_proto_status_code (proto) == MLM_PROTO_COMMAND_INVALID);

    //  Now do a stream publish-subscribe test
    zsock_t *writer = zsock_new (ZMQ_DEALER);
    assert (writer);
    zsock_connect (writer, "tcp://127.0.0.1:%s", port);
    zsock_set_rcvtimeo (reader, 500);

    //  Open connections from both reader and writer
    mlm_proto_set_id (proto, MLM_PROTO_CONNECTION_OPEN);
    mlm_proto_send (proto, reader);
    mlm_proto_recv (proto, reader);
    assert (mlm_proto_id (proto) == MLM_PROTO_OK);

    mlm_proto_set_id (proto, MLM_PROTO_CONNECTION_OPEN);
    mlm_proto_send (proto, writer);
    mlm_proto_recv (proto, writer);
    assert (mlm_proto_id (proto) == MLM_PROTO_OK);

    //  Prepare to write and read a "weather" stream
    mlm_proto_set_id (proto, MLM_PROTO_STREAM_WRITE);
    mlm_proto_set_stream (proto, "weather");
    mlm_proto_send (proto, writer);
    mlm_proto_recv (proto, writer);
    assert (mlm_proto_id (proto) == MLM_PROTO_OK);

    mlm_proto_set_id (proto, MLM_PROTO_STREAM_READ);
    mlm_proto_set_pattern (proto, "temp.*");
    mlm_proto_send (proto, reader);
    mlm_proto_recv (proto, reader);
    assert (mlm_proto_id (proto) == MLM_PROTO_OK);

    //  Now send some weather data, with null contents
    mlm_proto_set_id (proto, MLM_PROTO_STREAM_SEND);
    mlm_proto_set_subject (proto, "temp.moscow");
    mlm_proto_send (proto, writer);
    mlm_proto_set_subject (proto, "rain.moscow");
    mlm_proto_send (proto, writer);
    mlm_proto_set_subject (proto, "temp.chicago");
    mlm_proto_send (proto, writer);
    mlm_proto_set_subject (proto, "rain.chicago");
    mlm_proto_send (proto, writer);
    mlm_proto_set_subject (proto, "temp.london");
    mlm_proto_send (proto, writer);
    mlm_proto_set_subject (proto, "rain.london");
    mlm_proto_send (proto, writer);

    //  We should receive exactly three deliveries, in order
    mlm_proto_recv (proto, reader);
    assert (mlm_proto_id (proto) == MLM_PROTO_STREAM_DELIVER);
    assert (streq (mlm_proto_subject (proto), "temp.moscow"));

    mlm_proto_recv (proto, reader);
    assert (mlm_proto_id (proto) == MLM_PROTO_STREAM_DELIVER);
    assert (streq (mlm_proto_subject (proto), "temp.chicago"));

    mlm_proto_recv (proto, reader);
    assert (mlm_proto_id (proto) == MLM_PROTO_STREAM_DELIVER);
    assert (streq (mlm_proto_subject (proto), "temp.london"));

    mlm_proto_destroy (&proto);

    //  Finished, we can clean up
    zsock_destroy (&writer);
    zsock_destroy (&reader);
    zactor_destroy (&server);
    zstr_free (&port);
    zstr_free (&command);

    // Test Case:
    //      CLIENTLIST command
    {
        const char *endpoint = "inproc://mlm_server_clientlist_test";
        zactor_t *server = zactor_new (mlm_server, "mlm_server_clientlist_test");
        if (verbose)
            zstr_send (server, "VERBOSE");
        zstr_sendx (server, "BIND", endpoint, NULL);

        mlm_client_t *client_1 = mlm_client_new ();
        int rv = mlm_client_connect (client_1, endpoint, 1000, "Karol");
        assert (rv >= 0);

        mlm_client_t *client_2 = mlm_client_new ();
        rv = mlm_client_connect (client_2, endpoint, 1000, "Tomas");
        assert (rv >= 0);

        mlm_client_t *client_3 = mlm_client_new ();
        rv = mlm_client_connect (client_3, endpoint, 1000, "Alenka");
        assert (rv >= 0);

        zclock_sleep (500);

        zstr_sendx (server, "CLIENTLIST", NULL);

        zmsg_t *message = zmsg_recv (server);
        assert (message);
        assert (zmsg_size (message) == 4);

        char *pop = zmsg_popstr (message);
        assert (streq (pop, "CLIENTLIST"));
        zstr_free (&pop);

        zlistx_t *expected_names = zlistx_new ();
        assert (expected_names);
        zlistx_set_destructor (expected_names, (czmq_destructor *) zstr_free);
        zlistx_set_duplicator (expected_names, (czmq_duplicator *) strdup);
        zlistx_set_comparator (expected_names, (czmq_comparator *) strcmp);

        zlistx_add_end (expected_names, (void *) "Karol");
        zlistx_add_end (expected_names, (void *) "Tomas");
        zlistx_add_end (expected_names, (void *) "Alenka");

        pop = zmsg_popstr (message);
        assert (pop);
        void *handle = zlistx_find (expected_names, pop);
        assert (handle);
        rv = zlistx_delete (expected_names, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_names, pop);
        assert (handle);
        rv = zlistx_delete (expected_names, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_names, pop);
        assert (handle);
        rv = zlistx_delete (expected_names, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop == NULL);
        assert (zlistx_size (expected_names) == 0);


        zmsg_destroy (&message);

        // remove a client Karol
        mlm_client_destroy (&client_1);

        zlistx_add_end (expected_names, (void *) "Tomas");
        zlistx_add_end (expected_names, (void *) "Alenka");

        zstr_sendx (server, "CLIENTLIST", NULL);
        zclock_sleep (100);

        message = zmsg_recv (server);
        assert (message);
        assert (zmsg_size (message) == 3);

        pop = zmsg_popstr (message);
        assert (streq (pop, "CLIENTLIST"));
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_names, pop);
        assert (handle);
        rv = zlistx_delete (expected_names, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_names, pop);
        assert (handle);
        rv = zlistx_delete (expected_names, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop == NULL);
        assert (zlistx_size (expected_names) == 0);

        zlistx_destroy (&expected_names);
        zmsg_destroy (&message);

        mlm_client_destroy (&client_2);
        mlm_client_destroy (&client_3);
        zactor_destroy (&server);
    }

    // Test Case:
    //      STREAMLIST command
    {
        const char *endpoint = "inproc://mlm_server_streamlist_test";
        zactor_t *server = zactor_new (mlm_server, "mlm_server_streamlist_test");
        if (verbose)
            zstr_send (server, "VERBOSE");
        zstr_sendx (server, "BIND", endpoint, NULL);

        mlm_client_t *client_1 = mlm_client_new ();
        int rv = mlm_client_connect (client_1, endpoint, 1000, "Karol");
        assert (rv != -1);
        rv = mlm_client_set_producer (client_1, "STREAM_1");
        assert (rv != -1);

        mlm_client_t *client_2 = mlm_client_new ();
        rv = mlm_client_connect (client_2, endpoint, 1000, "Tomas");
        assert (rv != -1);
        rv = mlm_client_set_producer (client_2, "STREAM_2");
        assert (rv != -1);

        mlm_client_t *client_3 = mlm_client_new ();
        rv = mlm_client_connect (client_3, endpoint, 1000, "Alenka");
        assert (rv != -1);
        rv = mlm_client_set_consumer (client_3, "STREAM_2", ".*");
        assert (rv != -1);

        zclock_sleep (100);

        zlistx_t *expected_streams = zlistx_new ();
        assert (expected_streams);
        zlistx_set_destructor (expected_streams, (czmq_destructor *) zstr_free);
        zlistx_set_duplicator (expected_streams, (czmq_duplicator *) strdup);
        zlistx_set_comparator (expected_streams, (czmq_comparator *) strcmp);

        zlistx_add_end (expected_streams, (void *) "STREAM_1");
        zlistx_add_end (expected_streams, (void *) "STREAM_2");

        zstr_sendx (server, "STREAMLIST", NULL);

        zmsg_t *message = zmsg_recv (server);
        assert (message);
        assert (zmsg_size (message) == 3);

        char *pop = zmsg_popstr (message);
        assert (streq (pop, "STREAMLIST"));
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        void *handle = zlistx_find (expected_streams, pop);
        assert (handle);
        rv = zlistx_delete (expected_streams, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_streams, pop);
        assert (handle);
        rv = zlistx_delete (expected_streams, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop == NULL);
        assert (zlistx_size (expected_streams) == 0);

        zmsg_destroy (&message);

        //  NOTE: Currently when producer disconnects, malamute does not destroy the stream
        //  Therefore it doesn't make sense to test removal of streams, but addition
        mlm_client_t *client_4 = mlm_client_new ();
        rv = mlm_client_connect (client_4, endpoint, 1000, "Michal");
        assert (rv >= 0);
        rv = mlm_client_set_producer (client_4, "New stream");
        assert (rv >= 0);

        zlistx_add_end (expected_streams, (void *) "STREAM_1");
        zlistx_add_end (expected_streams, (void *) "STREAM_2");
        zlistx_add_end (expected_streams, (void *) "New stream");
        zclock_sleep (100);

        zstr_sendx (server, "STREAMLIST", NULL);
        zclock_sleep (100);

        message = zmsg_recv (server);
        assert (message);
        assert (zmsg_size (message) == 4);

        pop = zmsg_popstr (message);
        assert (streq (pop, "STREAMLIST"));
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_streams, pop);
        assert (handle);
        rv = zlistx_delete (expected_streams, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_streams, pop);
        assert (handle);
        rv = zlistx_delete (expected_streams, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop);
        handle = zlistx_find (expected_streams, pop);
        assert (handle);
        rv = zlistx_delete (expected_streams, handle);
        assert (rv == 0);
        zstr_free (&pop);

        pop = zmsg_popstr (message);
        assert (pop == NULL);
        assert (zlistx_size (expected_streams) == 0);

        zlistx_destroy (&expected_streams);
        zmsg_destroy (&message);

        mlm_client_destroy (&client_1);
        mlm_client_destroy (&client_2);
        mlm_client_destroy (&client_3);
        mlm_client_destroy (&client_4);
        zactor_destroy (&server);
    }

    // Regression Test Case:
    //      Segfault from deregistering zombie connection
    {
        const char *endpoint = "inproc://mlm_server_deregister_zombie_connection_test";
        zactor_t *server = zactor_new (mlm_server, "mlm_server_deregister_zombie_connection_test");
        if (verbose)
            zstr_send (server, "VERBOSE");
        zstr_sendx (server, "BIND", endpoint, NULL);
        zstr_sendx (server, "SET", "server/timeout", "3000", NULL); // 3 second client timeout

        zsock_t *reader = zsock_new (ZMQ_DEALER);
        assert (reader);
        zsock_connect (reader, "inproc://mlm_server_deregister_zombie_connection_test");
        zsock_set_rcvtimeo (reader, 500);

        mlm_proto_t *proto = mlm_proto_new ();

        // If the malamute server is restarted and clients have queued
        // up ping messages, the'll be sent before any
        // CONNECTION_OPEN.  The server eventually tries to deregister
        // this and (previously) would derefence a null pointer for
        // the client address.
        mlm_proto_set_id (proto, MLM_PROTO_CONNECTION_PING);
        mlm_proto_send (proto, reader);

        printf("Regression test for segfault due to leftover client messages after restart...\n");
        // Give the server more than 3 seconds to time out the client...
        zclock_sleep (3100);
        printf("passed\n");

        mlm_proto_destroy (&proto);
        zsock_destroy (&reader);
        zactor_destroy (&server);
    }

    {
        const char *endpoint = "inproc://mlm_server_disconnect_pending_stream_traffic";
        zactor_t *server = zactor_new (mlm_server, "mlm_server_disconnect_pending_stream_traffic");
        if (verbose) {
            zstr_send (server, "VERBOSE");
            printf("Regression test for use-after-free with pending stream traffic after disconnect\n");
        }
        zstr_sendx (server, "BIND", endpoint, NULL);

        mlm_client_t *producer = mlm_client_new ();
        assert (mlm_client_connect (producer, endpoint, 1000, "producer") >= 0);
        assert (mlm_client_set_producer (producer, "STREAM_TEST") >= 0);

        zstr_sendx (server, "SLOW_TEST_MODE", NULL);

        mlm_client_t *consumer = mlm_client_new ();
        assert (mlm_client_connect (consumer, endpoint, 1000, "consumer") >= 0);
        assert (mlm_client_set_consumer (consumer, "STREAM_TEST", ".*") >= 0);

        zmsg_t *msg = zmsg_new ();
        zmsg_addstr (msg, "world");
        assert (mlm_client_send (producer, "hello", &msg) >= 0);

        mlm_client_destroy (&consumer);

        zclock_sleep (2000);

        mlm_client_destroy (&producer);
        zactor_destroy (&server);
    }

    //  @end
    printf ("OK\n");
}
Пример #22
0
///
//  Add an item to the tail of the list. Calls the item duplicator, if any,
//  on the item. Resets cursor to list head. Returns an item handle on     
//  success, NULL if memory was exhausted.                                 
void * QZlistx::addEnd (void *item)
{
    void * rv = zlistx_add_end (self, item);
    return rv;
}
Пример #23
0
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
    bool event = false;
    zlistx_t *headers = zlistx_new ();
    zlistx_add_end (headers, "Host: zeromq.org");
    zhttp_client_get (self, url, headers, -1, test_handler, &event);
    zlistx_destroy (&headers);

    //  Receive request on the server
    zchunk_t *routing_id = recv_http_request (server);

    //  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);
    zchunk_destroy (&routing_id);

    //  Receive the response on the http client
    int rc = zhttp_client_wait (self, -1);
    assert (rc == 0);
    zhttp_client_execute (self);
    assert (event);

    // Send a POST request
    event = false;
    zchunk_t *body = zchunk_new ("World", 5);
    zhttp_client_post (self, url, NULL, body, -1, test_handler, &event);

    //  Receive request on the server
    routing_id = recv_http_request (server);

    //  Send the response
    zsock_send (server, "cs", routing_id, response);
    zchunk_destroy (&routing_id);

    //  Receive the response on the http client
    rc = zhttp_client_wait (self, -1);
    assert (rc == 0);
    zhttp_client_execute (self);
    assert (event);

    //  Timeout check
    event = false;
    zhttp_client_get (self, url, NULL, 1000, test_handler, &event);
    rc = zhttp_client_wait (self, 1200);
    assert (rc == 0);
    zhttp_client_execute (self);
    assert (event);

    //  Sending another request, without being answer
    //  Checking the client ability to stop while request are inprogres
    zhttp_client_get (self, url, NULL, -1, test_handler, NULL);

    zchunk_destroy (&body);
    zhttp_client_destroy (&self);
    zsock_destroy (&server);

    //  @end
    printf ("OK\n");
#endif
}
Пример #24
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 ();
}
Пример #25
0
void
zlistx_test (bool verbose)
{
    printf (" * zlistx: ");

    //  @selftest
    zlistx_t *list = zlistx_new ();
    assert (list);
    assert (zlistx_size (list) == 0);

    //  Test operations on an empty list
    assert (zlistx_first (list) == NULL);
    assert (zlistx_last (list) == NULL);
    assert (zlistx_next (list) == NULL);
    assert (zlistx_prev (list) == NULL);
    assert (zlistx_find (list, "hello") == NULL);
    assert (zlistx_delete (list, NULL) == -1);
    assert (zlistx_detach (list, NULL) == NULL);
    assert (zlistx_delete (list, NULL) == -1);
    assert (zlistx_detach (list, NULL) == NULL);
    zlistx_purge (list);
    zlistx_sort (list);

    //  Use item handlers
    zlistx_set_destructor (list, (zlistx_destructor_fn *) zstr_free);
    zlistx_set_duplicator (list, (zlistx_duplicator_fn *) strdup);
    zlistx_set_comparator (list, (zlistx_comparator_fn *) strcmp);

    //  Try simple insert/sort/delete/next
    assert (zlistx_next (list) == NULL);
    zlistx_add_end (list, "world");
    assert (streq ((char *) zlistx_next (list), "world"));
    zlistx_add_end (list, "hello");
    assert (streq ((char *) zlistx_prev (list), "hello"));
    zlistx_sort (list);
    assert (zlistx_size (list) == 2);
    void *handle = zlistx_find (list, "hello");
    char *item1 = (char *) zlistx_item (list);
    char *item2 = (char *) zlistx_handle_item (handle);
    assert (item1 == item2);
    assert (streq (item1, "hello"));
    zlistx_delete (list, handle);
    assert (zlistx_size (list) == 1);
    char *string = (char *) zlistx_detach (list, NULL);
    assert (streq (string, "world"));
    free (string);
    assert (zlistx_size (list) == 0);

    //  Check next/back work
    //  Now populate the list with items
    zlistx_add_start (list, "five");
    zlistx_add_end   (list, "six");
    zlistx_add_start (list, "four");
    zlistx_add_end   (list, "seven");
    zlistx_add_start (list, "three");
    zlistx_add_end   (list, "eight");
    zlistx_add_start (list, "two");
    zlistx_add_end   (list, "nine");
    zlistx_add_start (list, "one");
    zlistx_add_end   (list, "ten");

    //  Test our navigation skills
    assert (zlistx_size (list) == 10);
    assert (streq ((char *) zlistx_last (list), "ten"));
    assert (streq ((char *) zlistx_prev (list), "nine"));
    assert (streq ((char *) zlistx_prev (list), "eight"));
    assert (streq ((char *) zlistx_prev (list), "seven"));
    assert (streq ((char *) zlistx_prev (list), "six"));
    assert (streq ((char *) zlistx_prev (list), "five"));
    assert (streq ((char *) zlistx_first (list), "one"));
    assert (streq ((char *) zlistx_next (list), "two"));
    assert (streq ((char *) zlistx_next (list), "three"));
    assert (streq ((char *) zlistx_next (list), "four"));

    //  Sort by alphabetical order
    zlistx_sort (list);
    assert (streq ((char *) zlistx_first (list), "eight"));
    assert (streq ((char *) zlistx_last (list), "two"));

    //  Moving items around
    handle = zlistx_find (list, "six");
    zlistx_move_start (list, handle);
    assert (streq ((char *) zlistx_first (list), "six"));
    zlistx_move_end (list, handle);
    assert (streq ((char *) zlistx_last (list), "six"));
    zlistx_sort (list);
    assert (streq ((char *) zlistx_last (list), "two"));

    //  Copying a list
    zlistx_t *copy = zlistx_dup (list);
    assert (copy);
    assert (zlistx_size (copy) == 10);
    assert (streq ((char *) zlistx_first (copy), "eight"));
    assert (streq ((char *) zlistx_last (copy), "two"));
    zlistx_destroy (&copy);

    //  Delete items while iterating
    string = (char *) zlistx_first (list);
    assert (streq (string, "eight"));
    string = (char *) zlistx_next (list);
    assert (streq (string, "five"));
    zlistx_delete (list, zlistx_cursor (list));
    string = (char *) zlistx_next (list);
    assert (streq (string, "four"));

    zlistx_purge (list);
    zlistx_destroy (&list);
    //  @end

    printf ("OK\n");
}
Пример #26
0
void
ziflist_reload (ziflist_t *self)
{
    assert (self);
    zlistx_t *list = (zlistx_t *) self;
    zlistx_purge (list);

#if defined (HAVE_GETIFADDRS)
    struct ifaddrs *interfaces;
    if (getifaddrs (&interfaces) == 0) {
        struct ifaddrs *interface = interfaces;
        while (interface) {
            //  On Solaris, loopback interfaces have a NULL in ifa_broadaddr
            if (interface->ifa_broadaddr
            &&  interface->ifa_addr
            &&  interface->ifa_addr->sa_family == AF_INET
            &&  s_valid_flags (interface->ifa_flags)) {
                inaddr_t address = *(inaddr_t *) interface->ifa_addr;
                inaddr_t netmask = *(inaddr_t *) interface->ifa_netmask;
                inaddr_t broadcast = *(inaddr_t *) interface->ifa_broadaddr;

                //  If the returned broadcast address is the same as source
                //  address, build the broadcast address from the source
                //  address and netmask.
                if (address.sin_addr.s_addr == broadcast.sin_addr.s_addr)
                    broadcast.sin_addr.s_addr |= ~(netmask.sin_addr.s_addr);

                interface_t *item =
                    s_interface_new (interface->ifa_name, address, netmask,
                                     broadcast);
                if (item)
                    zlistx_add_end (list, item);
            }
            interface = interface->ifa_next;
        }
    }
    freeifaddrs (interfaces);

#   elif defined (__UNIX__)
    int sock = socket (AF_INET, SOCK_DGRAM, 0);
    if (sock != -1) {
        int num_interfaces = 0;
        struct ifconf ifconfig = { 0 };
        //  First ioctl call gets us length of buffer; second call gets us contents
        if (!ioctl (sock, SIOCGIFCONF, (caddr_t) &ifconfig, sizeof (struct ifconf))) {
            ifconfig.ifc_buf = (char *) zmalloc (ifconfig.ifc_len);
            if (!ioctl (sock, SIOCGIFCONF, (caddr_t) &ifconfig, sizeof (struct ifconf)))
                num_interfaces = ifconfig.ifc_len / sizeof (struct ifreq);
        }
        int index;
        for (index = 0; index < num_interfaces; index++) {
            struct ifreq *ifr = &ifconfig.ifc_req [index];
            //  Check interface flags
            bool is_valid = false;
            if (!ioctl (sock, SIOCGIFFLAGS, (caddr_t) ifr, sizeof (struct ifreq)))
                is_valid = s_valid_flags (ifr->ifr_flags);

            //  Get interface properties
            inaddr_t address = { 0 };
            if (!ioctl (sock, SIOCGIFADDR, (caddr_t) ifr, sizeof (struct ifreq)))
                address = *((inaddr_t *) &ifr->ifr_addr);
            else
                is_valid = false;

            inaddr_t broadcast = { 0 };
            if (!ioctl (sock, SIOCGIFBRDADDR, (caddr_t) ifr, sizeof (struct ifreq)))
                broadcast = *((inaddr_t *) &ifr->ifr_addr);
            else
                is_valid = false;

            inaddr_t netmask = { 0 };
            if (!ioctl (sock, SIOCGIFNETMASK, (caddr_t) ifr, sizeof (struct ifreq)))
                netmask = *((inaddr_t *) &ifr->ifr_addr);
            else
                is_valid = false;

            if (is_valid) {
                interface_t *item = s_interface_new (ifr->ifr_name, address,
                                                     netmask, broadcast);
                if (item)
                    zlistx_add_end (list, item);
            }
        }
        free (ifconfig.ifc_buf);
        close (sock);
    }

#   elif defined (__WINDOWS__)
    ULONG addr_size = 0;
    DWORD rc = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &addr_size);
    assert (rc == ERROR_BUFFER_OVERFLOW);

    PIP_ADAPTER_ADDRESSES pip_addresses = (PIP_ADAPTER_ADDRESSES) zmalloc (addr_size);
    rc = GetAdaptersAddresses (AF_INET,
                               GAA_FLAG_INCLUDE_PREFIX, NULL, pip_addresses, &addr_size);
    assert (rc == NO_ERROR);

    PIP_ADAPTER_ADDRESSES cur_address = pip_addresses;
    while (cur_address) {
        PIP_ADAPTER_UNICAST_ADDRESS pUnicast = cur_address->FirstUnicastAddress;
        PIP_ADAPTER_PREFIX pPrefix = cur_address->FirstPrefix;

        PWCHAR friendlyName = cur_address->FriendlyName;
        size_t asciiSize = wcstombs (0, friendlyName, 0) + 1;
        char *asciiFriendlyName = (char *) zmalloc (asciiSize);
        wcstombs (asciiFriendlyName, friendlyName, asciiSize);

        bool valid = (cur_address->OperStatus == IfOperStatusUp)
                     && (pUnicast && pPrefix)
                     && (pUnicast->Address.lpSockaddr->sa_family == AF_INET)
                     && (pPrefix->PrefixLength <= 32);

        if (valid) {
            inaddr_t address = *(inaddr_t *) pUnicast->Address.lpSockaddr;
            inaddr_t netmask;
            netmask.sin_addr.s_addr = htonl ((0xffffffffU) << (32 - pPrefix->PrefixLength));
            inaddr_t broadcast = address;
            broadcast.sin_addr.s_addr |= ~(netmask.sin_addr.s_addr);
            interface_t *item = s_interface_new (asciiFriendlyName, address,
                                                 netmask, broadcast);
            if (item)
                zlistx_add_end (list, item);
        }
        free (asciiFriendlyName);
        cur_address = cur_address->Next;
    }
    free (pip_addresses);

#   else
#       error "Interface detection TBD on this operating system"
#   endif
}