## Tutorial

### Getting started

#### Hello World

Following programming language traditions, let's start with a "Hello World" example. We'll write a client that sends strings to a server, and a server that prints the strings to standard output.

Here is the server:

    #include <RCF/RCF.hpp>

    #include <iostream>

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
    RCF_END(I_HelloWorld)

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
        }
    };

    int main()
    {
        RCF::RcfInitDeinit rcfInit;

        HelloWorldImpl helloWorld;
        RCF::RcfServer server( RCF::TcpEndpoint(50001) );
        server.bind<I_HelloWorld>(helloWorld);
        server.start();

        std::cout << "Press Enter to exit..." << std::endl;
        std::cin.get();

        return 0;
    }

And the client:

    #include <RCF/RCF.hpp>

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
    RCF_END(I_HelloWorld)

    int main()
    {
        RCF::RcfInitDeinit rcfInit;
        std::cout << "Calling the I_HelloWorld Print() method." << std::endl;
        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
        client.Print("Hello World");
        return 0;
    }

The transport used is a TCP connection, with the server listening on port 50001 of the localhost (`127.0.0.1`) interface.

Before we can run this code, we need to build it. To build RCF, you simply need to compile the `src/RCF/RCF.cpp` source file into your application. RCF requires the Boost library to be available, so you will need to download Boost. Any version from 1.35.0 onwards will do. You do not need to build any Boost libraries, as RCF will in its default configuration only use header files from Boost.

Here is how you would build the server code above, with two common compiler toolsets.

#### How to build - Visual Studio 2010

- In the Visual Studio IDE, select `New Project -> Visual C++ -> Win32 -> Win32 Console Application`
- In the `Application Settings` dialog, check the `Empty Project` checkbox.
- In the `Project Properties` dialog for the new project, select `C/C++ -> General -> Additional Include Directories`.
- Add the include paths for Boost and RCF, e.g. `C:\boost_1_49_0` and `C:\RCF\include`.
- Add a file `Server.cpp` to the project, and copy-paste the code above into it.
- Add `RCF\src\RCF\RCF.cpp` to the project.
- Select `Build -> Build Solution`.

#### How to build - gcc

- Create a file `Server.cpp` and copy-paste the code above into it.
- From the same directory, run the following command:

    g++ Server.cpp /path/to/RCF/src/RCF/RCF.cpp -I/path/to/boost_1_49_0 -I/path/to/RCF/include -lpthread -ldl -oServer

, replacing `/path/to/boost_1_49_0` and `/path/to/RCF` with the actual paths on your system.

#### Running the server and client

Let's start the server:

    c:\Projects\RcfSample\Debug>Server.exe
    Press Enter to exit...

, and then the client:

    c:\Projects\RcfSample\Debug>Client.exe
    Calling the I_HelloWorld Print() method.
    c:\Projects\RcfSample\Debug>

In the server window, you should now see:

    c:\Projects\RcfSample\Debug>Server.exe
    Press Enter to exit...
    I_HelloWorld service: Hello World

To simplify the rest of the tutorial, we'll rewrite our Hello World example so that the client and server run in a single process:

    #include <iostream>

    #include <RCF/RCF.hpp>

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
    RCF_END(I_HelloWorld)

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
        }
    };

    int main()
    {
        RCF::RcfInitDeinit rcfInit;

        HelloWorldImpl helloWorld;
        RCF::RcfServer server( RCF::TcpEndpoint(50001) );

        server.bind<I_HelloWorld>(helloWorld);

        server.start();

        std::cout << "Calling the I_HelloWorld Print() method." << std::endl;

        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
        client.Print("Hello World");

        return 0;
    }

Running this program yields the output:

    Calling the I_HelloWorld Print() method.
    I_HelloWorld service: Hello World

The rest of the tutorial will build on this example, to illustrate some of the fundamental features of RCF.

### Interfaces and implementations

RCF allows you to define remote interfaces, directly in code. In the example above, we defined the `I_HelloWorld` interface:

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
    RCF_END(I_HelloWorld)

`RCF_BEGIN()`, `RCF_METHOD_xx()`, and `RCF_END()` are macros that are used to generate client and server stubs for remote calls.

- `RCF_BEGIN()` starts the interface definition, and defines the compile time identifier of the interface (`I_HelloWorld`), and the runtime identifier of the interface (`"I_HelloWorld"`).
- `RCF_METHOD_xx()` - The `RCF_METHOD_xx()` macros define remote methods. `RCF_METHOD_V1()` defines a remote method taking one parameter (in this case `const std::string &`), and returning `void`. `RCF_METHOD_R2()` defines a remote method with two parameters and a non-`void` return value, and so on. The `RCF_METHOD_xx()` macros are defined for `void` and non-`void` remote calls taking up to 15 parameters.
- `RCF_END()` ends the interface definition.

On the server, we bind the interface to a servant object:

    server.bind<I_HelloWorld>(helloWorld);

Let's add a few more remote methods to the `I_HelloWorld` interface. We'll add methods to print a list of strings, and return the number of characters printed:

    // Serialization code for std::vector<>.
    #include <SF/vector.hpp>

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
        RCF_METHOD_R1(int,  Print, const std::vector<std::string> &)
        RCF_METHOD_V2(void, Print, const std::vector<std::string> &, int &)
    RCF_END(I_HelloWorld)

