Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Dec 07 22:34
    rlebeau commented #147
  • Dec 07 14:17
    aminalinezhad commented #368
  • Dec 07 14:15
    aminalinezhad commented #368
  • Dec 07 14:13
    aminalinezhad commented #368
  • Dec 07 06:02
    drtimothyjennings commented #147
  • Dec 06 15:28
    webaddicto commented #390
  • Dec 06 15:27
    webaddicto commented #390
  • Dec 02 17:36
    rlebeau edited #392
  • Dec 01 19:05
    rlebeau opened #392
  • Dec 01 19:05
    rlebeau labeled #392
  • Dec 01 19:05
    rlebeau milestoned #392
  • Dec 01 19:05
    rlebeau labeled #392
  • Dec 01 01:43
    rlebeau edited #181
  • Nov 30 15:37
    webaddicto commented #390
  • Nov 30 15:27
    webaddicto commented #390
  • Nov 30 14:10
    dhewg commented #299
  • Nov 30 13:32
    mezen synchronize #299
  • Nov 29 19:27
    rlebeau edited #391
  • Nov 29 19:27
    rlebeau labeled #391
  • Nov 29 19:27
    rlebeau labeled #391
DelphiWorlds
@DelphiWorlds
ok.. I need multicast because IPv6 is involved
procedure TNetworkingModel.ConfigureUDPBindings(const AListener: TIdIPMCastClient);
var
LHandle: TIdSocketHandle;
I: Integer;
begin
AListener.Bindings.Clear;
for I := 0 to FLocalAddresses.Count - 1 do
begin
LHandle := AListener.Bindings.Add;
LHandle.IPVersion := FLocalAddresses.Addresses[I].IPVersion;
LHandle.IP := FLocalAddresses.Addresses[I].IPAddress;
LHandle.Port := AListener.DefaultPort;
end;
end;
oops
not that good with gitter
procedure TNetworkingModel.ConfigureUDPBindings(const AListener: TIdIPMCastClient);
var
  LHandle: TIdSocketHandle;
  I: Integer;
begin
  AListener.Bindings.Clear;
  for I := 0 to FLocalAddresses.Count - 1 do
  begin
    LHandle := AListener.Bindings.Add;
    LHandle.IPVersion := FLocalAddresses.Addresses[I].IPVersion;
    LHandle.IP := FLocalAddresses.Addresses[I].IPAddress;
    LHandle.Port := AListener.DefaultPort;
  end;
end;
that's how I'm configuring the bindings
DelphiWorlds
@DelphiWorlds
if I don't attempt to bind the IPv6 addresses, no error
DelphiWorlds
@DelphiWorlds
TIdIPMCastServer also errors if attempting a Send on an IPv6 address

Debugger Exception Notification

Project dyld_sim raised exception class EIdSocketError with message 'Socket Error # 49

Cannot assign requested address.'.

Break Continue Help

DelphiWorlds
@DelphiWorlds
even if I ignore the IPv6 addresses, my client (192.168.56.100) doesn't receive a broadcast from the server (192.168.56.1)
Remy Lebeau
@rlebeau
@DelphiWorlds how are you sending the broadcast? What does that code look like?
DelphiWorlds
@DelphiWorlds
Francesco Marano may have given me a solution in the forums.. the thread starts here:
https://forums.embarcadero.com/message.jspa?messageID=887844&tstart=0
I neglected to consider that the IPMCast classes have their own IPVersion property, as well as MulticastGroup property.. doh
DelphiWorlds
@DelphiWorlds
if you read Francesco's last reply, his example code works on Windows, fails on iOS.. same error
It fails when setting the client active
DelphiWorlds
@DelphiWorlds
TIdStackVCLPosix.GetLocalAddressList fails to retrieve any addresses for me on my Android 7 device, so I've created this Gist, in case it's of any use:
https://gist.github.com/DelphiWorlds/0733b6611707c8d5725ee42fd1ae01fd
Remy Lebeau
@rlebeau
@DelphiWorlds TIdStackVCLPosix.GetLocalAddressList() being broken on Android is a known issue. There are comments to that effect in the code. I stay away from using Embarcadero's JNI Bridge interfaces because 1) they are not portable (they only work in Delphi, not in FreePascal), and 2) there are threading issues related to accessing Java objects in native code, so I try to stick with native solutions. Which I have not implemented for Android yet.
DelphiWorlds
@DelphiWorlds
ok.. no clues about what might be causing the failure on iOS? I'm also having problems attempting to broadcast on each IP address.. for some reason or another using a loop it broadcasts only on the last address
procedure TForm1.SendBroadcast(const AServer: TIdIPMCastServer; const ABroadcast: string);
var
  I: Integer;
begin
  for I := 0 to FLocalAddresses.Count - 1 do
  begin
    if FLocalAddresses[I].IPVersion = AServer.IPVersion then
    begin
      AServer.Active := False;
      AServer.BoundIP := FLocalAddresses[I].IPAddress;
      AServer.BoundPort := AServer.Port;
      AServer.Active := True;
      AServer.Send(ABroadcast);
    end;
  end;
