Server and client transports are responsible for the actual transmission and reception of network messages. A RcfServer
contains one or more server transports, while a client contains only a single client transport.
To access the server transports of a RcfServer
, capture the return value of RcfServer::addEndpoint()
:
Alternatively, if the RcfServer
only has a single server transport, you can access it by calling RCF::RcfServer::getServerTransport()
:
On the client side, the client transport is availablable through RCF::ClientStub::getTransport()
:
For server-side transports, it is generally necessary to set an upper limit on the size of incoming network messages. Without an upper limit, it is possible for malformed requests to cause arbitrarily sized memory allocations on the server.
The maximum incoming message length setting of a RCF server transport defaults to 1 Mb, and can be changed by calling RCF::ServerTransport::setMaxIncomingMessageLength()
:
Similarly, there is a maximum incoming message length setting for client transports. It defaults to 1 Mb and can be changed by calling RCF::ClientTransport::setMaxIncomingMessageLength()
:
As client transports only receive network messages from a peer they have connected to, the risk of malformed packets is not as great as for server transports.
It is possible to query a RcfClient<>
for the sizes of the latest request and response messages sent:
To set the maximum number of simultaneous connections to a RCF server transport:
This setting is not relevant to the UDP server transport, as there is no concept of connections within the UDP protocol.
For IP-based server transports, you can allow the local system to assign a server port number automatically, by specifying 0 as the port number. When the server starts, the system will find a free port and assign it to the server. The port number can subseqently be retrieved through RCF::IpServerTransport::getPort()
:
For IP-based server transports, client access can be allowed or denied, based on the IP addresses of the clients.
To configure IP rules for allowing clients, use RCF::IpServerTransport::setAllowIps():
To configure IP rules for denying clients, use RCF::IpServerTransport::setDenyIps():
RCF supports both IPv4 and IPv6. IPv6 support is enabled by default in RCF, but you can define RCF_FEATURE_IPV6=0
to disable it (see Building RCF).
For example, to run a server and client over a loopback IPv4 connection:
To run a server and client over a loopback IPv6 connection instead, specify ::1
instead of 127.0.0.1
:
RCF uses the POSIX getaddrinfo()
function to resolve IP addresses. getaddrinfo()
can return either IPv4 or IPv6 addresses, depending on the configuration of the local system and network. So the following client will use either IPv4 or IPv6, depending on how the local system and network have been configured:
You can force IPv4 or IPv6 resolution by using the RCF::IpAddressV4
and RCF::IpAddressV6
classes:
On machines with dual IPv4/IPv6 stacks, you will probably want your server to listen on both IPv4 and IPv6 addresses. To do this portably, you should listen on both 0.0.0.0
and ::0
:
On some platforms, it is sufficient to listen only on ::0
, as the system will translate incoming IPv4 connections into IPv6 connections with a special class of IPv6 addresses.
When a RcfClient<>
connects to a server using an IP-based transport, the default behavior is to allow the system to decide which local network interface and local port to use. In some circumstances, you may want to explicitly set the local network interface a client should bind to.
You can do so by calling RCF::IpClientTransport::setLocalIp()
, before connecting:
After a RcfClient<>
has connected, you can determine which local network interface and port it is bound to, by calling RCF::IpClientTransport::getAssignedLocalIp()
:
RCF provides access to the underlying OS primitives, such as sockets and handles, of client and server transports. For example:
This can be useful if you need to set custom socket options.
This sections covers the various transport types that are implemented in RCF.
TCP endpoints are represented in RCF by the RCF::TcpEndpoint
class, constructed from an IP address and a port number.
Server transports interpret the IP address as the local network interface to listen on. So for example "0.0.0.0"
should be specified in order to listen on all available IPv4 network interfaces, and "127.0.0.1"
should be specified to listen only on the loopback IPv4 interface. If no IP address is specified, "127.0.0.1"
is assumed.
Like RCF::TcpEndpoint
, RCF::UdpEndpoint
is constructed from an IP address and a port.
RCF::UdpEndpoint
also contains some extra functionality, to deal with multicasting and broadcasting.
RCF::UdpEndpoint
can be configured to listen on a multicast IP address:
Note that the server still needs to specify a local network interface to listen on.
To send multicast messages, specify a multicast IP address and port when creating the client:
To send broadcast messages, specify a broadcast IP address and port:
RCF's UDP server transport can be configured to share its address binding, so that multiple RcfServer
's can listen on the same port of the same interface. This is enabled by default when listening on multicast addresses, but can also be enabled when listening on non-multicast addresses. This can be useful if multiple processes on the same machine need to listen to the same broadcasts:
In situations where servers are started on dynamically assigned ports, multicasting and broadcasting can be a useful means of communicating server IP addresses and ports to clients. For example:
Note that here we are actually using a multicast address to broadcast information to clients. If multicasting had been unavailable on this particular network, we could also have used an IP broadcast address instead of an IP multicast address.
RCF supports Win32 named pipe transports. RCF::Win32NamedPipeEndpoint
takes one constructor parameter, which is the name of the named pipe, with or without the leading \\.\pipe\
prefix.
An advantage of using Win32 named pipes, is that they allow easy authentication of clients. A server using a Win32 named pipe server transport can authenticate its clients through the RCF::Win32NamedPipeImpersonator
class, which uses the Windows API function ImpersonateNamedPipeClient()
to impersonate the client:
If we had used a TCP connection to 127.0.0.1
instead, we would have needed to enable Kerberos or NTLM authentication to securely determine the clients user name (see Transport protocols).
UNIX domain sockets function analogously to Win32 named pipes, and allow efficient communication between servers and clients on the same machine. RCF::UnixLocalEndpoint
takes one parameter, which is the name of the UNIX domain socket. The name must be a valid filesystem path. For servers, the program must have sufficient privilege to create the given path, and the file must not already exist. For clients, the program must have sufficient privilege to access the given path.
Here is a simple example:
RCF supports tunneling remote calls over the HTTP and HTTPS protocols. In particular, remote calls can be directed through HTTP and HTTPS proxies.
HTTPS is essentially the HTTP protocol layered on top of the SSL protocol. As such, configuration of the SSL aspects of HTTPS, is done in the same way as for the SSL transport protocol (see Transport protocols).
To setup a server with an HTTP endpoint, use RCF::HttpEndpoint
:
Similarly, for an HTTPS endpoint, use RCF::HttpsEndpoint
:
Client side configuration is similar, using RCF::HttpEndpoint
for a HTTP client:
, and RCF::HttpsEndpoint
for a HTTPS client:
Finally, to direct remote calls through a HTTP or HTTPS proxy, use the RCF::ClientStub::setHttpProxy()
and RCF::ClientStub::setHttpProxyPort()
functions:
HTTP reverse proxies are common on the Internet, and are used to provide functionality such as load balancing and SSL offloading for back-end HTTP servers.
Reverse proxies are generally transparent to the client and destination servers. You can place a reverse proxy between a RCF client and a server, and this provides an out-of-the-box mechanism for distributing load across a set of RCF servers.
In load-balancing scenarios, you may want a RCF client to continue sending requests to the same back-end server that it initially connects to. To accomplish this, you will need to use a reverse proxy with support for session affinity. Session affinity is normally implemented by the reverse proxy, by inserting a special HTTP cookie in the initial HTTP response of the communication stream. The RCF client will then automatically include this cookie on subsequent requests, allowing the reverse proxy to route subsequent requests through to the same back-end server.
If you have multiple RCF client connections, you can configure them to connect to the same back-end server, by retrieving the HTTP cookies from the first connection and subsequently applying them to the other connections (see RCF::ClientStub::setHttpCookies()
).
Another reverse proxying feature you can utilize with RCF is SSL offloading. With SSL offloading , the RCF client connects using a HTTPS connection, but the HTTPS connection is decrypted by the reverse proxy, and the decrypted HTTP stream is forwarded on to the back-end server. This allows secure communication between the client and the back-end server, with the reverse proxy assuming the load of SSL encryption/decryption. This also has the advantage of centralizing certificate configuration, from multiple back-end servers, to the reverse proxy server.
RCF has been tested with the following reverse proxies: