RTC Forums
November 25, 2024, 04:51:45 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1] 2
  Print  
Author Topic: Using proxy...  (Read 14090 times)
Director
Newbie
*
Posts: 24


« on: January 07, 2010, 08:50:40 PM »

Initial data:
1. A client which uses RTC SDK
2. Two TRtcHttpClient objects on the DataModule - first works in sync. mode, second works in async. mode
3. Now client use only direct connection to the server

It is required to make connection through a proxy (with fully custom proxy settings: address, port, login, pass) and to keep old functionality.

When I try set UseProxy=True and setup UserLogin property client freezes on first remote call. Change of property UseWinHTTP does not change this result (moreover RTC always uses TWinHttpProv even when UseWinHTTP=False)

What it is necessary to change to use a proxy?
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: January 07, 2010, 09:40:46 PM »

WinHttp API is used if you enter proxy parameters. If you leave proxy parameters empty and set "useProxy" to TRUE, WinInet API is used. WinHttp as well as WinInet APIs are *blocking*.

If you want non-blocking behavior when using WinInet or WinHTTP APIs, set the MultiThreaded property to TRUE and make sure your code is thread-safe.

PS. WinInet API has a limit of maximum 2 active physical connections at a time, so do NOT use more than 2 TRtcHttpClient components if you need to use the WinInet API.

Best Regards,
Danijel Tkalcec
Logged
Director
Newbie
*
Posts: 24


« Reply #2 on: January 07, 2010, 10:27:34 PM »

OK, WinHTTP is blocking... I try to call remote function synchronously.

1 example:
Code:
RtcHTTPClient.MultiThreaded:=False;
RtcHTTPClient.UseProxy:=True
RtcHTTPClient.UserLogin.ProxyAddr:='...';
RtcHTTPClient.UserLogin.ProxyLogin:='...';
RtcHTTPClient.UserLogin.ProxyPassword:='...';

RtcClientModule.Data.Clear;
RtcClientModule.Data.NewFunction('...').asString:='...';
RtcClientModule.Call(RtcResult);
RtcClientModule.WaitForCompletion(False);    <----  infinite freeze
PrepareAnswer;
with RtcClientModule.Execute is the same situation/


2 example:
Code:
RtcHTTPClient.MultiThreaded:=False;
RtcHTTPClient.UseProxy:=True
RtcHTTPClient.UserLogin.ProxyAddr:='...';
RtcHTTPClient.UserLogin.ProxyLogin:='...';
RtcHTTPClient.UserLogin.ProxyPassword:='...';

RtcClientModule.Data.Clear;
RtcClientModule.Data.NewFunction('...').asString:='...';
RtcClientModule.Call(RtcResult);
PrepareAnswer;   <--- RtcResult.OnResult doesn't fired and RtcResult.isType always rtc_Null

What's wrong? And how it will be correct?
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #3 on: January 07, 2010, 10:38:20 PM »

1) If that is the complete source code, then you are not doing anything to get a connection opened, because of which your remote function call can not be sent out and WaitForCompletion can wait forever. In other words, I don't see a line setting "RtcHTTPClient.AutoConnect" to TRUE, nor a line calling "RtcHTTPClient.Connect" to get the connection open.

2) WaitForCompletion function currently does not recognize a scenario where you forget to open a connection, which is causing an endless loop in WaitForCompletion, because the request will never get sent out nor cancelled. And this ends up in your application freezing - unless you use a timeout value in WaitForCompletion. I am aware of this limitation in the WaitForCompletion function and should have a fix ready in a couple of days to avoid application freezing in such and simular situations. The result of this fix will be that the WaitForCompletion function (as well as the new "Execute" function) will return immediately with an error state.

PS. If you want to use AutoConnect=TRUE, make sure you also set all ReconnectOn properties to TRUE.

Best Regards,
Danijel Tkalcec
Logged
Director
Newbie
*
Posts: 24


« Reply #4 on: January 07, 2010, 11:29:44 PM »

Of course connection is established  Smiley

First part of each example executes in DataModuleCreate(), second part - in RtcHTTPClientConnect().

Unfortunately you has not answered what variant is correct...
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #5 on: January 07, 2010, 11:38:31 PM »

1) How are you opening the connection? I don't see any code which would open a connection.

2) You should NEVER EVER use the WaitForCompletion method inside an event triggered by the RTC SDK, or from a method called from an event triggered by the RTC SDK. NEVER! This will ALWAYS result in your application freezing infinitely. WaitForCompletion can ONLY be used from the main thread (provided the thread was NOT synchronized from a RTC SDK event) or from a background thread created by you manually. The reason for this is simple. If you use WaitForCompletion from an event triggered by the RTC SDK, you will be blocking further RTC SDK code execution and what ever you expect the RTC SDK components to do will NOT start until the event exists.

In other words, you can call the remote function and use WaitForCompel from DataModule's OnCreate event, but you should NEVER use WaitForCompletion from the RtcHttpClient.OnConnect event NOR from any other event triggered by the RTC SDK.

Best Regards,
Danijel Tkalcec
Logged
Director
Newbie
*
Posts: 24


« Reply #6 on: January 08, 2010, 12:03:11 AM »

You should NEVER EVER use the WaitForCompletion method inside an event triggered by the RTC SDK
OK, I have understood it  Smiley



I wrote simple fully functionally example:

Quote
procedure TMain.ButtonClick(Sender: TObject);
begin
  RtcHTTPClient.ServerAddr := '...';
  RtcHTTPClient.ServerPort := '...';

  RtcHTTPClient.UseProxy:=True;
  RtcHTTPClient.UserLogin.ProxyAddr     := '...';
  RtcHTTPClient.UserLogin.ProxyUserName := '...';
  RtcHTTPClient.UserLogin.ProxyPassword := '...';

  RtcHttpClient.Connect
