The
x::fd
reference-counted object
provides standard wrappers for the usual socket functions,
socket(2),
connect(2),
listen(2),
bind(2), and
accept(2).
Additionally, the
x::netaddr
reference provides a convenient high level interface for creating sockets:
#include <x/fd.H> #include <x/netaddr.H> x::fd sock=x::netaddr::create("www.example.com", "http", SOCK_STREAM) ->domain(AF_INET)->connect();
x::netaddr
holds an unresolved network address
(the hostname, port, socket type, and a few other attributes). Its
connect
() method uses
getaddrinfo(3) to resolve the network address, then tries connecting
to each resolved address. If the server's name resolves to multiple
addresses, a connection attempt gets made to each address, until a
connection gets established. An exception gets thrown if connection
to all resolved addresses fails.
An optional parameter to connect
() implements a
general mechanism for timing out a connection attempt:
#include <x/fdtimeoutconfig.H> class my_timeout_config : public x::fdtimeoutconfig { public: x::fd termfd; x::fdbase operator()(const fd &fdArg) const { x::fdtimeout fd_with_timeout(x::fdtimeout::create(fd)); fd_with_timeout->set_terminate_fd(termfd); return fd_with_timeout; } }; // ... my_timeout_config timeout; // ... fd sock=x::netaddr::create("www.example.com", "http", SOCK_STREAM) ->domain(AF_INET) ->connect(timeout);
The optional parameter to connect
() is a functor
subclass of
x::fdtimeoutconfig
.
The functor receives the newly created socket object, and returns a
reference to the
x::fdbase
which
will be used for the actual connection attempt.
The above example sets a
file descriptor terminator.
If the terminator descriptor becomes readable, the connection attempt
gets aborted.
fd sock=x::netaddr::create("www.example.com", "http", SOCK_STREAM) ->domain(AF_INET) ->connect(x::fdtimeoutconfig::terminate_fd(termfd));
Use
x::fdtimeoutconfig::terminate_fd
as a convenient shortcut to implement the same functionality.
The constructor takes a terminator file descriptor, and defines a
functor that installs the terminator file descriptor into each received
file descriptor.
LIBCXX_NAMESPACE::fdtimeoutptr timeout; fd sock=x::netaddr::create("www.example.com", "http", SOCK_STREAM) ->domain(AF_INET) ->connect(x::make_fdtimeoutconfig( [&timeout] (const x::fdbase &fd) { auto new_timeout=x::fdtimeout::create(fd); new_timeout->set_write_timeout(60); timeout=new_timeout; return new_timeout; })); timeout->set_read_timeout(60);
x::make_fdtimeoutconfig
()
takes a lambda as a
parameter, and constructs a subclass of
x::fdtimeoutconfig::terminate_fd
that calls the lambda. Note that connect
()
uses the returned timeout handler for the duration of the socket
connection only, and returns the actual socket file descriptor, so
this lambda saves the constructed timeout handled, for use after
connect
() returns.
std::list<x::fd> fdList; x::netaddr::create("", "http", SOCK_STREAM) ->bind(fdList, true);
x::netaddr
's bind() method creates a list of
socket objects and binds them to the specified address. It's possible
that the specified address may resolve to multiple addresses, for example
an IPv4 and an IPv6 socket. This is why bind() takes a list of
sockets as a parameter. bind() creates all sockets, binds each socket,
and adds them to the list.
The second parameter may also be a string with a list of port names
or numbers, separated by commas or spaces; or an explicit
std::list<int> &
.
When used with bind
(), this creates listening sockets
on all specified ports.
When used with connect
(), this connects to the
first port in the list that's listening for connections.
An alternative format provides for a unified way to create either a network or filesystem domain socket:
x::fd fd=x::netaddr::create(SOCK_STREAM, "inet:www.example.com", "http"); // ... x::fd fd=x::netaddr::create(SOCK_STREAM, "file:/tmp/sock"); ->bind(fdList, true);
Specify “inet:host
” creates a
network socket, and
“file:path
” connects to a
filesystem socket. For network sockets, “/port” may also
be appended to the host parameter, instead of given as a separate
argument.
std::string d=x::fd::base::mktempdir(0700); std::pair<x::fd, std::string> tmpsock=x::fd::tmpunixfilesock(d + "/sysmon.");
As explained at the beginning of this chapter,
x::fd::mktempdir
() creates a temporary
subdirectory, with the right permissions, in
/tmp
.
x::fd::tmpunixfilesock
() creates a randomly
named filename and attempts to bind a filesystem
domain socket, returning the socket and the bound name. To prevent
pollution, every attempt to manually unlink the socket should be made,
before the process terminates.