• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 521
  • Last Modified:

IP MultiCasting & Interface selection problem...

Let's say I have 4 ethernet cards installed and I am using IP MultiCasting. When I receive data there's no problem. But if I try to send data using sendto() I am getting problem. Is there a way to select interface to send data? Is it possible to do that with setsockopts() or using iphlpapi (routing) ? Can someone please send me a sample?

Regards,
0
Dumani
Asked:
Dumani
1 Solution
 
steve_hskCommented:
Hi Dumani ...

This is something I overcome on a monthly basis, and is a very common problem. There are different ways from which to approach this, my favourite being by IP Address.

If you have 4 different Ethernet cards, you must be connected to 4 different networks, each with a different (list of) IP address(es).

When you create the socket, you must bind it before you can communicate. If you select the IP address you want to bind to, this represents the network card and attached subnet.

If you want the user to be able to select at run-time which network to communicate with (like a network monitor), then you can use the IP Helper API (IPHlpAPI) to produce a network card list. You can retrive the IP addr from that card, and then perform your bind operation.

I can provide examples of a simple bind, or an IPHlpAPI example (IP Addr ADD, Retrive, remove)(route add, retrieve, remove)(network interface list).

Need to know a little more about what you're trying to acheieve, as each example can be quite lengthy ???

PS ... It can get more conveinient sometimes, by adding multiple alias IP addresses to a single network interface, which depending on your network, can provide you with some better design options.

Hope this helps,
Steve
0
 
DumaniAuthor Commented:
Thanks for your comment but I have bind my ethernet ip which did not work. I can get ethernet list using iphlpapi. I don't have any problems with it. However i can not seelct the ethernet i want to use during runtime. If you please give me an example on how to select it would be perfect.
0
 
steve_hskCommented:
Hi Dumani ...

If your bind did not work, then I would have thought that the problem would be with the bind statement and the necessary parameters. Eg you may have an incorrect IP address, or you may not have any IP address, or Winsock may not have been initialised, etcetc...

I Can check this code if you wish. Otherwise the IPHlpAPI example to provide a list of network cards and their details, including IP addresses :-

This just a button and a memopad on a form :-

uses
  IPExport,
  IPHlpApi,
  Iprtrmib,
  IpTypes,
  Winsock;


procedure VVGetNetworkParams(var p: PfixedInfo; var OutBufLen: Cardinal);
var
  Res: DWORD;
begin
  p := Nil;
  OutBufLen := 0;
  if @GetNetworkParams = Nil then
    raise EIpHlpError.CreateFmt(sNotImplemented, ['GetNetworkParams']);
  Res := GetNetworkParams(p, OutBufLen);
  if Res = ERROR_BUFFER_OVERFLOW then
  begin
    Getmem(p, OutBufLen);
    FillChar(p^, OutBufLen, #0);
    Res := GetNetworkParams(p, OutBufLen);
  end;
  if Res <> 0 then
    IpHlpError('GetNetworkParams', Res);
end;

procedure VVGetPerAdapterInfo(IfIndex: Cardinal; var p: PIpPerAdapterInfo;
  var OutBufLen: Cardinal);
var
  Res: DWORD;
begin
  p := Nil;
  OutBufLen := 0;
  if @GetPerAdapterInfo = Nil then
    raise EIpHlpError.CreateFmt(sNotImplemented, ['GetPerAdapterInfo']);
  Res := GetPerAdapterInfo(IfIndex,p, OutBufLen);
  if Res = ERROR_BUFFER_OVERFLOW then
  begin
    Getmem(p, OutBufLen);
    FillChar(p^, OutBufLen, #0);
    Res := GetPerAdapterInfo(IfIndex,p, OutBufLen);
  end;
  if Res <> 0 then
    IpHlpError('GetPerAdapterInfo', Res);
end;

procedure TFmIpTest.BtGetAdaptersInfoClick(Sender: TObject);
var
  PAdapter, PMem: PipAdapterInfo;
  pPerAdapter: PIpPerAdapterInfo;
  PIPAddr: PIpAddrString;
  OutBufLen, OutBufLen2: ULONG;
  s: string;
  i: integer;
begin
  Memo1.Lines.Add('GetAdaptersInfo');
  VVGetAdaptersInfo(PAdapter, OutBufLen);
  PMem := PAdapter;
  try
    while PAdapter <> nil do
      with Memo1.Lines do
      begin
        Add('AdapterName: ' + PAdapter.AdapterName);
        Add('Description: ' + PAdapter.Description);
        s := '';
        for i := 0 to PAdapter.AddressLength do
          s := s + Format('%1d', [PAdapter.Address[i]]);
        Add('Index: ' + IntToStr(PAdapter.Index));
        Add('Type: ' + IntToStr(PAdapter.Type_));
        Add('DhcpEnabled: ' + IntToStr(PAdapter.DhcpEnabled));
        if PAdapter.CurrentIpAddress <> nil then
        begin
          Add('CurrentIpAddress.IpAddress:' + PAdapter.CurrentIpAddress.IpAddress.S);
          Add('CurrentIpAddress.IpMask:' + PAdapter.CurrentIpAddress.IpMask.S);
        end
        else
          Add('CurrentIpAddress: nil');
        PIPAddr := @PAdapter.IpAddressList;
        repeat
          Add('-----------');
          Add('IpAddressList.IpAddress ' + PIPAddr.IpAddress.S);
          Add('IpAddressList.IpMask ' + PIPAddr.IpMask.S);
          PIPAddr := PIPAddr.Next;
        until PIPAddr = nil;
        Add('-----------');
        try
          Memo1.Lines.Add('GetPerAdapterInfo');
          VVGetPerAdapterInfo(PAdapter.Index, pPerAdapter,OutBufLen2);
          if pPerAdapter <> nil then
            try
              Add('AutoconfigEnabled: ' + IntToStr(pPerAdapter.AutoconfigEnabled));
              Add('AutoconfigActive: ' + IntToStr(pPerAdapter.AutoconfigActive));
              PIPAddr := pPerAdapter.CurrentDnsServer;
              if not Assigned(PIPAddr) then
                Add('CurrentDnsServer: nil');
              while Assigned(PIPAddr) do
              begin
                Add('CurrentDnsServer.IpAddress: ' + PIPAddr^.IpAddress.S);
                Add('CurrentDnsServer.IpMask: ' + PIPAddr^.IpMask.S);
                PIPAddr := PIPAddr.Next;
              end;
              PIPAddr := @pPerAdapter.DnsServerList;
              while Assigned(PIPAddr) do
              begin
                Add('DnsServerList.IpAddress: ' + pPerAdapter.DnsServerList.IpAddress.S);
                Add('DnsServerList.IpMask: ' + pPerAdapter.DnsServerList.IpMask.S);
                PIPAddr := PIPAddr.Next;
              end;
            finally
              Freemem(pPerAdapter,OutBufLen2);
            end;
        except
          on E:EIpHlpError do
            ShowMessage(E.Message);
        end;
        PAdapter := PAdapter.Next;
      end;
  finally
    if PAdapter <> nil then
      Freemem(PMem, OutBufLen);
  end;
end;

This code should be downloaded form :-
http://delphi-jedi.org 
http://voldemarv.virtualave.net 

Portions created by Vladimir Vassiliev are
Copyright (C) 2000 Vladimir Vassiliev. All Rights Reserved. The original file is: IpUnit1.pas, released  December 2000. The initial developer of the Pascal code is Vladimir Vassiliev voldemarv@hotpop.com                  

Contributor(s): Marcel van Brakel (brakelm@bart.nl)
                John Penman (jcp@craiglockhart.com)

I can also provide C++Builder and VC++ and other delphi examples I've written ... I think this is the easiest to understand.

Hope this helps ?!? :-)
Steve


0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
DumaniAuthor Commented:
Thanks but i don't have any problem with getting ethernet information. I need to USE selected interface to send data. That's the problem
0
 
steve_hskCommented:
That's what I've been trying to say Dumani ...

After you've decided on which interface from the list you want to use, simply pass the IP address to your bind statement, and you will then have a socket bound to that network card via the IP address.

I'm 110% sure this works.

Using the above example, take the following variable for your chosen card :-

PAdapter.CurrentIpAddress.IpAddress.S

and use it in your bind code :-

m_tpAddress   : tSockAddrIn;
m_tUDPSock    : TSocket;

m_tpAddress.sin_family      := AF_INET;
m_tpAddress.sin_port        := htons(8601);
m_tpAddress.sin_addr.S_addr := PAdapter.CurrentIpAddress.IpAddress.S;

IF (bind (m_tUDPSock, @m_tpAddress,sizeof(tSockAddrIn)) = SOCKET_ERROR) THEN
BEGIN
      // Analyse the Error if it occurs to find out why your bind fails
      Result := WSAGetLastError;
END;


Any better ;-) ?