Remote calls can return arguments either through a return value (as the second `Print()` method does), or through a non-const reference parameter (as the third `Print()` method does).

Having added these methods to the `I_HelloWorld` interface, we also need to implement them in the `HelloWorldImpl` servant object:

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
        }

        int Print(const std::vector<std::string> & v)
        {
            int howManyChars = 0;
            for (std::size_t i=0; i<v.size(); ++i)
            {
                std::cout << "I_HelloWorld service: " << v[i] << std::endl;
                howManyChars += v[i].size();
            }
            return howManyChars;
        }

        void Print(const std::vector<std::string> & v, int & howManyChars)
        {
            howManyChars = 0;
            for (std::size_t i=0; i<v.size(); ++i)
            {
                std::cout << "I_HelloWorld service: " << v[i] << std::endl;
                howManyChars += v[i].size();
            }
        }
    };

Notice that `HelloWorldImpl` is not a derived class. Instead of virtual functions, RCF uses template-based static polymorphism to bind interfaces to implementations.

Here is sample client code to call the new `Print()` methods:

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

    std::vector<std::string> stringsToPrint;
    stringsToPrint.push_back("AAA");
    stringsToPrint.push_back("BBB");
    stringsToPrint.push_back("CCC");

    // Remote call returning argument through return value.
    int howManyChars = client.Print(stringsToPrint);

    // Remote call returning argument through non-const reference parameter.
    client.Print(stringsToPrint, howManyChars);

And the output:

    I_HelloWorld service: AAA
    I_HelloWorld service: BBB
    I_HelloWorld service: CCC
    I_HelloWorld service: AAA
    I_HelloWorld service: BBB
    I_HelloWorld service: CCC

### Error handling

If a remote call does not complete, RCF will throw an exception containing an error message describing the error condition. Let's put a `try/catch` wrapper around the remote call:

    try
    {
        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
        client.Print("Hello World");
    }
    catch(const RCF::Exception & e)
    {
        std::cout << "Error: " << e.getErrorString() << std::endl;
    }

We can simulate the server being down, by commenting out the `RcfServer::start()` call:

    HelloWorldImpl helloWorld;
    RCF::RcfServer server( RCF::TcpEndpoint(50001) );
    server.bind<I_HelloWorld>(helloWorld);
    //server.start();

Running the client, we now get this:

    Error: Client connection to 127.0.0.1:50001 timed out after 2000 ms (server not started?).

All exceptions thrown by RCF are derived from `RCF::Exception`. `RCF::Exception` holds various descriptive and contextual information about the error. You can call `RCF::Exception::getErrorId()` to retrieve the error code, and `RCF::Exception::getErrorString()`, to retrieve an English translation of the error, including any error-specific arguments.

If the server implementation of a remote call throws an exception, it will be caught by the `RcfServer` and returned to the client, where it is thrown as a `RCF::RemoteException`. For example, if we start the server with the following servant implementation:

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            throw std::runtime_error("Print() service is unavailable at this time.");
            std::cout << "I_HelloWorld service: " << s << std::endl;
        }
    };

, the client will now output:

    Error: Server-side user exception. Exception type: class std::runtime_error. Exception message: "Print() service is unavailable at this time.".

### Client stubs

Remote calls are always made through a client stub (`RCF::ClientStub`). You can access the client stub of a `RcfClient<>` by calling `RcfClient<>::getClientStub()`. The client stub contains a number of settings that affect how a remote call is executed.

Two of the most important settings are the connection timeout and the remote call timeout. The connection timeout determines how long RCF will wait while trying to establish a network connection to the server. The remote call timeout determines how long RCF will wait for a remote call response to return from the server.

To change these settings, call the `ClientStub::setConnectionTimeoutMs()` and `ClientStub::setRemoteCallTimeoutMs()` functions:

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

    // 5 second timeout when establishing network connection.
    client.getClientStub().setConnectTimeoutMs(5*1000);

    // 60 second timeout when waiting for remote call response from the server.
    client.getClientStub().setRemoteCallTimeoutMs(60*1000);

    client.Print("Hello World");

See Remote calls - Client-side for more about client stubs.

### Server sessions

On the server-side, RCF maintains a session (`RCF::RcfSession`) for every client connection to the server. The `RcfSession` of a client connection is available to server-side code through `RCF::getCurrentSession()`. You can use `RcfSession` to maintain application data specific to a particular client connection. Arbitrary C++ objects can be stored in a session by calling `RcfSession::createSessionObject<>()` or `RcfSession::getSessionObject<>()`.

For instance, to associate a `HelloWorldSession` object with each client connection to the `I_HelloWorld` interface, which tracks the numer of calls made on a connection:

    class HelloWorldSession
    {
    public:
        HelloWorldSession() : mCallCount(0)
        {
            std::cout << "Created HelloWorldSession object." << std::endl;
        }

        ~HelloWorldSession()
        {
            std::cout << "Destroyed HelloWorldSession object." << std::endl;
        }

        std::size_t mCallCount;
    };

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            RCF::RcfSession & session = RCF::getCurrentRcfSession();

            // Creates the session object if it doesn't already exist.
            HelloWorldSession & hwSession = session.getSessionObject<HelloWorldSession>(true);

            ++hwSession.mCallCount;

            std::cout << "I_HelloWorld service: " << s << std::endl;
            std::cout << "I_HelloWorld service: " << "Total calls on this connection so far: " << hwSession.mCallCount << std::endl;
        }
    };

Distinct `RcfClient<>` instances will have distinct connections to the server. Here we are calling `Print()` three times from two `RcfClient<>` instances:

    for (std::size_t i=0; i<2; ++i)
    {
        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
        client.Print("Hello World");
        client.Print("Hello World");
        client.Print("Hello World");
    }

    // Wait a little so the server has time to destroy the last session.
    RCF::sleepMs(1000);

, resulting in the following output:

    Created HelloWorldSession object.
    I_HelloWorld service: Hello World
    I_HelloWorld service: Total calls on this connection so far: 1
    I_HelloWorld service: Hello World
    I_HelloWorld service: Total calls on this connection so far: 2
    I_HelloWorld service: Hello World
    I_HelloWorld service: Total calls on this connection so far: 3
    Destroyed HelloWorldSession object.
    Created HelloWorldSession object.
    I_HelloWorld service: Hello World
    I_HelloWorld service: Total calls on this connection so far: 1
    I_HelloWorld service: Hello World
    I_HelloWorld service: Total calls on this connection so far: 2
    I_HelloWorld service: Hello World
    I_HelloWorld service: Total calls on this connection so far: 3
    Destroyed HelloWorldSession object.

The server session and any associated session objects are destroyed when the client connection is closed.

See Remote calls - Server-side for more about server sessions.

### Transports

RCF makes it easy to change the underlying transport of a remote call. The transport layer is determined by the endpoint parameters passed to `RcfServer` and `RcfClient<>`. So far we've been using `TcpEndpoint`, to specify a TCP transport.

By default, when you specify a `TcpEndpoint` with only a port number, RCF will use `127.0.0.1` as the IP address. So the following two snippets are equivalent:

    RCF::RcfServer server( RCF::TcpEndpoint(50001) );

    RCF::RcfServer server( RCF::TcpEndpoint("127.0.0.1", 50001) );

, as are the following:

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint("127.0.0.1", 50001) );

`127.0.0.1` is the IPv4 loopback address. A server listening on `127.0.0.1` will only be available to clients on the same machine as the server. It's likely you'll want to run clients across the network, in which case the server will need to listen on an externally visible network address. The easiest way to do that is to specify `0.0.0.0` (for IPv4), or `::0` (for IPv6) instead, which will make the server listen on all available network interfaces:

    // Server-side.
    RCF::RcfServer server( RCF::TcpEndpoint("0.0.0.0", 50001) );

    // Client-side.
    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint("Server123", 50001) );

RCF supports a number of other endpoint types as well. To run the server and client over UDP, use `UdpEndpoint`:

    // Server-side.
    RCF::RcfServer server( RCF::UdpEndpoint("0.0.0.0", 50001) );

    // Client-side.
    RcfClient<I_HelloWorld> client( RCF::UdpEndpoint("Server123", 50001) );

To run the server and client over named pipes, use `NamedPipeEndpoint`:

    // Server-side.
    RCF::RcfServer server( RCF::Win32NamedPipeEndpoint("MyPipe") );

    // Client-side.
    RcfClient<I_HelloWorld> client( RCF::Win32NamedPipeEndpoint("MyPipe") );

`NamedPipeEndpoint` maps onto Windows named pipes on Windows systems, and UNIX local domain sockets on UNIX-based systems.

It's usually not practical to use UDP for two-way (request/response) messaging, as the unreliable semantics of UDP mean that messages may not be delivered, or may be delivered out of order. UDP is useful in one-way messaging scenarios, where the server application logic is resilient to messages being lost or arriving out of order.

RCF supports tunneling of remote calls over the HTTP and HTTPS protocols. `RCF::HttpEndpoint` is used to configure tunneling over HTTP. Here is an example of a client making remote calls to a server, through a third party HTTP proxy:

    // Server-side.
    HelloWorldImpl helloWorldImpl;
    RCF::RcfServer server( RCF::HttpEndpoint("0.0.0.0", 80) );
    server.bind<I_HelloWorld>(helloWorldImpl);
    server.start();

    // Client-side.
    // This client will connect to server1.acme.com via the HTTP proxy at proxy.acme.com:8080.
    RcfClient<I_HelloWorld> client( RCF::HttpEndpoint("server1.acme.com", 80) );
    client.getClientStub().setHttpProxy("proxy.acme.com");
    client.getClientStub().setHttpProxyPort(8080);
    client.Print("Hello World");

Similarly, `RCF::HttpsEndpoint` can be used to configure tunneling over HTTPS:

    // Server-side.
    HelloWorldImpl helloWorldImpl;
    RCF::RcfServer server( RCF::HttpsEndpoint("0.0.0.0", 443) );
    server.bind<I_HelloWorld>(helloWorldImpl);
    RCF::CertificatePtr serverCertPtr( new RCF::PfxCertificate("path/to/certificate.p12", "password", "CertificateName") );
    server.setCertificate(serverCertPtr);
    server.start();

    // Client-side.
    // This client will connect to server1.acme.com via the HTTP proxy at proxy.acme.com:8080.
    RcfClient<I_HelloWorld> client( RCF::HttpsEndpoint("server1.acme.com", 443) );
    client.getClientStub().setHttpProxy("proxy.acme.com");
    client.getClientStub().setHttpProxyPort(8080);
    client.Print("Hello World");