end;


procedure TMain.RtcHttpClientConnect(Sender: TRtcConnection);
 begin
  with RtcClientModule.Prepare('...')
   do   begin
         asString['Alias']     := '...';
         asInteger['AppID']    := ...;
        end;
  RtcClientModule.Call(RtcResult);
  ShowMessage('Function called')
 end;


procedure TMain.RtcResultReturn(Sender: TRtcConnection; Data, Result: TRtcValue);
 begin
  ShowMessage('Result recieved'+#13#10+Result.toCode)
 end;

All components properties set to defaults, except RtcClientModule.Client and RtcClientModule.ModuleFileName (RTC SDK v3.44).

When I press the Button at first there is a message "Function called", and then (after some seconds) - "Result recieved". How it is possible if WinHTTP is blocking? And how can I make really sync. call remote function with proxy? (RtcHttpClient.Blocking:=True does not help)
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #7 on: January 08, 2010, 12:11:54 AM »

Here is the same example using blocking implementation ...

procedure TMain.ButtonClick(Sender: TObject);
begin
  RtcHTTPClient.ServerAddr := '...';
  RtcHTTPClient.ServerPort := '...';

  RtcHTTPClient.UseProxy:=True;
  RtcHTTPClient.UserLogin.ProxyAddr     := '...';
  RtcHTTPClient.UserLogin.ProxyUserName := '...';
  RtcHTTPClient.UserLogin.ProxyPassword := '...';

  RtcHttpClient.Connect;

  with RtcClientModule.Prepare('...')
   do   begin
         asString['Alias']     := '...';
         asInteger['AppID']    := ...;
        end;
  RtcClientModule.Execute;
  ShowMessage('Result recieved'+#13#10+RtcClientModule.LastResult.toCode);
end;

No events, just use "Execute" and you have access to the result through the RtcClientModule.LastResult property, which will remain available there until you make the next call. The only difference is that no events are being written and no messages are displayed from inside events (which is also one of the things you should NOT do. Do NOT open message dialogs from events triggered by the RTC SDK).

Best Regards,
Danijel Tkalcec
Logged
Director
Newbie
*
Posts: 24


« Reply #8 on: January 08, 2010, 12:52:37 AM »

Your decision approaches for beginners, who starts new project. But if there are some ready projects which need to be updated for work via a proxy such decision will force to alter a lot of code... Is there any other, "old-style", variant of work (with additional components and events)?
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #9 on: January 08, 2010, 01:02:10 AM »

If you do not use WaitForCompletion or the new blocking Execute method from inside events triggered by the RTC SDK, all you have to do is set the useProxy property to TRUE and your project will be working with a proxy. But if you have been calling remote functions from inside events triggered by the RTC SDK, then you should update your code because this is something you should not do if you want your code to continue working with all future RTC SDK updates.

If you want your code to be non-blocking and you are only using remote functions, you can easily enable non-blocking behavior by setting the RtcHttpClient.MultiThreaded:=True and RtcClientModule.AutoSyncEvents:=True. This will make your code work as close as possible to the asynchronous mode and you will not have to worry about multi-threading.

Best Regards,
Danijel Tkalcec
Logged
Director
Newbie
*
Posts: 24


« Reply #10 on: January 08, 2010, 01:42:04 AM »

Code:
RtcHttpClient.Connect;

with RtcClientModule.Prepare('...')
 do   begin
      end
Let's consider these lines. What will be if connection is not installed? How I can learn about it before call Prepare and Execute?
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #11 on: January 08, 2010, 01:48:33 AM »

when using WinInet or WinHTTP API, there are no physical connections established when you call Connect. Instead, the component is prepared for use and is put into "connected" state. Only after you prepare and send a remote call will you know if a real physical connection was possible or not. The Execute method will raise an exception if a connection wasn't possible and your remote function data was discarded.

Please note that all the events you get when using the components in event-driven mode are still being triggered. You can still use events to monitor your connection status and other things. The only thing you should NOT do is send requests or make remote function calls from inside events triggered by RTC SDK components.

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #12 on: January 08, 2010, 01:55:08 AM »

Btw ... regardless of which API you are using I would always recommend setting AutoConnect:=TRUE and setting all ReconnectOn property values to TRUE on the TRtcHttpClient component instead of manually calling Connect and Disconnect. That way, you are allowing the connection to get closed when it is not used. If AutoConnect is FALSE and you call Connect manually, a connection will be forced to remain open until you call Disconnect, regardless of the fact if it is actually being used or not. And that generates unnecessary load on your Server.

Best Regards,
Danijel Tkalcec
Logged
Director
Newbie
*
Posts: 24


« Reply #13 on: January 08, 2010, 11:30:00 AM »

Thanks for remarks. It is interesting to me, why you do not describe similar nuances of operation in separate articles or help (all in one place)?
Logged
Director
Newbie
*
Posts: 24


« Reply #14 on: January 08, 2010, 11:40:25 AM »

And still. I have noticed one unpleasant feature in operations via a proxy. On each remote function call 2 requests are generated. The first request is referred a proxy server without "Proxy-Authorization" header (when ProxyUserName assigned), the second request already contains it.
Now I have solved this problem with code:

Code:
procedure TDataCommon.HTTPClientBeginRequest(Sender: TRtcConnection);
 begin
  with TRtcHTTPClient(Sender), UserLogin, Request
   do   if ProxyUserName<>''
         then   HeaderText:=HeaderText+CRLF+'Proxy-Authorization: Basic '+Base64Encode(ProxyUserName+':'+ProxyPassword)
 end;

What it is - a WinHTTP bug or RTC bug?
Logged
Pages: [1] 2
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.03 seconds with 17 queries.