Remote Call Framework 3.1
Appendix - FAQ

Building

Why is my program trying to link to a Boost library?

If you have defined RCF_FEATURE_BOOST_SERIALIZATION, RCF will need to link to the Boost.Serialization library.

RCF does not link to any other Boost libraries.

Boost libraries have an auto linking feature that may cause your linker to look for the wrong file to link to. You can define BOOST_ALL_NO_LIB, and then explicitly tell the linker which files to link to.

Can I compile RCF into a DLL?

Yes. To export RCF functions from a DLL (Windows) or shared library (Unix), you will need to define RCF_BUILD_DLL when building the DLL or shared library.

Why do I sometimes get compiler errors when I include <windows.h> before RCF headers?

Historically there have been some header ordering issues with the Windows platform headers <windows.h> and <winsock2.h>. Including <windows.h> will by default include an older version of Winsock, and makes it impossible to subsequently include <winsock2.h> in the same translation unit.

The easiest workaround for this issue is to define WIN32_LEAN_AND_MEAN, before including <windows.h>.

Does RCF compile warning free on level 4 on Visual C++?

Yes, if the following warnings are disabled:

C4510 'class' : default constructor could not be generated
C4511 'class' : copy constructor could not be generated
C4512 'class' : assignment operator could not be generated
C4127 conditional expression is constant

Can I run RCF on platform XYZ?

Probably, but you may need to make minor modifications to RCF yourself, to accomodate platform specific issues, such as which platform headers to include.

Why do I get linker errors?

On Windows, if you are using TCP transports, you'll need to link to ws2_32.lib. On Unix platforms, you'll need to link to libraries like libnsl or libsocket.

Does RCF support 64 bit compilers?

Yes.

Does RCF support Unicode builds on Windows?

Yes.

Why do I get duplicate symbol linker errors for my external serialization functions?

If you define external serialization functions in a header file, without the inline modifier, and include them in two or more source files, you will get linker errors about duplicate symbols. The solution is to either add an inline modifier:

// X.hpp
inline void serialize(SF::Archive & ar, X & x)
{
...
}

, or to declare the serialization function in a header and define it in a source file :

// X.hpp
void serialize(SF::Archive & ar, X & x);
// X.cpp
void serialize(SF::Archive & ar, X & x)
{
...
}

How do I reduce build times for my application?

If you include RCF headers into commonly used application headers of your own, you may notice an increase in build time, as the compiler will parse the RCF headers once for every source file that includes them.

You should only include RCF headers when you need to - in other words, only include them into source files that use RCF functionality. In your application header files, you should be able to use forward declarations, rather than including the corresponding header files.

For example, if you are defining a class X with a RcfClient<> member, you can forward declare the RcfClient<>, and then use a pointer for the member:

// X.h
template<typename T>
class RcfClient;
class SomeInterface;
typedef RcfClient<SomeInterface> MyRcfClient;
typedef std::shared_ptr<MyRcfClient> MyRcfClientPtr;
class RcfServer;
typedef std::shared_ptr<RcfServer> RcfServerPtr;
// Application specific class that holds a RcfClient and a RcfServer.
class X
{
X();
MyRcfClientPtr mClientPtr;
RcfServerPtr mServerPtr;
};
// X.cpp
#include "X.h"
#include <RCF/RcfClient.hpp>
#include <RCF/RcfServer.hpp>
X::X() :
mClientPtr( new RcfClient<SomeInterface>(...) ),
mRcfServerPtr( new RcfServer(...) )
{}

You can then include X.h anywhere in your application, without including any RCF headers.

Platforms

Why do I run out of socket handles on Windows XP?

Whenever an outgoing TCP connection is made, a local port number has to be assigned to the connection. On Windows XP, those local ports (sometimes referred to as ephemeral ports) are by default assigned from a range of about 4000 port numbers.

