Page 1 of 1

Creating callback connection established new connection.

Posted: Wed Aug 20, 2014 10:22 am
by falk
Hello,
we have an issue with the creation of callback connections as documented in http://www.deltavsoft.com/doc/rcf_user_ ... onnections.
We are working currently with version RCF 2.0.0.2685.
The callback connection makes it possible that a client can be called by the server when a connection from the client to server was established before. This works so far.
But the server and client applications uses two established connections if an additional RcfClient object is made. I have initially thought that the callback connection also uses the already established connection.

So an existing RcfClient with an established connection should be used to create callback connections. The User Guide based code

Code: Select all

// Client-side - start a callback server.
RCF::RcfServer callbackServer( RCF::TcpEndpoint(0) );
HelloWorldImpl helloWorldImpl;
callbackServer.bind<I_HelloWorld>(helloWorldImpl);
callbackServer.start();

//Client-side additional code
RcfClient<SomeInterface_Rcf> alreadyExistingClient(( RCF::TcpEndpoint(port) ));
alreadyExistingClient.simpleCallToServer();

// Client-side - create callback connection.
RcfClient<I_HelloWorld> client(( RCF::TcpEndpoint(port) ));
RCF::createCallbackConnection(client, callbackServer);
alreadyExistingClient.simpleCallToServer();
is changed to

Code: Select all

// Client-side - start a callback server.
RCF::RcfServer callbackServer( RCF::TcpEndpoint(0) );
HelloWorldImpl helloWorldImpl;
callbackServer.bind<I_HelloWorld>(helloWorldImpl);
callbackServer.start();

//Client-side additional code
RcfClient<SomeInterface_Rcf> alreadyExistingClient(( RCF::TcpEndpoint(port) ));
client.simpleCallToServer();

// Client-side - create callback connection.
RCF::createCallbackConnection(alreadyExistingClient, callbackServer);
alreadyExistingClient.simpleCallToServer(); //exception occurred here.
The alreadyExistingClient is still used as a <SomeInterface_Rcf> client with the established connection from the simpleCallToServer method call previously. But this is not possible. It seems that the established connection of the client is lost after the createCallbackConnection statement. If the client is used again as in the last line of the changed user guide code an exception occurred with the following message:
OS: 10038 - An operation was attempted on something that is not a socket.
The problem was boiled down to a method in the file Marshal.cpp in the method createCallbackConnectionImpl:

Code: Select all

void createCallbackConnectionImpl(
        ClientStub & clientStub, 
        ServerTransport & callbackServer)
    {
    RcfClient<I_CreateCallbackConnection> client(clientStub);
    client.getClientStub().setTransport( clientStub.releaseTransport() );
    client.CreateCallbackConnection();

    convertRcfClientToRcfSession(client.getClientStub(), callbackServer);
    }
It seems that the ClientStub from client.getClientStub() is destroyed when the method returns to the caller. I have added a line where the client transport is set back into the given clientStub at the end of the method:

Code: Select all

clientStub.setTransport(client.getClientStub().releaseTransport());
With this additional implementation it is still possible to use the RcfClient as the initial client object it was made at the beginning. Additionally only one tcp connection is established for the bidirectional connection on client- and server-side.

But maybe i have missed some point. I am not aware of possible side-effects with the additional statement in the file Marshal.cpp. And i have seen that in Rcf version 2.0.1 the Marshal.cpp method has changed and i have not tested this with this version. But at first look it seems to me that the problem is still there in version 2.0.1.

Kind regards
Falk

Re: Creating callback connection established new connection.

Posted: Sat Aug 23, 2014 6:08 am
by jarl
Hi Falk,

The thing to remember when you are working with callback connections, is that if you want to keep on making regular client-to-server calls, you need to setup a new RcfClient<>, which will have its own TCP connection to the server.

When you execute this code:

Code: Select all

RcfClient<I_HelloWorld> client(( RCF::TcpEndpoint(port) ));
RCF::createCallbackConnection(client, callbackServer);
, the underlying TCP connection has been moved to the callback connection and is now managed by the RcfServer. To continue making client-to-server calls, just create a new connection:

Code: Select all

RcfClient<SomeInterface_Rcf> anotherClient(( RCF::TcpEndpoint(port) ));
anotherClient.simpleCallToServer();

Re: Creating callback connection established new connection.

Posted: Mon Aug 25, 2014 6:49 am
by falk
Hi Jarl,
thanks for your response and your remarks to the topic.
But i disagree with your statement
if you want to keep on making regular client-to-server calls, you need to setup a new RcfClient<>, which will have its own TCP connection to the server.
With my experiences so far with RCF, this is not needed currently. An RcfClient is created, then it is used to make a callback connection. And then the same client object is used for regular client-to-server calls again. The thing is that the underlying tcp connection is shared by the client-to-server and server-to-client connection. When the callback connection is created, the tcp connection is taken from the client stub. And at the end the tcp connection is injected back into this client stub with the addtional statement. The callback connection created before is still usable.

Code: Select all

clientStub.setTransport(client.getClientStub().releaseTransport());
Of course it must be clear who got the responsibility of the shared tcp connection. Especially who is responsible to destroy it. My implementation relies on a wrapped RcfClient<> with its own private RcfServer for the callback connection. So it is possible to set the order of resource destroying.

Another question is, if this effort is worth it. Another tcp connection is a resource which is normally negligible. But if there are many callback connections in a software made on Rcf then the amount of tcp connections is reduced by half.
Some of the decision maker are looking after such resource acquiring and appreciate the effort :)

Re: Creating callback connection established new connection.

Posted: Tue Aug 26, 2014 12:19 pm
by falk
Hi Jarl,
well, this is embarrassing. :oops: The callback connection still established two connections, even with the addtional statement in Marshal.cpp. In my test scenario the second connection was made somewhat later on but is still created.
Somewhere in TcpAsioServerTransport (e.g. method implTransferNativeFrom) there is an assignment of the socket resource which leads to the need of another connection creation.

I think there is currently no way (at least no simple) to create bidirectional connection over one socket.
I apologize for this noise on the support forum : :?

Kind regards
Falk

Re: Creating callback connection established new connection.

Posted: Tue Sep 02, 2014 7:05 am
by jarl
No problem Falk :)

You're right that currently the code does not support bidirectional communication over a single TCP connection. This would require some restructuring in the codebase, and for now I'm not sure it's worth the effort.