Certificates and certificate validation for HTTPS are configured as for the SSL transport protocol (see Transport Protocols below).

Multiple transports can be configured for a single `RcfServer`. For example, to configure a server that accepts both IPv4 and IPv6 connections on port 50001:

    RCF::RcfServer server;
    server.addEndpoint( RCF::TcpEndpoint("0.0.0.0", 50001) );
    server.addEndpoint( RCF::TcpEndpoint("::0", 50001) );
    server.start();

On some platforms, the underlying network stack will allow you to specify `::0` to listen on both IPv4 and IPv6 interfaces, in which case this would be sufficient:

    RCF::RcfServer server;
    server.addEndpoint( RCF::TcpEndpoint("::0", 50001) );
    server.start();

Here is a server accepting connections over TCP, UDP and named pipes:

    RCF::RcfServer server;
    server.addEndpoint( RCF::TcpEndpoint("::0", 50001) );
    server.addEndpoint( RCF::UdpEndpoint("::0", 50002) );
    server.addEndpoint( RCF::Win32NamedPipeEndpoint("MyPipe") );
    server.start();

See Transports for more information on transports.

### Transport protocols

Transport protocols are layered on top of the transport, and provide authentication and encryption.

RCF supports the following transport protocols:

- NTLM
- Kerberos
- SSL

The NTLM and Kerberos transport protocols are only supported on Windows, while the SSL transport protocol is supported on all platforms.

An `RcfServer` can be configured to require certain transport protocols:

    std::vector<RCF::TransportProtocol> protocols;
    protocols.push_back(RCF::Tp_Ntlm);
    protocols.push_back(RCF::Tp_Kerberos);
    server.setSupportedTransportProtocols(protocols);

On the client-side, `ClientStub::setTransportProtocol()` is used to configure transport protocols. For instance, to use the NTLM protocol on a client connection:

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    client.getClientStub().setTransportProtocol(RCF::Tp_Ntlm);
    client.Print("Hello World");

In this example, the client will authenticate itself to the server and encrypt its connection using the NTLM protocol, using the implicit credentials of the logged on user.

To provide explicit credentials, use `ClientStub::setUsername()` and `ClientStub::setPassword()`:

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    client.getClientStub().setTransportProtocol(RCF::Tp_Ntlm);
    client.getClientStub().setUsername("SomeDomain\\Joe");
    client.getClientStub().setPassword("JoesPassword");
    client.Print("Hello World");

The Kerberos protocol can be configured similarly. The Kerberos protocol requires the client to supply the Service Principal Name (SPN) of the server. You can do this by calling `ClientStub::setKerberosSpn()`:

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    client.getClientStub().setTransportProtocol(RCF::Tp_Kerberos);
    client.getClientStub().setKerberosSpn("SomeDomain\\ServerAccount");
    client.Print("Hello World");

If a client attempts to call `Print()` without configuring one of the transport protocols required by the server, they will get an error:

    try
    {
        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
        client.Print("Hello World");
    }
    catch(const RCF::Exception & e)
    {
        std::cout << "Error: " << e.getErrorString() << std::endl;
    }

    Error: Server requires one of the following transport protocols to be used: NTLM, Kerberos.

From within the server implementation of `Print()`, you can retrieve the transport protocol of the current session. If the transport protocol is NTLM or Kerberos, you can also retrieve the username of the client, as well as impersonate the client:

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            RCF::RcfSession & session = RCF::getCurrentRcfSession();

            RCF::TransportProtocol protocol = session.getTransportProtocol();

            if ( protocol == RCF::Tp_Ntlm || protocol == RCF::Tp_Kerberos )
            {
                std::string clientUsername = session.getClientUsername();

                RCF::SspiImpersonator impersonator(session);

                // Now running under Windows credentials of client.
                // ...

                // Impersonation ends when we exit scope.
            }

            std::cout << s << std::endl;
        }
    };

RCF also supports using SSL as the transport protocol. RCF provides two SSL implementations, one based on OpenSSL, and the other based on the Windows Schannel security package. The Windows Schannel implementation is used automatically on Windows, while the OpenSSL implementation is used if `RCF_USE_OPENSSL` is defined when building RCF (see Building).

SSL-enabled servers need to configure a SSL certificate. The mechanics of certificate configuration vary depending on which implementation is being used. Here is an example using the Schannel SSL implementation:

    RCF::RcfServer server( RCF::TcpEndpoint(50001) );

    RCF::CertificatePtr serverCertificatePtr( new RCF::PfxCertificate(
        "C:\\ServerCert.p12",
        "Password",
        "CertificateName") );

    server.setCertificate(serverCertificatePtr);

    server.start();

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    client.getClientStub().setTransportProtocol(RCF::Tp_Ssl);
    client.getClientStub().setEnableSchannelCertificateValidation("localhost");

`RCF::PfxCertificate` is used to load PKCS #12 certificates, from .pfx and .p12 files. RCF also provides the `RCF::StoreCertificate` class, to load certificates from a Windows certificate store.

When using the OpenSSL-based SSL implementation, the `RCF::PemCertificate` class is used to load PEM certificates, from .pem files.

RCF also supports link level compression of remote calls. Compression is configured independently of transport protocols, using `ClientStub::setEnableCompression()`. The compression stage is applied immediately before the transport protocol stage.

Here is an example of a client connecting to a server through an HTTP proxy, using NTLM for authentication and encryption, and with compression enabled:

    RcfClient<I_HelloWorld> client( RCF::HttpEndpoint("server123.com", 80) );
    client.getClientStub().setHttpProxy("proxy.mycompany.com");
    client.getClientStub().setHttpProxyPort(8080);
    client.getClientStub().setTransportProtocol(RCF::Tp_Ntlm);
    client.getClientStub().setEnableCompression(true);

    client.Print("Hello World");

For more information see Transport protocols.

### Server-side threading

By default a `RcfServer` uses a single thread to handle incoming remote calls, so remote calls are dispatched serially, one after the other.

This can be a problem if you have multiple clients and some of them are making calls that take significant time to complete. To improve responsiveness in these situations, a `RcfServer` can be configured to run multiple threads and dispatch remote calls in parallel.

To configure a multi-threaded `RcfServer`, use `RcfServer::setThreadPool()` to assign a thread pool to the server. RCF thread pools can be configured to use either a fixed number of threads:

    RCF::RcfServer server( RCF::TcpEndpoint(50001) );

    // Thread pool with fixed number of threads (5).
    RCF::ThreadPoolPtr tpPtr( new RCF::ThreadPool(5) );
    server.setThreadPool(tpPtr);

    server.start();

, or a dynamic number of threads, varying with server load:

    RCF::RcfServer server( RCF::TcpEndpoint(50001) );

    // Thread pool with varying number of threads (1 to 25).
    RCF::ThreadPoolPtr tpPtr( new RCF::ThreadPool(1, 25) );
    server.setThreadPool(tpPtr);

    server.start();

Thread pools configured through `RcfServer::setThreadPool()` are shared across all the transports of that `RcfServer`. It is also possible to use `I_ServerTransport::setThreadPool()` to configure thread pools for individual transports:

    RCF::RcfServer server;

    RCF::ServerTransport & tcpTransport = server.addEndpoint(RCF::TcpEndpoint(50001));
    RCF::ServerTransport & pipeTransport = server.addEndpoint(RCF::Win32NamedPipeEndpoint("MyPipe"));

    // Thread pool with up to 5 threads to serve TCP clients.
    RCF::ThreadPoolPtr tcpThreadPoolPtr( new RCF::ThreadPool(1, 5) );
    tcpTransport.setThreadPool(tcpThreadPoolPtr);

    // Thread pool with single thread to serve named pipe clients.
    RCF::ThreadPoolPtr pipeThreadPoolPtr( new RCF::ThreadPool(1) );
    pipeTransport.setThreadPool(pipeThreadPoolPtr);

    server.start();

### Asynchronous remote calls

RCF supports client-side asynchronous remote call invocation, and server-side asynchronous remote call dispatching.

#### Asynchronous remote call invocation

On the client-side, asynchronous remote calls allow you to avoid blocking the thread that is making a remote call. Asynchronous remote calls complete on background threads, and the calling thread is notified at a later point, when the call completes.

Asynchronous remote call invocation is implemented in RCF using the `RCF::Future<>` template. Here is a simple example of waiting for an asynchronous call to complete:

    HelloWorldImpl helloWorld;
    RCF::RcfServer server( RCF::TcpEndpoint(50001) );
    server.bind<I_HelloWorld>(helloWorld);
    server.start();

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

    RCF::Future<int> fRet;

    // Asynchronous remote call.
    fRet = client.Print("Hello World");

    // Wait for the call to complete.
    while (!fRet.ready()) RCF::sleepMs(1000);

    // Check for errors.
    std::auto_ptr<RCF::Exception> ePtr = client.getClientStub().getAsyncException();
    if (ePtr.get())
    {
        // Error handling.
        // ...
    }
    else
    {
        int howManyCharsPrinted = *fRet;
    }

A remote call is performed asynchronously, if any of the parameters, or the return value, is of type `RCF::Future<>`, or if `RCF::AsyncOneway` or `RCF::AsyncTwoway` is specified as the calling semantic. Once a call is complete, `RCF::Future<>` instances can be dereferenced to retrieve the return values. If the call completed with an error, the error can be retrieved by calling `RCF::ClientStub::getAsyncException()` . The error will also be thrown if an attempt is made to dereference an associated `RCF::Future<>` instance.

Instead of waiting for the result on the calling thread, we can assign a completion callback to the remote call:

    typedef boost::shared_ptr< RcfClient<I_HelloWorld> > HelloWorldPtr;

    void onPrintCompleted(
        RCF::Future<int> fRet,
        HelloWorldPtr clientPtr)
    {
        int howManyCharsPrinted = *fRet;
    }

    HelloWorldPtr clientPtr(
        new RcfClient<I_HelloWorld>(RCF::TcpEndpoint(50001)) );

    RCF::Future<int> fRet;

    // Asynchronous remote call, with completion callback.
    fRet = clientPtr->Print(
        RCF::AsyncTwoway( boost::bind(&onPrintCompleted, fRet, clientPtr) ),
        "Hello World");