If you create many RcfClient<> objects, with TCP endpoints, you will eventually exhaust the available ports, as Windows holds on to them for a short while after the connection is closed.

You should use as few TCP connections as possible (reuse RcfClient<> objects instead of creating new ones). There are also registry settings on Windows XP that alleviate the issue. Locate the following key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

, and set

TcpNumConnections = 0x800, MaxUserPort = 65534

After restarting, the system will allow an expanded range of ephemeral ports.

This problem is only relevant to older versions of Windows. Windows Vista and later use an expanded range of ephemeral ports.

Why does my leak detector think there is a leak in RCF?

Probably because RCF::deinit() has not yet been executed.

Is RCF's TCP server implementation based on I/O completion ports?

On Windows, RCF uses I/O completion ports. See Scalability.

Does RCF support a shared memory transport?

For local RPC on Windows, RCF supports named pipe transports (RCF::Win32NamedPipeEndpoint), which are backed by shared memory.

For local RPC on Unix, RCF supports Unix local socket transports (RCF::UnixLocalEndpoint).

Does RCF support IPv6?

Yes - see IPv4/IPv6.

Programming

How do I keep my user interface from becoming unresponsive when there's a remote call in progress?

Either run remote calls on a non-UI thread, or use progress callbacks to repaint the UI at short intervals. See Client Progress Notification.

How do I cancel a long-running client call?

Use a progress callback (see Client Progress Notification). You can configure the callback to be called at any given frequency, and when you want to cancel the call, throw an exception.

How do I stop a server from within a remote call?

You can't call RCF::RcfServer::stop() from within a remote call, because the stop() call will wait for all worker threads to exit, including the thread calling stop(), hence causing a deadlock.

If you really need to stop the server from within a remote call, you can start a new thread to do so:

RCF_BEGIN(I_Echo, "I_Echo")
RCF_METHOD_R1(std::string, Echo, const std::string &)
RCF_END(I_Echo)
class EchoImpl
{
public:
std::string Echo(const std::string &s)
{
if (s == "stop")
{
// Spawn a temporary thread to stop the server.
RCF::Thread t( [=]() { pServer->stop(); } );
t.detach();
}
return s;
}
};

How can I make remotely accessible functions private?

Make RcfClient<> a friend of your implementation class:

RCF_BEGIN(I_Echo, "I_Echo")
RCF_METHOD_R1(std::string, Echo, const std::string &)
RCF_END(I_Echo)
class EchoImpl
{
private:
friend RcfClient<I_Echo>;
std::string Echo(const std::string &s)
{
return s;
}
};

How do I use a single TCP connection with several RcfClient<> instances?

You can move network connections from one RcfClient<> to another. See Transport Access.

How do I forcibly disconnect a client from the server?

Call RCF::getCurrentRcfSession().disconnect() in your server implementation.

At what point does a RcfClient<> object connect to the server?

A RcfClient<> will only establish a network connection once you initiate a remote call. If you want to establish a network connections without actually making a remote call, use RCF::ClientStub::connect().

How do I determine what IP address a client is connecting from?

Call RCF::getCurrentRcfSession().getClientAddress() in your server implementation.

How do I detect client disconnections, from server-side code?

When a client disconnects, the associated RCF::RcfSession on the server is destroyed. You can use RcfSession::setOnDestroyCallback(), to notify your application code when this happens.

void onClientDisconnect(RCF::RcfSession & session)
{
// ...
}
class ServerImpl
{
void SomeFunc()
{
// From within a remote call, register a callback to be called when this RcfSession is destroyed.
auto onDestroy = [&](RCF::RcfSession& session) { onClientDisconnect(session); };
RCF::getCurrentRcfSession().setOnDestroyCallback(onDestroy);
}
};

Can I use publish/subscribe through a firewall?

Yes. As long as a subscriber is able to initiate a connection to the publisher, it will receive published messages. The publisher will never initiate any network connection back to a subscriber.

How do I know whether a subscriber has received a published message?

