How do I receive a message after enabling loopback? - c

I have my multicast (udp) sender/receiver program up and running. If I use setsockopt to enable loopback with the sender like so:
if(setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0)
error("loopback failed.");
and later on I send out the message to every subscriber, how does my sender get the message that's sent out? The sender doesn't store its own IP address and Port number and sent itself a message (basically subscribing to itself) does it?
So it should be something like:
receiver1 (subscription) -> sender
receiver2 (subscription) -> sender
when it's time to send:
sender (info) -> receiver1
sender (info) -> receiver2
sender (info) -> sender? //how does this step work?
Thanks for the help :)

In your code, loop must be of type u_char, not int. Of course, this will also change the final setsockopt() parameter to have the value 1. I have no personal experience of this, but W. Richard Stevens says so in UNIX Network Programming (3rd edition), Vol. 1, Section 21.6, so it must be so.
He also says that using type int here is a common programming error.

In addition to enabling loopback (which actually may be enabled by default, according to http://tldp.org/HOWTO/Multicast-HOWTO-6.html#ss6.1), you also need to subscribe to the multicast group.
It isn't necessary to send a separate copy of the packet to each receiver. If the multicast subscriptions are correct and you're on a network that supports multicast, then a single transmission is sufficient.

Related

How can I use libpcap to filter only client packets?

I am using libpcap to capture packet with the following filter:
"tcp[tcpflags] & (tcp-syn) != 0 and not net 127.0.0.1"
But I actually want to get the packet only if the sender is the client (SYN-SENT).
Basically what I am trying to do is to get inform only for new connection and not multiple time for every connection.
Is there a way to do that?
If you only want the SYN from the client but not the SYN+ACK from the server use:
tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn

Multiple outgoing ipv6 addresses

I need to implement the following scheme (in C, however the language is not the case here):
client(192.168.1.2) <-> proxy(addr4: 192.168.1.1:1000, addr6: FE80:0000:0000:0000:0202:B3FF:FE1E:8329) <-> some_remote_host(remote_addr6)
The thing is addr6 on proxy side must be dynamically changed according to incoming ipv4 port. For example:
client connects to 192.168.1.1:1000, outgoing connection is made via addr6_0
client connects to 192.168.1.1:1001, outgoing connection is made via addr6_1
etc ...
The most straight-forward implementation would be: assign multiple static ipv6 addrs to ethernet interface and use bind() on socket before outgoing connection. The problem is that the number of incoming ports/outgoing addrs can be ~10000 (and as far as I understood recommended value for net.ipv6.conf.all.max_addresses is 32 or 64, default is 16).
The questions are:
What possible problems can I expect if I assign 10000 ipv6 addrs to one interface, I assume performance issues?
Is there a better way to achieve the goal?

How network event FD_WRITE is generated when using Event Driven Sockets?

I am working on newtwork event based socket application.
When client has sent some data and there is something to be read on the socket, FD_READ network event is generated.
Now according to my understanding, when server wants to write over the socket, there must be an event generated i.e. FD_WRITE. But how this message will be generated?
When there is something available to be read, FD_READ is automatically generated but what about FD_WRITE when server wants to write something?
Anyone who can help me with this confusion please?
Following is the code snippet:
WSAEVENT hEvent = WSACreateEvent();
WSANETWORKEVENTS events;
WSAEventSelect(newSocketIdentifier, hEvent, FD_READ | FD_WRITE);
while(1)
{ //while(1) starts
waitRet = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE);
//WSAResetEvent(hEvent);
if(WSAEnumNetworkEvents(newSocketIdentifier,hEvent,&events) == SOCKET_ERROR)
{
//Failure
}
else
{ //else event occurred starts
if(events.lNetworkEvents & FD_READ)
{
//recvfrom()
}
if(events.lNetworkEvents & FD_WRITE)
{
//sendto()
}
}
}
FD_WRITE means you can write to the socket right now. If the send buffers fill up (you're sending data faster than it can be sent on the network), eventually you won't be able to write anymore until you wait a bit.
Once you make a write that fails due to the buffers being full, this message will be sent to you to let you know you can retry that send.
It's also sent when you first open up the socket to let you know it's there and you can start writing.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms741576(v=vs.85).aspx
The FD_WRITE network event is handled slightly differently. An
FD_WRITE network event is recorded when a socket is first connected
with a call to the connect, ConnectEx, WSAConnect, WSAConnectByList,
or WSAConnectByName function or when a socket is accepted with accept,
AcceptEx, or WSAAccept function and then after a send fails with
WSAEWOULDBLOCK and buffer space becomes available. Therefore, an
application can assume that sends are possible starting from the first
FD_WRITE network event setting and lasting until a send returns
WSAEWOULDBLOCK. After such a failure the application will find out
that sends are again possible when an FD_WRITE network event is
recorded and the associated event object is set.
So, ideally you're probably keeping a flag as to whether it's OK to write, right now. It starts off as true, but eventually, you get a WSAEWOULDBLOCK when calling sendto, and you set it to false. Once you receive FD_WRITE, you set the flag back to true and resume sending packets.

connected udp multicast needs bind in the sender side

I have an ambiguous issue, I have a multicast group between two users one of them is a sender and another is receiver I did these scenarios in each side:
Receiver:
create a udp socket.
bind to a multicast group address
connect to the sender side ( connect(sender ip))
join the multicast group
recv from the multicast group.
Sender:
create a udp socket.
send to the multicast group.
In this scenario above when sender sent data receiver couldn't receive but if we checked the receiver side by tcpdump there is data was received from multicast group.
but if there is no connect to sender side in receiver, data will be received.
BUT Actually, If we let the sender bind to the multicast address before send to the multicast group and also receiver connect to the sender side as scenario above data will be received successfully!!!!
Any explanation when we added the bind in the sender side ???
You might want to connect(2) the sender's socket to the multicast group to speed up sending, but don't connect(2) the receiver since it restricts it to unicast (yes, it's a bit confusing, but that's how it works). Just bind(2) the receiver to the group/port, and do the setsockopt(2) with IP_ADD_MEMBERSHIP to join the group.
There is no such thing as 'connected UDP multicast'. It is is connected or it is multicast. Remove the connect() steps completely.
On the receiver side, both the bind() and connect() calls do the same thing: they associate a given Internet socket address with a given connectionless socket. For the bind() call -- in which the Internet socket address is the address of the multicast group -- this means that the socket will only receive UDP packets whose destination address is that of the multicast group. For the connect() call -- in which the Internet socket address is that of the sender -- this means that the socket will only receive UDP packets whose destination address is that of the sender, which isn't what you want.
The connect() call is overriding the bind() call, resulting in no packets being received.
Replace the bind() call with a connect() call to the multicast group and you should still receive the UDP packets -- or keep only the bind() call. It's your call.

Refresh multicast group membership

I have several embedded machines listening and streaming rtp audio data to a multicast group. They are connected to a smart managed switch (Netgear GS108Ev2) which does basic igmp snooping and multicast filtering on its ports, so that the rest of my (W)LAN doesn't get flooded.
At start everything works fine for about 500-520 seconds. After that, they don't receive any more data until they leave and join the group again. I guess the switch is "forgetting" about the join after a timeout.
Is there any way to refresh the group membership, i.e. letting the switch know, that there ist still someone listening, without losing packets?
System info:
Arch: blackfin
# cat /proc/version
Linux version 2.6.28.10-ADI-2009R1-uCBF54x-EMM
(gcc version 4.3.3 (ADI) ) #158 PREEMPT Tue Jun 5 20:05:42 CEST 2012
This is the way multicast / the IGMP protocol works. A client has to join the group periodically by sending a Membership Report or it will be assumed that he has left the group after some short timeout. However, those reports are usually sent only when receiving a Membership Query from the local multicast router. Either your clients don't receive the query or don't respond with a report.
Try to use a tool like wireshark in order to see which IGMP packets are sent through your network.
You need an IGMP querier to send the Membership Queries, as was already explained by scai.
If you can't configure your router to do that, you can use one of your computers. Seeing how running a full multicast routing daemon would be overkill (and I've never done that), I suggest you try to abuse igmpproxy.
First create a dummy upstream interface (this is not persistent!):
ip tap add dev tap6 mode tap
Write igmpproxy.conf:
# Dummy upstream interface.
phyint tap6 upstream ratelimit 0 threshold 1
# Local interface.
phyint eth0 downstream ratelimit 0 threshold 1
# Explicitly disable any other interfaces (yes, it sucks).
phyint NAME disabled
...
Finally start igmpproxy (as root):
igmpproxy -v /path/to/igmpproxy.conf
If your embedded devices are running linux, you need to turn off the reverse packet filter on them or they won't respond to group membership queries. In that case the upstream switch will assume there is no-one listening to that multicast and switch it off.
I had same problem, multicast on wifi was lost after 260 seconds, I solved it with my application by adding AddSourceMembership on socket.
private void StartListner(IPAddress sourceIp, IPAddress multicastGroupIp, IPAddress localIp, int port)
{
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint localEndpoint = new IPEndPoint(localIp, port);
socket.Bind(localEndpoint);
byte[] membershipAddresses = new byte[12]; // 3 IPs * 4 bytes (IPv4)
Buffer.BlockCopy(multicastGroupIp.GetAddressBytes(), 0, membershipAddresses, 0, 4);
Buffer.BlockCopy(sourceIp.GetAddressBytes(), 0, membershipAddresses, 4, 4);
Buffer.BlockCopy(localIp.GetAddressBytes(), 0, membershipAddresses, 8, 4);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddSourceMembership, membershipAddresses);
try
{
byte[] b = new byte[1024 * 2];
int length = socket.Receive(b);
}
catch { }
}
catch (Exception ex)
{
logger.Error("Exception: " + ex);
}
}

Resources