## Remote Calls - Client-side

The client-side of a remote call is controlled through `RCF::ClientStub`. `RCF::ClientStub` controls a single connection to the server. Every `RcfClient<>` instance contains a `RCF::ClientStub`, which can be accessed by calling `getClientStub()`.

    RCF::ClientStub & clientStub = client.getClientStub();

### Remote call semantics

You can use `ClientStub::setRemoteCallSemantics()` to set the calling semantics of a remote call.

    client.getClientStub().setRemoteCallSemantics(RCF::Oneway);
    client.Print("Hello World");

    client.getClientStub().setRemoteCallSemantics(RCF::Twoway);
    client.Print("Hello World");

- Twoway calls (`RCF::Twoway`) are the default. A twoway call does not complete until the client receives a reply from the server.
- A oneway call (`RCF::Oneway`) is complete as soon as the request has been sent to the server. The server will not send any response to a oneway call.

By default a twoway call will cause the calling thread to wait until a response is received from the server. It is also possible to receive the response asynchronously, thus freeing the calling thread to perform other tasks - see Asynchronous Remote Calls. Asynchronous semantics can also be used on oneway calls, to prevent the calling thread from blocking if the local network send buffers are full.

Calling semantics can also be provided on a call-by-call basis, as the first argument of the remote call:

    client.Print(RCF::Oneway, "Hello World");
    client.Print(RCF::Twoway, "Hello World");

RCF also provides batched oneway calls, as an optimization for oneway calls. Normally, when a `RcfClient<>` is configured to make oneway calls, a network message is sent to the server for each remote call that is made. If a large number of calls are being made, batched oneway calls can be configured, allowing multiple oneway calls to be coalesced into a single network message, and subsequently executed in sequence on the server.

To configure batched oneway calls, use the `ClientStub::enableBatching()`, `ClientStub::disableBatching()` and `ClientStub::flushBatch()` functions:

    client.getClientStub().enableBatching();

    // Automatically send batch when message size approaches 50kb.
    client.getClientStub().setMaxBatchMessageLength(1024*50);
    for (std::size_t i=0; i<100; ++i)
    {
        client.Print("Hello World");
    }

    // Send final batch.
    client.getClientStub().flushBatch();

### Pinging

The `ClientStub::ping()` method can be used, to determine if the connection to the server is functional. A ping behaves exactly as a remote call with no in or out parameters, and is subject to the same timeouts.

    // Ping the server.
    client.getClientStub().ping();

### Client progress callbacks

RCF can be configured to periodically report progress to a custom client progress callback function during a twoway call. You can use the progress callback function to display a progress bar, repaint the application window, or even cancel the call itself.

    void onRemoteCallProgress()
    {
        // To cancel the call, throw an exception.
        throw std::runtime_error("Canceling remote call.");
    }

    boost::uint32_t progressCallbackIntervalMs = 500;

    client.getClientStub().setRemoteCallProgressCallback(
        boost::bind(&onRemoteCallProgress),
        progressCallbackIntervalMs);

    // While the call is in progress, onRemoteCallProgress() will be called every 500ms.
    client.Print("Hello World");

### Per-request user data

Normally the data transferred from the client to the server in a remote call is contained in the arguments of the remote call. However, you can also supply extra information in the user data field of the remote call request. Similarly, the server can send extra information to the client by setting the the user data field of the remote call response.

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

            RCF::RcfSession & session = RCF::getCurrentRcfSession();

            std::string customRequestData = session.getRequestUserData();
            std::cout << "Custom request data: " << customRequestData << std::endl;

            std::string customResponseData = "f81d4fae-7dec-11d0-a765-00a0c91e6bf6";
            session.setResponseUserData(customResponseData);
        }
    };

    client.getClientStub().setRequestUserData( "e6a9bb54-da25-102b-9a03-2db401e887ec" );
    client.Print("Hello World");
    std::string customReponseData = client.getClientStub().getResponseUserData();
    std::cout << "Custom response data: " << customReponseData << std::endl;

The user data fields can be used to implement custom authentication schemes where a token needs to be passed along as part of every remote call, but you don't want to have the token to be part of your remote call interface.

### Access to underlying transport

You can use `ClientStub::getTransport()` to access the underlying transport of a ClientStub.

    RCF::ClientTransport & transport = client.getClientStub().getTransport();

Transport level connection and disconnection from a server is normally handled automatically. However, you can also connect and disconnect manually by calling `ClientStub::connect()` and `ClientStub::disconnect()`.

    // Connect to server.
    client.getClientStub().connect();

    // Disconnect from server.
    client.getClientStub().disconnect();

You can use `ClientStub::releaseTransport()` and `ClientStub::setTransport()` to move a transport from one client stub to another:

    RcfClient<I_AnotherInterface> client2( client.getClientStub().releaseTransport() );
    client2.AnotherPrint("Hello World");
    client.getClientStub().setTransport( client2.getClientStub().releaseTransport() );
    client.Print("Hello World");

This is useful if you want to use the same connection to make calls on different interfaces.

### Copy semantics

`RCF::RcfClient<>` objects can be copied, put in containers, and so on. However, each copy of a `RcfClient<>` object will establish its own network connection to the server. So the following code will establish 3 network connections to the server:

    RcfClient<I_HelloWorld> client1(( RCF::TcpEndpoint(port) ));

    RcfClient<I_HelloWorld> client2(client1);

    RcfClient<I_HelloWorld> client3;
    client3 = client1;

    client1.Print("Hello World");
    client2.Print("Hello World");
    client3.Print("Hello World");