The publisher cannot know this, because messages are published using one-way semantics.

How does a subscriber know if a publisher has stopped publishing?

Use subscriber disconnect notifications. See Subscribers.

You can also poll for connectedness using RCF::Subscription::isConnected().

Why can't I use pointers in RCF interfaces?

Pointers can't be used as return types in RCF interfaces, because there is no safe way of marshaling them.

Pointers can be used as parameters in RCF interfaces, although most of the time you are better off either using references, or one of the smart pointer types available in C++.

How do I start a TCP server on the first available port on my machine?

Specify a port number of zero in the RCF::TcpEndpoint object passed to the RCF::RcfServer constructor. After the server is started, retrieve the port number by calling RcfServer::getIpServerTransport().getPort().

How do I expose several servant objects with the same RCF interface?

Use servant binding names. See Adding Servant Bindings.

Why is my server only accessible from the local machine, and not across the network?

In the RCF::TcpEndpoint passed to your RCF::RcfServer, you need to specify 0.0.0.0 as the IP address, to allow clients to access it through any network interface. By default 127.0.0.1 is used, which will only allow clients on the local machine to connect.

Why does my program crash or assert when exiting?

Probably because your program has a global static object whose destructor is trying to destroy a RcfClient<> or RcfServer object (or some other RCF object), after RCF has been deinitialized.

Make sure you destroy all RCF objects before deinitializing RCF.

How do I serialize enums?

RCF will serialize and deserialize C++03 enums automatically, as integer representations.

C++11 enum classes require a helper macro SF_SERIALIZE_ENUM_CLASS() (see Standard C++ Types).

Can I use SF to serialize objects to and from files?

Yes, see Serialization To and From Disk.

How do I send a file using RCF?

See File Transfers.

How can I access the internal asio::io_service used by the RCF server?

You can call AsioServerTransport::getIoService():

#include <RCF/AsioServerTransport.hpp>
RCF::RcfServer server( RCF::TcpEndpoint(0) );
RCF::ServerTransport & transport = server.getServerTransport();
RCF::AsioServerTransport & asioTransport = dynamic_cast<RCF::AsioServerTransport &>(transport);
boost::asio::io_service & ioService = asioTransport.getIoService();

The io_service will be destroyed when the RcfServer is stopped.

How do I pass a security token from the client to the server, without changing the RCF interface?

You can use custom request user data (RCF::ClientStub::setRequestUserData(), RCF::RcfSession::getRequestUserData()) , to pass application specific data from the client to the server. See Custom Request and Response Data.

Can I send std::wstring objects between Linux and Windows?

Yes. std::wstring objects are assumed to be represented in UTF-32 on Linux, and UTF-16 on Windows, and RCF will encode them as UTF-8 when serializing.

Can I send UTF-8 encoded std::string objects between Linux and Windows?

Yes. RCF serializes std::string as a sequence of 8-bit characters, so it doesn't matter whether the encoding is ASCII, ISO-8859-1, UTF-8, or anything else.

Miscellaneous

Why are there double parentheses in many of the examples in the documentation?

The following code snippet will cause compiler errors:

int port = 0;
RcfClient<I_Echo> client( RCF::TcpEndpoint(port) );
// Will get compiler errors on both of these lines...
client.getClientStub();
server.start();

Because of a C++ language idiosyncracy, the declarations of client and server are actually interpreted as function declarations, taking a RCF::TcpEndpoint parameter named port. C++ compilers interpret the declarations this way to maintain backwards compatibility with C.

To clear up this ambiguity, extra parentheses are needed around the RCF::TcpEndpoint:

int port = 0;
RcfClient<I_Echo> client(( RCF::TcpEndpoint(port) ));
RCF::RcfServer server(( RCF::TcpEndpoint(port) ));
// Now its OK.
client.getClientStub();
server.start();

This quirk of the C++ language is sometimes referred to as "C++'s most vexing parse".