Merge pull request #238 from ianbarber/master

Wildcard support in TCP and IPC addresses
This commit is contained in:
Pieter Hintjens 2012-02-14 16:39:32 -08:00
commit b2e9347372
11 changed files with 112 additions and 8 deletions

View File

@ -33,6 +33,7 @@ Gerard Toonstra <gtoonstra@gmail.com>
Ghislain Putois <ghpu@infonie.fr>
Gonzalo Diethelm <gdiethelm@dcv.cl>
Guido Goldstein <zmq@a-nugget.de>
Ian Barber <ian.barber@gmail.com>
Ilja Golshtein <ilejncs@narod.ru>
Ivo Danihelka <ivo@danihelka.net>
Jacob Rideout <jacob.rideout@returnpath.net>

View File

@ -391,6 +391,17 @@ Option value unit:: N/A (flags)
Default value:: N/A
Applicable socket types:: all
ZMQ_LAST_ENDPOINT: Retrieve the last endpoint set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_LAST_ENDPOINT' option shall retrieve the last endpoint bound for
TCP and IPC transports. The returned value will be a string in the form of
a ZMQ DSN.
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: NULL
Applicable socket types:: all, when binding TCP or IPC transports
RETURN VALUE
------------

View File

@ -221,6 +221,7 @@ ZMQ_EXPORT int zmq_term (zmq_ctx_t context);
#define ZMQ_RCVTIMEO 27
#define ZMQ_SNDTIMEO 28
#define ZMQ_IPV4ONLY 31
#define ZMQ_LAST_ENDPOINT 32
/* Message options */
#define ZMQ_MORE 1

View File

@ -95,8 +95,32 @@ void zmq::ipc_listener_t::in_event ()
send_attach (session, engine, false);
}
int zmq::ipc_listener_t::get_address (std::string *addr_)
{
struct sockaddr_un sun;
int rc;
// Get the details of the IPC socket
socklen_t sl = sizeof(sockaddr_un);
rc = getsockname (s, (sockaddr *)&sun, &sl);
if (rc != 0) {
return rc;
}
// Store the address for retrieval by users using wildcards
*addr_ = std::string("ipc://") + std::string(sun.sun_path);
return 0;
}
int zmq::ipc_listener_t::set_address (const char *addr_)
{
// Allow wildcard file
if(*addr_ == '*') {
addr_ = tempnam(NULL, NULL);
}
// Get rid of the file associated with the UNIX domain socket that
// may have been left behind by the previous run of the application.
::unlink (addr_);
@ -124,7 +148,7 @@ int zmq::ipc_listener_t::set_address (const char *addr_)
rc = listen (s, options.backlog);
if (rc != 0)
return -1;
return 0;
}

View File

@ -48,6 +48,9 @@ namespace zmq
// Set address to listen on.
int set_address (const char *addr_);
// Get the bound address for use with wildcards
int get_address(std::string *addr_);
private:

View File

@ -213,7 +213,6 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
ipv4only = val;
return 0;
}
}
errno = EINVAL;
@ -385,7 +384,16 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
*((int*) optval_) = ipv4only;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_LAST_ENDPOINT:
// don't allow string which cannot contain the entire message
if (*optvallen_ < last_endpoint.size() + 1) {
errno = EINVAL;
return -1;
}
memcpy (optval_, last_endpoint.c_str(), last_endpoint.size()+1);
*optvallen_ = last_endpoint.size()+1;
return 0;
}
errno = EINVAL;

View File

@ -23,6 +23,8 @@
#ifndef __ZMQ_OPTIONS_HPP_INCLUDED__
#define __ZMQ_OPTIONS_HPP_INCLUDED__
#include <string>
#include "stddef.h"
#include "stdint.hpp"
@ -46,6 +48,9 @@ namespace zmq
// Socket identity
unsigned char identity_size;
unsigned char identity [256];
// Last socket endpoint URI
std::string last_endpoint;
// Maximum tranfer rate [kb/s]. Default 100kb/s.
int rate;

View File

@ -161,6 +161,7 @@ int zmq::socket_base_t::parse_uri (const char *uri_,
}
protocol_ = uri.substr (0, pos);
address_ = uri.substr (pos + 3);
if (protocol_.empty () || address_.empty ()) {
errno = EINVAL;
return -1;
@ -340,6 +341,8 @@ int zmq::socket_base_t::bind (const char *addr_)
delete listener;
return -1;
}
rc = listener->get_address (&options.last_endpoint);
launch_child (listener);
return 0;
}
@ -354,6 +357,8 @@ int zmq::socket_base_t::bind (const char *addr_)
delete listener;
return -1;
}
rc = listener->get_address (&options.last_endpoint);
launch_child (listener);
return 0;
}

View File

@ -387,11 +387,18 @@ int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_)
addr_str [addr_str.size () - 1] == ']')
addr_str = addr_str.substr (1, addr_str.size () - 2);
// Parse the port number (0 is not a valid port).
uint16_t port = (uint16_t) atoi (port_str.c_str());
if (port == 0) {
errno = EINVAL;
return -1;
uint16_t port;
// Allow 0 specifically, to detect invalid port error in atoi if not
if (port_str[0] == '*' || port_str[0] == '0') {
// Resolve wildcard to 0 to allow autoselection of port
port = 0;
} else {
// Parse the port number (0 is not a valid port).
port = (uint16_t) atoi (port_str.c_str());
if (port == 0) {
errno = EINVAL;
return -1;
}
}
// Resolve the IP address.

View File

@ -22,6 +22,7 @@
#include <new>
#include <string.h>
#include <sstream>
#include "platform.hpp"
#include "tcp_listener.hpp"
@ -119,6 +120,40 @@ void zmq::tcp_listener_t::close ()
s = retired_fd;
}
int zmq::tcp_listener_t::get_address (std::string *addr_)
{
struct sockaddr sa;
char host[INET6_ADDRSTRLEN];
int port, rc;
std::stringstream portnum;
// Get the details of the TCP socket
socklen_t sl = sizeof(sockaddr);
rc = getsockname (s, &sa, &sl);
if (rc != 0) {
return rc;
}
// Split the retrieval between IPv4 and v6 addresses
if ( sa.sa_family == AF_INET ) {
inet_ntop(AF_INET, &(((struct sockaddr_in *)&sa)->sin_addr), host, INET6_ADDRSTRLEN);
port = ntohs( ((struct sockaddr_in *)&sa)->sin_port);
portnum << port;
// Store the address for retrieval by users using wildcards
*addr_ = std::string("tcp://") + std::string(host) + std::string(":") + portnum.str();
} else {
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&sa)->sin6_addr), host, INET6_ADDRSTRLEN);
port = ntohs( ((struct sockaddr_in6 *)&sa)->sin6_port);
portnum << port;
// Store the address for retrieval by users using wildcards
*addr_ = std::string("tcp://[") + std::string(host) + std::string("]:") + portnum.str();
}
return 0;
}
int zmq::tcp_listener_t::set_address (const char *addr_)
{
// Convert the textual address into address structure.
@ -168,6 +203,7 @@ int zmq::tcp_listener_t::set_address (const char *addr_)
errno_assert (rc == 0);
#endif
// Bind the socket to the network interface and port.
rc = bind (s, address.addr (), address.addrlen ());
#ifdef ZMQ_HAVE_WINDOWS

View File

@ -44,6 +44,9 @@ namespace zmq
// Set address to listen on.
int set_address (const char *addr_);
// Get the bound address for use with wildcard
int get_address(std::string *addr_);
private: