> {quote:title=Remy Lebeau (TeamB) wrote:}{quote}
> > So I was studying the multicast RFC 1112 and Steve Deering's articles
> > on the subject, and I must conclude that the Indy implementation (or
> > at least what you say in your earlier response to me) is not really
> > correct.
>
> I assure you, it is.
I appreciate your deep knowledge, but I am really not convinced that you are right this time.
As I mentioned before, I believe that you must *_NOT_* bind the socket to a specific interface IP; rather you bind it to IN_ADDR_ANY and then call IP_ADD_MEMBERSHIP on the socket explicitly for each specific physical NIC IP. (A side benefit of this is that you only need one socket to explicitly listen for multicasts on several NICs).
My code is listed below. And this seems now to work fine...
{code}
{ TUdpSocket }
function TUdpSocket.Bind(const AHost: string; APort: Word): boolean;
var
Lrec: TSockAddr;
begin
FillChar(Lrec, SizeOf(Lrec), #0);
Lrec.sin_family := AF_INET;
Lrec.sin_port := htons(APort);
Lrec.sin_addr.S_addr := AddrHostToNet(AHost);
Result := SocketOk and
(IdWinsock2.Bind(FSocket, @Lrec, sizeof(Lrec)) <> SOCKET_ERROR);
end;
function TUdpSocket.Connect: boolean;
begin
FSocket := Socket(AF_INET, SOCK_DGRAM, 0);
Result := SocketOk;
end;
constructor TUdpSocket.Create;
begin
inherited;
FSocket := INVALID_SOCKET;
end;
procedure TUdpSocket.SetActive(const Value: boolean);
begin
if Value <> Active then
begin
if Value then
begin
if not Connect then
begin
FSocket := INVALID_SOCKET;
raise Exception.CreateFmt('SetConnected() Error "%u"', [WSAGetLastError]);
end;
end
else Disconnect;
end;
end;
function TUdpSocket.SetReuseAddr(AValue: boolean): boolean;
var
LoptVal: Integer;
begin
LoptVal := Ord(AValue);
Result := SocketOk and
Success(SetSockOpt(FSocket, SOL_SOCKET, SO_REUSEADDR, @LoptVal, sizeof(LoptVal)));
function TUdpSocket.JoinMulticastGroup(const AHost: string; const AInterface: string): boolean;
var
LoptVal: ip_mreq;
begin
FillChar(LoptVal, SizeOf(LoptVal), #0);
LoptVal.imr_multiaddr.S_addr := AddrHostToNet(AHost);
LoptVal.imr_interface.S_addr := AddrHostToNet(AInterface);
Result := SocketOk and
Success(SetSockOpt(FSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, @LoptVal, sizeof(LoptVal)));
end;
function TUdpSocket.SocketOk: boolean;
begin
Result := FSocket <> INVALID_SOCKET;
end;
function TUdpSocket.Success(AResult: Integer): boolean;
begin
Result := AResult <> SOCKET_ERROR;
end;
{ TMulticastListener }
function TMulticastListener.Connect: boolean;
var
i: Integer;
LInterfaces: TStringList;
begin
Result := inherited
and SetReuseAddr(True)
and Bind('', FMulticastPort);
if Result then
begin
LInterfaces := TStringList.Create;
try
GStack.AddLocalAddressesToList(LInterfaces);
for i := 0 to LInterfaces.Count - 1 do
Result := Result and JoinMulticastGroup(FMulticastGroup, LInterfaces[i]);
finally
LInterfaces.Free;
end;
end;
if Result then
begin
FThread := TMulticastListenerThread.Create(self);
FThread.Start;
end;
end;
constructor TMulticastListener.Create;
begin
inherited;
FMulticastGroup := '239.255.255.250';
FMulticastPort := 1900;
end;
{code}
--
Regards,
AndrewFG