end;
Remy Lebeau
@rlebeau
@DelphiWorlds I'm not a multicast expert, or an iOS user, I can't tell you why it fails on iOS. What is the actual error? On which line of code? Where are you setting AServer.MulticastGroup? Is that group valid on all networks you are trying to bind to?
DelphiWorlds
@DelphiWorlds
I posted the error earlier, and it occurs when attempting to set Active to True on the TIdIPMCastClient
Remy Lebeau
@rlebeau
@DelphiWorlds the code above is server, not client. Do you have problems if you use a separate TIdIPMCastServer for each local IP, instead of binding and re-binding a single TIdIPMcastServer over and over?
DelphiWorlds
@DelphiWorlds
I mean earlier than that
For now I'll assume it's because the MulticastGroup value is invalid.. I'm far from a multicast expert, too ;-)
Remy Lebeau
@rlebeau
@DelphiWorlds What is the EXACT error? What does the EXACT call stack look like when the error is raised?
DelphiWorlds
@DelphiWorlds
I posted the exact error message earlier.. one moment and I'll have a call stack
Exact error message again:
Project dyld_sim raised exception class EIdSocketError with message 'Socket Error # 49
Cannot assign requested address.'.
Call stack:
System._DbgExcNotify(0,$C9B3010,$909364 {'EIdSocketError'},$6306C8,nil)
System.NotifyReRaise
:00017cc7 NotifyReRaise + $13
IdStack.TIdStack.RaiseSocketError(49)
IdStack.TIdStack.RaiseLastSocketError
IdStack.TIdStack.CheckForSocketError(-1)
IdStackVCLPosix.TIdStackVCLPosix.SetSocketOption(9,41,12,(no value),20)
IdStackBSDBase.TIdStackBSDBase.MembershipSockOpt(9,???,'0:0:0:0:0:0:0:0',12,Id_IPv6)
IdStackBSDBase.TIdStackBSDBase.AddMulticastMembership(9,'FF01:0:0:0:0:0:0:1','0:0:0:0:0:0:0:0',Id_IPv6)
IdSocketHandle.TIdSocketHandle.AddMulticastMembership('FF01:0:0:0:0:0:0:1')
:00633c46 TIdSocketHandle.AddMulticastMembership + $3A
IdIPMCastBase.TIdIPMCastBase.SetActive(True)
Multicast.TMulticastModule.EnableServices(True)
Multicast.TMulticastModule.Create($D820800)
the same code works on Windows.. but I'm guessing that may be irrelevant given differences in OS
Remy Lebeau
@rlebeau
@DelphiWorlds The error is coming from setsockopt() when adding a local IP to the multicast group, which is done after the socket is bound locally. The local IP that is being passed in is 0:0:0:0:0:0:0 (aka in6addr_any), which comes from the TIdSocketHandle.IP property, which is updated after binding. If the socket is bound to a specific local IP and not to in6addr_any, the TIdSocketHandle.IP property should not be all zeros. That implies a possible failure in TIdSocketHandle.UpdateBindingLocal(). But no matter, because the local IP is not currently being passed to setsockopt(IPV6_ADD_MEMBERSHIP) in IPv6, it is set to the default multicast interface instead. Maybe that is what iOS is complaining about.
DelphiWorlds
@DelphiWorlds
I see what you mean (from MembershipSockOpt)
DelphiWorlds
@DelphiWorlds
Some information here:
https://forums.developer.apple.com/message/71107
I'm still digesting it...
Looks like the interface number does matter
DelphiWorlds
@DelphiWorlds
...or not? seems to be conflicting info on the 'net..
mezen
@mezen