Steve
0
 
DumaniAuthor Commented:
I am sorry but that does not work. Please try that. I have tried that millions time.
Even i try to enter manualy it did not work.
adrinfo.sin_addr.S_addr := inet_addr('192.168.0.1');
0
 
steve_hskCommented:
That's what I've been trying to say Dumani ...

After you've decided on which interface from the list you want to use, simply pass the IP address to your bind statement, and you will then have a socket bound to that network card via the IP address.

I'm 110% sure this works.

Using the above example, take the following variable for your chosen card :-

PAdapter.CurrentIpAddress.IpAddress.S

and use it in your bind code :-

m_tpAddress   : tSockAddrIn;
m_tUDPSock    : TSocket;

m_tpAddress.sin_family      := AF_INET;
m_tpAddress.sin_port        := htons(8601);
m_tpAddress.sin_addr.S_addr := PAdapter.CurrentIpAddress.IpAddress.S;

IF (bind (m_tUDPSock, @m_tpAddress,sizeof(tSockAddrIn)) = SOCKET_ERROR) THEN
BEGIN
      // Analyse the Error if it occurs to find out why your bind fails
      Result := WSAGetLastError;
END;


Any better ;-) ?

Steve
0
 
steve_hskCommented:
Oops, sorry - posted again by mistake !

what is the bind error you get from (what is result?):

IF (bind (m_tUDPSock, @m_tpAddress,sizeof(tSockAddrIn)) = SOCKET_ERROR) THEN
BEGIN
     // Analyse the Error if it occurs to find out why your bind fails
     Result := WSAGetLastError; // <<<< ?
END;

maybe this will provide a clue ?

Steve
0
 
DumaniAuthor Commented:
Steve, I don't have any error. I can bind without any problem. But that does not work. I can multicast also without any problems. I can receive data however i can not send data with specified adapter.
0
 
steve_hskCommented:
ok, now we're getting there :-) slowly ...

>> "i can not send data with specified adapter."

Well you're sending via the IP addr you're bound to, so concentrate there, not on the adapter. I don't think the IPHlpAPI has anything to do with you're problem, nor the bind nor the receive procedure obviously !!!

So lets concentrate on the sendto !

1. What error do you get when you send ?
again using sendto () = SOCKET_ERROR and then WSAGetLastError = what ? ie : what does winsock think is wrong ?

2. Can you send data to a unicast addr ... maybe to your own IP addr successfully, or is it throwing errors no matter what ?

Steve

0
 
DumaniAuthor Commented:
Data goes from other ethernet card without any problems. So data arrives because connection is not required i don't get any problems. NO SOCKET_ERROR :)
0
 
steve_hskCommented:
ok, so winsock thinks everything is peachy with Unicast and MCast IP addresses and sends the packet successfully !

So the problem is it doesn't arrive successfully ?

If so, to check : just before you send do a :
OutputDebugString(sIpAddress), and check the event log to ensure that the IP address you're using is correct.

If you have a network monitor/sniffer, you should be able to validate the packet leaving the machine.

Finally, check the routes in your routing table to ensure this packet has a path : md dos prompt :  route print.

If this is all ok, then the sending machine seems to be operating successully. It would appear the receiver is not operating as it should ?

Steve
0
 
steve_hskCommented:
ps ... just a quick thought :

If you are joining MCast groups, I'm assuming you've set the correct socket options wspjoinleaf, and created the socket with wsPsocket ?

Steve
0
 
DumaniAuthor Commented:
Steve thanks for your replies but they don't work. I found what i need and i am writing it down. Regards,

var
  localif: integer;
begin
  localif := inet_addr(PChar('192.168.0.1'));
  setsockopt(FSocket, IPPROTO_IP, IP_MULTICAST_IF, @localif, sizeof(localif));
end;
0
 
CleanupPingCommented:
Dumani:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1 
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
0
 
snehanshuCommented:
Hi!
No comment has been added lately and this question is therefore classified abandoned.

If asker wishes to close the question, then refer to
http://www.experts-exchange.com/help/closing.jsp

Otherwise, I will leave a recommendation in the Cleanup topic area that this question is:

AQ'd and pts refunded

Please leave any comments here within the next seven days. It is assumed that any participant not responding to this request is no longer interested in its final disposition.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

...Snehanshu
EE Cleanup Volunteer
0
 
moduloCommented:
PAQed, with points refunded (150)

modulo
Community Support Moderator
0

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now