We've passed both the `Future<int>` return value and a reference counted client (`HelloWorldPtr`) to the callback. If we were to destroy the client on the main thread, the asynchronous call would be automatically canceled, and the callback would not be called at all.

Asynchronous remote calls are useful in many circumstances. For instance, the following code will call `Print()` once every 10 seconds on 50 different servers:

    void onPrintCompleted(HelloWorldPtr clientPtr);
    void onWaitCompleted(HelloWorldPtr clientPtr);

    void onPrintCompleted(HelloWorldPtr clientPtr)
    {
        // Print() call completed. Wait for 10 seconds.

        clientPtr->getClientStub().wait(
            boost::bind(&onWaitCompleted, clientPtr),
            10*1000);
    }

    void onWaitCompleted(HelloWorldPtr clientPtr)
    {
        // 10 second wait completed. Make another Print() call.

        clientPtr->Print(
            RCF::AsyncTwoway( boost::bind(onPrintCompleted, clientPtr)),
            "Hello World");
    }

    // Addresses to 50 servers.
    std::vector<RCF::TcpEndpoint> servers(50);
    // ...

    // Create a connection to each server, and make the first call.
    std::vector<HelloWorldPtr> clients;
    for (std::size_t i=0; i<50; ++i)
    {
        HelloWorldPtr clientPtr( new RcfClient<I_HelloWorld>(servers[i]) );
        clients.push_back(clientPtr);

        // Asynchronous remote call, with completion callback.
        clientPtr->Print(
            RCF::AsyncTwoway( boost::bind(&onPrintCompleted, clientPtr)),
            "Hello World");
    }

    // All 50 servers are now being called once every 10 s.
    // ...

    // Upon leaving scope, the clients are all automatically destroyed. Any
    // remote calls in progress are automatically canceled.

Instead of blocking 50 threads with synchronous remote calls, all 50 connections are managed by a single thread. The remote call sequences to the 50 servers are all handled on a background RCF thread, and the connections are automatically destroyed when the main thread leaves scope.

#### Asynchronous remote call dispatching

RCF also supports server-side asynchronous remote call dispatching. When a remote call arrives at a `RcfServer`, it is handled by one of the threads in the servers thread pool. To process the call asynchronously on another thread, you can use the `RCF::RemoteCallContext<>` template to capture the server-side context of the remote call, and queue it for later processing.

Here is an example of using `RemoteCallContext<>` in server-side code. Instead of responding to `Print()` calls in `HelloWorldImpl::Print()`, we are passing the remote call contexts to a background thread to be processed in bulk once every second. The background thread uses `RemoteCallContext::parameters()` to access the parameters of each remote call, and `RemoteCallContext::commit()` to send the remote call response back to the client.

    #include <RCF/RemoteCallContext.hpp>

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_R1(int, Print, const std::string &)
    RCF_END(I_HelloWorld)

    // I_HelloWorld servant object
    class HelloWorldImpl
    {
    public:

        typedef RCF::RemoteCallContext<int, const std::string &> PrintCall;

        int Print(const std::string & s)
        {
            // Capture the remote call context and queue it in mPrintCalls.
            RCF::Lock lock(mPrintCallsMutex);
            mPrintCalls.push_back( PrintCall(RCF::getCurrentRcfSession()) );

            // Dummy return value.
            return 0;
        }

        HelloWorldImpl()
        {
            // Start the asynchronous printing thread.
            mStopFlag = false;

            mPrintThreadPtr.reset( new RCF::Thread( boost::bind(
                &HelloWorldImpl::processPrintCalls,
                this) ) );
        }

        ~HelloWorldImpl()
        {
            // Stop the asynchronous printing thread.
            mStopFlag = true;
            mPrintThreadPtr->join();
        }

    private:

        // Queue of remote calls.
        RCF::Mutex              mPrintCallsMutex;
        std::deque<PrintCall>   mPrintCalls;

        // Asynchronous printing thread.
        RCF::ThreadPtr          mPrintThreadPtr;
        volatile bool           mStopFlag;

        void processPrintCalls()
        {
            // Once a second, process all queued Print() calls.
            while (!mStopFlag)
            {
                Sleep(1000);

                // Retrieve all queued print calls.
                std::deque<PrintCall> printCalls;
                {
                    RCF::Lock lock(mPrintCallsMutex);
                    printCalls.swap(mPrintCalls);
                }

                // Process them.
                for (std::size_t i=0; i<printCalls.size(); ++i)
                {
                    PrintCall & printCall = printCalls[i];
                    const std::string & stringToPrint = printCall.parameters().a1.get();
                    std::cout << "I_HelloWorld service: " << stringToPrint << std::endl;
                    printCall.parameters().r.set( stringToPrint.size() );
                    printCall.commit();
                }
            }
        }
    };

The client code is unchanged:

    int main()
    {
        RCF::RcfInitDeinit rcfInit;

        HelloWorldImpl helloWorld;
        RCF::RcfServer server( RCF::TcpEndpoint(50001) );
        server.bind<I_HelloWorld>(helloWorld);
        server.start();

        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
        int charsPrinted = client.Print("Hello World");

        return 0;
    }

For more information, see Asynchronous Remote Calls.