I have still problems with HTTP and NTLM Proxy :( IdAuthenticationNTLM, IdAuthenticationSSPI, IdAuthenticationDigest are used in the interface uses section
For debugging I created event handler for every event of TIdHTTP with logging all method parameters.
First OnStatus (with hsConnecting) will be fired, then OnStatus again (with hsConnected), OnHeadersAvailable, OnWorkBegin (AWorkCountMax = 2609), OnWork (AWorkCount = 2609) and OnWorkEnd as last... No OnProxyAuthorization or OnSelectProxyAuthorization is called!
The received header is

Proxy-Authenticate: Negotiate
Proxy-Authenticate: NTLM
Date: Tue, 06 Jun 2017 09:07:12 GMT
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset="UTF-8"
Content-Length: 2609
Accept-Ranges: none
Proxy-Connection: keep-alive

The component will be created via

  LHttp := TIdHTTP.Create(nil);
  LHttp.ProxyParams.ProxyServer := LProxy.ProxyServer;
  LHttp.ProxyParams.ProxyPort := LProxy.ProxyPort;
  if LProxy.UseAuthentification then
  begin
    LHttp.ProxyParams.BasicAuthentication := True;
    LHttp.ProxyParams.ProxyUsername := LProxy.Username;
    LHttp.ProxyParams.ProxyPassword := LProxy.Password;
  end;
  LHttp.Request.UserAgent := 'My Client ' + CVersion; // WebServer will always accept this user agent
  LHttp.OnAuthorization := HTTP1Authorization;
  LHttp.OnChunkReceived := HTTP1ChunkReceived;
  LHttp.OnConnected := HTTPConnected;
  LHttp.OnDisconnected := HTTPDisconnected;
  LHttp.OnHeadersAvailable := HTTP1HeadersAvailable;
  LHttp.OnProxyAuthorization := HTTP1ProxyAuthorization;
  LHttp.OnRedirect := HTTP1Redirect;
  LHttp.OnSelectAuthorization := HTTP1SelectAuthorization;
  LHttp.OnSelectProxyAuthorization := HTTP1SelectProxyAuthorization;
  LHttp.OnStatus := HTTP1Status;
  LHttp.OnWork := HTTP1Work;
  LHttp.OnWorkBegin := HTTP1WorkBegin;
  LHttp.OnWorkEnd := HTTP1WorkEnd;

  LHttp.Get(LUrl, LFileStream, [CAccepted_WebServerResponses]);

Did I miss something?
I also have Wireshark logs of the Get-Trys. The first Get from Indy sends already a Proxy-Authorization in Basic, is that correct? But Answer is always HTTP/1.1 407 Proxy Authorization required and there is no more traffic, no second attampt is maded. My biggest problem is, I have no test enviremont. Every change I do, I have to create a new binary and give it to a customer (which knows that they are experimental and, for now, is happy to be a alpha tester).

DelphiWorlds
@DelphiWorlds
which version of Indy?
mezen
@mezen
The one shipped with Delphi Berlin
DelphiWorlds
@DelphiWorlds
are you unable to debug this yourself? if the result is 407, the OnSelectProxyAuthorization event should be called, unless MaxAuthRetries is exceeded.. what do you have that set to?
actually, equal to, or exceeded
mezen
@mezen
Nop, I have no proxy which requires NTLM authentication, so I cant debug, only building binaries and give it to my customer :(
MaxAuthRetries is unchanged, so it should still be on 3 (as Indy default)
I also tried to send a second GET after the first failed one with MauxAuthRetries = 42. No success :(
(Only a lot of more traffic in the wireshark log, but all the same as the first try: Indy only sends a GET with basic authentication and proxy answers with 407)
Remy Lebeau
@rlebeau
@mezen try setting BasicAuthentication to false. You are setting it to true, which gives TIdHTTP permission to send Basic authentication requests. That is not what the proxy is asking for.
mezen
@mezen
Is it possible to determine before connecting if BasicAuthentication should be false? Or is it more like try and error? First try with Basic, if it is not successful do a second try without Basic?
mezen
@mezen
And when should I set hoInProcessAuth in HTTPOptions?
Remy Lebeau
@rlebeau
@mezen BasicAuthentication has to be set before you send a request, since it helps govern the type of authentication sent in the request. The only way to determine the server's desired authentication type(s) is to send a request, even if just HEAD, and see how the server responds. The authentication(s) are specified in the response's WWW-Authenticate and Proxy-Authenticate headers. If you plan on having TIdHTTP handle authentication, hoInProcessAuthshould always be set. At the very least, it needs to be set before the response is parsed, so you could set it dynamically in the OnHeadersAvailable event, for instance. If hoInProcessAuth is not set, you have to handle authentication manually by checking the TIdHTTP.ResponseCode and then setting the TIdHTTP.Request.Authentication or TIdHTTP.Request.CustomHeaders.Values['Authorization'] on the next request.
mezen
@mezen
Or, now tried this: First GET request is as shown above. If I get a 407 back I set hoInProcessAuth = True and BasicAuthentication = Falseand retry the GET request.
Wireshark now says Indy send 4 (MaxAuthRetries is still on default = 3) request instead of 1. Every request still has a basic proxy-authorization set.
mezen
@mezen
Difference in calling of the Events after changing the options is: No OnStatus will be called, only OnHeadersAvailable , OnWorkBegin, OnWork and OnWorkEnd. Still no calls of OnProxyAuthorizationor OnSelectProxyAuthorization.
Remy Lebeau
@rlebeau
@mezen TIdHTTP will not send a BASIC request unless BasicAuthentication=True, or the server actually requests Basic in WWW-Authenticate or Proxy-Authenticate, or you force Request.Authentication or ProxyParams.Authentication to TIdBasicAuthentication directly. When TIdHTTP receives 407, the only ways that OnSelectProxyAuthorization would not be triggered are either 1) AuthProxyRetries has exceeded MaxAuthRetries, or 2) ProxyParams.Authentication is already assigned an auth class. After an auth class has been assigned, the only ways that OnProxyAuthorization would not be triggered are either 1) ProxyParams.ProxyPassword is blank, or 2) the authentication class doesn't request user input (TIdAuthentication.Next() does not return wnAskTheProgram). You are going to have to step into Indy's souce code with the debugger to figure out what TIdHTTP is really doing during its 407 processing. TIdHTTP should be handling the retry requests for you. Make sure the credentials you are using are accurate. If they are not working, maybe the NTLM request is being malformed, so the proxy keeps rejecting it.