### Publish/subscribe

RCF makes it easy to setup publish/subscribe feeds. For example, here is a publisher publishing `"Hello World"` once every second:

    RCF::RcfServer publishingServer( RCF::TcpEndpoint(50001) );
    publishingServer.start();

    // Start publishing.
    typedef boost::shared_ptr< RCF::Publisher<I_HelloWorld> > HelloWorldPublisherPtr;
    HelloWorldPublisherPtr pubPtr = publishingServer.createPublisher<I_HelloWorld>();

    while (shouldContinue())
    {
        Sleep(1000);

        // Publish a Print() call to all currently connected subscribers.
        pubPtr->publish().Print("Hello World");
    }

    // Close the publisher.
    pubPtr->close();

To create a subscription to the publisher:

    // Start a subscriber.
    RCF::RcfServer subscriptionServer(( RCF::TcpEndpoint() ));
    subscriptionServer.start();

    HelloWorldImpl helloWorld;

    RCF::SubscriptionPtr subPtr = subscriptionServer.createSubscription<I_HelloWorld>(
        helloWorld,
        RCF::TcpEndpoint(50001));

    // At this point Print() will be called on the helloWorld object once a second.
    // ...

    // Close the subscription.
    subPtr->close();

Each call the publisher makes is sent as a oneway call to all subscribers.

For more information on publish/subscribe messaging, see Publish/subscribe.

### Callback connections

So far we've seen clients making remote calls to servers. It's also possible for a server to make remote calls back to a client, once the client has established a connection. To do this, the client starts a `RcfServer` of its own, and calls `RcfServer::createCallbackConnection()`:

    // Client-side
    int main()
    {
        RCF::RcfInitDeinit rcfInit;

        // Client needs a RcfServer to accept callback connections.
        RCF::RcfServer callbackServer(( RCF::TcpEndpoint() ));
        HelloWorldImpl helloWorld;
        callbackServer.bind<I_HelloWorld>(helloWorld);
        callbackServer.start();

        // Establish client connection to server.
        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

        // Create the callback connection.
        RCF::createCallbackConnection(client, callbackServer);

        // Server can now call Print() on the helloWorld object.
        // ...

        return 0;
    }

On the server-side, `RcfServer::setCallbackConnectionCb()` is used to take control over the callback connection once it has been created by the client:

    // Server-side

    typedef boost::shared_ptr< RcfClient<I_HelloWorld> >    HelloWorldPtr;
    RCF::Mutex                                              gCallbackClientsMutex;
    std::vector< HelloWorldPtr >                            gCallbackClients;

    void onCallbackConnectionCreated(
        RCF::RcfSessionPtr sessionPtr,
        RCF::ClientTransportAutoPtr transportAutoPtr)
    {
        typedef boost::shared_ptr< RcfClient<I_HelloWorld> > HelloWorldPtr;
        HelloWorldPtr helloWorldPtr( new RcfClient<I_HelloWorld>(transportAutoPtr) );
        RCF::Lock lock(gCallbackClientsMutex);
        gCallbackClients.push_back( helloWorldPtr );
    }

    int main()
    {
        RCF::RcfInitDeinit rcfInit;

        RCF::RcfServer server( RCF::TcpEndpoint(50001) );

        server.setOnCallbackConnectionCreated(
            boost::bind(&onCallbackConnectionCreated, _1, _2) );

        server.start();

        // Wait for clients to create callback connections.
        // ...

        // Retrieve all created callback connections.
        std::vector<HelloWorldPtr> clients;
        {
            RCF::Lock lock(gCallbackClientsMutex);
            clients.swap(gCallbackClients);
        }

        // Call Print() on them.
        for (std::size_t i=0; i<clients.size(); ++i)
        {
            HelloWorldPtr clientPtr = clients[i];
            clientPtr->Print("Hello World");
        }

        return 0;
    }

Callback connections function just like regular connections, with the exception that callback connections cannot be reconnected. If a callback connection is lost, the client will need to connect again and call `RCF::createCallbackConnection()`, to re-establish connectivity.

For more information on callback connections, see Callback Connections.

### File transfers

File downloads and uploads are common in distributed systems. RCF provides built-in support for file transfers, through the `RCF::FileDownload` and `RCF::FileUpload` classes. `RCF::FileDownload` and `RCF::FileUpload` are used as remote method arguments, to implement file transfers as part of a remote call.

On the server-side, file transfer functionality is by default disabled, and needs to be explicitly enabled:

    HelloWorldImpl helloWorld;
    RCF::RcfServer server( RCF::TcpEndpoint(50001) );
    server.bind<I_HelloWorld>(helloWorld);

    server.start();

Here we've implemented a `PrintAndDownload()` method, that allows clients to download files:

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
        RCF_METHOD_V2(void, PrintAndDownload, const std::string &, RCF::FileDownload)
    RCF_END(I_HelloWorld)

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
        }

        void PrintAndDownload(const std::string & s, RCF::FileDownload fileDownload)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
            fileDownload = RCF::FileDownload("path/to/download");
        }
    };

, which can be called like this:

    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    RCF::FileDownload fileDownload("path/to/download/to");
    client.PrintAndDownload("Hello World", fileDownload);

    std::string pathToDownload = fileDownload.getLocalPath();
    RCF::FileManifest & downloadManifest = fileDownload.getManifest();
    std::cout << "Client-local path to upload: " << pathToDownload << std::endl;
    std::cout << "Number of files uploaded: " << downloadManifest.mFiles.size() << std::endl;

Here we've implemented a `PrintAndUpload()` method, that allows clients to upload files:

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
        RCF_METHOD_V2(void, PrintAndUpload, const std::string &, RCF::FileUpload)
    RCF_END(I_HelloWorld)

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
        }

        void PrintAndUpload(const std::string & s, RCF::FileUpload fileUpload)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
            std::string pathToUpload = fileUpload.getLocalPath();
            RCF::FileManifest & uploadManifest = fileUpload.getManifest();
            std::cout << "Server-local path to upload: " << pathToUpload << std::endl;
            std::cout << "Number of files uploaded: " << uploadManifest.mFiles.size() << std::endl;
        }
    };

, which can be called like this:

    // Upload files to server.
    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    RCF::FileUpload fileUpload("path/to/files");
    client.PrintAndUpload("Hello World", fileUpload);

File transfers can be monitored, paused, resumed, and canceled , and bandwidth throttles can be applied to file transfers to and from a given server.

For more information, see File transfers.

### Protocol Buffers

RCF provides native integration with Protocol Buffers. Classes that are generated by the Protocol Buffers compiler can be used in RCF interfaces, and serialization and deserialization is performed through the relevant Protocol Buffers functions.

For example, running the `protoc` compiler over the following Protobuf interface:

    // Person.proto

    message Person {
        required int32 id = 1;
        required string name = 2;
        optional string email = 3;
    }

    message PbEmpty {
        optional string log = 1;
    }

    protoc Person.proto --cpp_out=.

, generates the C++ class `Person`, defined in `Person.pb.h`.

By including `Person.pb.h`, we can send `Person` instances to our `Print()` function:

    #include <../test/protobuf/messages/cpp/Person.pb.h>

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
        RCF_METHOD_V1(void, Print, const Person &)
    RCF_END(I_HelloWorld)

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            std::cout << s << std::endl;
        }

        void Print(const Person & person)
        {
            std::cout << "Person name: " << person.name();
            std::cout << "Person email: " << person.email();
            std::cout << "Person id: " << person.id();
        }
    };

    int main()
    {
        RCF::RcfInitDeinit rcfInit;

        HelloWorldImpl helloWorld;
        RCF::RcfServer server( RCF::TcpEndpoint(50001) );
        server.bind<I_HelloWorld>(helloWorld);
        server.start();

        RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

        Person person;
        person.set_name("Bob");
        person.set_email("bob@acme.com");
        person.set_id(123);
        client.Print(person);

        return 0;
    }

For more information on Protocol Buffers support, see Protocol Buffers.

### JSON-RPC

RCF provides a built in JSON-RPC server, allowing access to C++ server functionality from JSON-RPC clients, such as Javascript code on web pages. RCF supports JSON-RPC over both HTTP and HTTPS.

RCF uses the JSON Spirit library to read and write JSON messages. You will need to download this library separately, and define `RCF_USE_JSON` when building RCF, to enable JSON-RPC support (see Appendix - Building).

To configure a JSON-RPC endpoint, call `I_ServerTransport::setRpcProtocol()` on the relevant server transport. To expose servant objects to JSON-RPC clients, use `RcfServer::bindJsonRpc()`.

Here is an example of a RCF server using multiple transports to accept both RCF requests and JSON-RPC requests:

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
        RCF_METHOD_V1(void, Print, const std::string &)
    RCF_END(I_HelloWorld)

    class HelloWorldImpl
    {
    public:
        void Print(const std::string & s)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
        }

        void JsonPrint(
            const RCF::JsonRpcRequest & request,
            RCF::JsonRpcResponse & response)
        {
            // Print out all the strings passed in, and return the number of
            // characters printed.

            int charsPrinted = 0;

            const json_spirit::Array & params = request.getJsonParams();
            for (std::size_t i=0; i<params.size(); ++i)
            {
                const std::string & s = params[i].get_str();
                std::cout << "I_HelloWorld service: " << s << std::endl;
                charsPrinted += s.size();
            }

            // Return number of characters printed.
            json_spirit::mObject & responseObj = response.getJsonResponse();
            responseObj["result"] = charsPrinted;
        }
    };

    int main()
    {
        RCF::RcfInitDeinit rcfInit;

        RCF::RcfServer server;

        // Accept RCF client requests on port 50001.
        HelloWorldImpl helloWorld;
        server.bind<I_HelloWorld>(helloWorld);
        server.addEndpoint( RCF::TcpEndpoint(50001) );

        // Accept JSON-RPC requests over HTTP on port 80.
        server.bindJsonRpc(
            boost::bind(&HelloWorldImpl::JsonPrint, &helloWorld, _1, _2),
            "JsonPrint");

        server.addEndpoint( RCF::HttpEndpoint(80) )
            .setRpcProtocol(RCF::Rp_JsonRpc);

        server.start();

        // RCF clients can call Print() on port 50001.
        // ...

        // JSON-RPC clients can call JsonPrint() over HTTP on port 80.
        // ...

        return 0;
    }

For more information on JSON-RPC servers, see JSON-RPC.