"UDP datagrams only" socket in C - c

In Linux, Ubuntu 14.04:
I'm writing a code that implements socket to send pure UDP datagrams which includes UDP header+payload, without any part of IP header.
I have created the socket
sokt_fd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP)
Also, I have prepared the UDP header.
I want to leave the IP encapsulation process to the kernel.
I want to send the datagram over any available IP interface. (I do not want to specify the source IP, and also leave this task to the kernel).
Do I need to specify the destination IP address before sending the datagram.
I must use "sendto()" command to send the datagram; how I must fill the "sockaddr" data structure?
#include <netinet/in.h>
struct sockaddr
{
unsigned short sa_family;// address family, AF_xxx
char sa_data[14];// 14 bytes of protocol address
};

Don't use the sockaddr structure. Use sockaddr_in instead and cast it when you have to pass a sockaddr* to a function.
struct sockaddr_in myaddr;
int s;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(3490);
inet_aton("63.161.169.137", &myaddr.sin_addr.s_addr);
s = socket(PF_INET, SOCK_STREAM, 0);
bind(s, (struct sockaddr*)myaddr, sizeof(myaddr));
The socket API is designed for different addressing families, others are Infrared and Bluetooth. Since AF_INET is only one of the families the API functions use the general sockaddr type in the parameters.

There is a nice explanation of this in Chapter 3, "Sockets Introduction" in the well-known book Unix Network Programming, The Sockets Networking API (Volume 1) by Richard Stevens et. al. Let me quote:
Most socket functions require a pointer to a socket address structure
as an argument. Each supported protocol suite defines its own socket
address structure. The names of these structures begin with
sockaddr_ and end with a unique suffix for each protocol suite.
For the IP (Internet protocol) suite, the structure is sockaddr_in so it follows that since your example is specifying the AF_INET address family when you created the socket that you would use the more specific sockaddr_in structure instead of the more generic sockaddr. The socket API, as a matter of efficiency uses the more generic sockaddr pointer in the signature prototype.
With regard to using send() versus sendto(), I have found that sendto() is used more commonly with UDP and send() with TCP sockets. Therefore, to answer your question in #3 above, with UDP you don't have to specify the destination address up front, but instead it is supplied as an argument to sendto().
For a given udp_datagram and datagram_length, your code might look something like this:
uint32_t address = inet_addr("1.2.3.4"); // can also provide hostname here
uint16_t port = 27890;
sockaddr_in_t dest_addr;
memset(*dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr.s_addr = htonl(address);
sendto(socket_fd,
(const char*)upd_datagram,
datagram_length,
0,
reinterpret_cast<sockaddr_t*>(&dest_addr),
sizeof(dest_addr));

The address API really wanted to be object-oriented, but had to deal with the fact that C isn't an OO language. sockaddr can be seen as the "base class" and the parameter type that bind, connect, sendto, recvfrom, etc. use when they need an address. However, you must provide a "subclassed" address matching the socket domain that you're using. This is because Berkeley sockets can be used for a wide and extensible range of protocols. IPv4 and IPv6 are the most typical, but UNIX-based installs also support sockets as filesystem objects ("addressed" by path), and, for instance, a hypervisor driver can install support for special inter-VM or guest-to-host sockets. See man 7 socket for an overview.
If you use IPv4, you need to use sockaddr_in. If you use IPv6, you need to use sockaddr_in6. In both cases, you need to cast your pointer to a sockaddr*.
To fill in a sockaddr_in, you need to do something like this:
struct sockaddr_in inet_addr;
inet_addr.sin_family = AF_INET;
inet_addr.sin_port = htons(port);
inet_addr.sin_addr.s_addr = htonl(ip_address_as_number);
struct sockaddr* addr = (struct sockaddr*)&inet_addr;
htons and htonl stand for "host to network (short)" and "host to network (long)", respectively. You need this because there was a time at which network drivers were too dumb to abstract away the machine's endianness and we can't go back in time to fix them. (The network byte order is big endian.)

Related

Send Raw arp reply packet in windows

I am currently learning how to use the windows raw sockets.
I created a raw arp reply frame(includes all headers (ethernet+arp headers)), and when I send it using sendto function,
It fails and return SOCKET_ERROR with error code 10047.
The parameters I used to create the socket are as follows:
socket s = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
and also I changed the socket options as follows:
int on=1;
setsockopt(s,IPPROTO_IP, 2,(char*)&on,sizeof(on));
(By the way, '2' is equal to IP_HDRINCL, for some reason, visual studio didn't recognize it..)
I try to send the packet as follows:
socketaddr sa = { 0 };
int SentBytesCount = sendto(s, (char*)&arp_raw_msg,sizeof(Arp_Frame),0,&sa,sizeof(sa));
Where Arp_Frame is a struct that includes ethernet header+arp header+18 Bytes for padding.
After this call I get that SentBytesCount is equal to SOCKET_ERROR(-1), and no packet is sent.
Thank you for your help!
Winsock error 10047 is WSAEAFNOSUPPORT:
Address family not supported by protocol family.
An address incompatible with the requested protocol was used. All sockets are created with an associated address family (that is, AF_INET for Internet Protocols) and a generic protocol type (that is, SOCK_STREAM). This error is returned if an incorrect protocol is explicitly requested in the socket call, or if an address of the wrong family is used for a socket, for example, in sendto.
You created an AF_INET (IPv4) socket, but you are not passing sendto() a valid sockaddr_in containing an IPv4 address and port, hence the error. You are passing it an empty socketaddr (what is that?) instead.
Any sockaddr_... struct you use with a socket must match what the socket's address family expects, as set by the socket() call (in your case, AF_INET, which uses sockaddr_in addresses).
sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("destination IP address");
sa.sin_port = htons(Destination port number);
int SentBytesCount = sendto(s, (char*)&arp_raw_msg, sizeof(Arp_Frame), 0, (struct sockaddr*)&sa, sizeof(sa));
As for IP_HDRINCL, it is defined in ws2tcpip.h.

sockaddr structure - (sys/socket.h)

Ive been reading the sys/socket.h all day and finally starting to understand it, and now starting to use it, however, I'm not sure why I can't assign a value to sa_family member of the sockaddr struct.
Specification sockaddr Structure:
struct sockaddr{
sa_family_t sa_family address family
char sa_data[] socket address (variable-length data)
};
Data Type: sa_family_t - Unsigned integral type (2-4 bytes)
Values:
Name Purpose Man page
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device netlink(7)
AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK AppleTalk ddp(7)
AF_PACKET Low level packet interface packet(7)
AF_ALG Interface to kernel crypto API
Which is a bit confusing since these values are char data types not an unsigned int.
Simple Test:
#include<stdio.h>
#include<sys/socket.h>
int main(void){
struct sockaddr_in address;
address.sin_family = AF_INET;
printf("Socket Address Family: %s\n", address.sin_family);
return 0;
}
Error:
storage size of ‘address’ isn’t known
It should be printing out Socket Address Family: AF_INET... what am I missing here?
It is because you don't include the definition of that structure. The structure sockaddr_in is defined in <netinet/in.h>. For more details, see: sockaddr_in undeclared identifier

socket connect() vs bind()

Both connect() and bind() system calls 'associate' the socket file descriptor to an address (typically an ip/port combination). Their prototypes are like:-
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
and
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
What is the exact difference between 2 calls? When should one use connect() and when bind()?
Specifically, in some sample server client codes, found that client is using connect() and server is using the bind() call. Reason was not fully clear to me.
To make understanding better , lets find out where exactly bind and connect comes into picture,
Further to positioning of two calls , as clarified by Sourav,
bind() associates the socket with its local address [that's why server side binds, so that clients can use that address to connect to server.]
connect() is used to connect to a remote [server] address, that's why is client side, connect [read as: connect to server] is used.
We cannot use them interchangeably (even when we have client/server on same machine) because of specific roles and corresponding implementation.
I will further recommend to correlate these calls TCP/IP handshake .
So, who will send SYN here, it will be connect(). While bind() is used for defining the communication end point.
The one liner : bind() to own address, connect() to remote address.
Quoting from the man page of bind()
bind() assigns the address specified by addr to the socket referred to by the file descriptor sockfd. addrlen specifies the size, in bytes, of the address structure pointed to by addr. Traditionally, this operation is called "assigning a name to a socket".
and, from the same for connect()
The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr.
To clarify,
bind() associates the socket with its local address [that's why
server side binds, so that clients can use that address to connect
to server.]
connect() is used to connect to a remote [server] address, that's
why is client side, connect [read as: connect to server] is used.
I think it would help your comprehension if you think of connect() and listen() as counterparts, rather than connect() and bind(). The reason for this is that you can call or omit bind() before either, although it's rarely a good idea to call it before connect(), or not to call it before listen().
If it helps to think in terms of servers and clients, it is listen() which is the hallmark of the former, and connect() the latter. bind() can be found - or not found - on either.
If we assume our server and client are on different machines, it becomes easier to understand the various functions.
bind() acts locally, which is to say it binds the end of the connection on the machine on which it is called, to the requested address and assigns the requested port to you. It does that irrespective of whether that machine will be a client or a server. connect() initiates a connection to a server, which is to say it connects to the requested address and port on the server, from a client. That server will almost certainly have called bind() prior to listen(), in order for you to be able to know on which address and port to connect to it with using connect().
If you don't call bind(), a port and address will be implicitly assigned and bound on the local machine for you when you call either connect() (client) or listen() (server). However, that's a side effect of both, not their purpose. A port assigned in this manner is ephemeral.
An important point here is that the client does not need to be bound, because clients connect to servers, and so the server will know the address and port of the client even though you are using an ephemeral port, rather than binding to something specific. On the other hand, although the server could call listen() without calling bind(), in that scenario they would need to discover their assigned ephemeral port, and communicate that to any client that it wants to connect to it.
I assume as you mention connect() you're interested in TCP, but this also carries over to UDP, where not calling bind() before the first sendto() (UDP is connection-less) also causes a port and address to be implicitly assigned and bound. One function you cannot call without binding is recvfrom(), which will return an error, because without an assigned port and bound address, there is nothing to receive from (or too much, depending on how you interpret the absence of a binding).
bind tells the running process to claim a port. i.e, it should bind itself to port 80 and listen for incomming requests. with bind, your process becomes a server. when you use connect, you tell your process to connect to a port that is ALREADY in use. your process becomes a client. the difference is important: bind wants a port that is not in use (so that it can claim it and become a server), and connect wants a port that is already in use (so it can connect to it and talk to the server)
From Wikipedia http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29
connect():
The connect() system call connects a socket, identified by its file descriptor, to a remote host specified by that host's address in the argument list.
Certain types of sockets are connectionless, most commonly user datagram protocol sockets. For these sockets, connect takes on a special meaning: the default target for sending and receiving data gets set to the given address, allowing the use of functions such as send() and recv() on connectionless sockets.
connect() returns an integer representing the error code: 0 represents success, while -1 represents an error.
bind():
bind() assigns a socket to an address. When a socket is created using socket(), it is only given a protocol family, but not assigned an address. This association with an address must be performed with the bind() system call before the socket can accept connections to other hosts. bind() takes three arguments:
sockfd, a descriptor representing the socket to perform the bind on.
my_addr, a pointer to a sockaddr structure representing the address to bind to.
addrlen, a socklen_t field specifying the size of the sockaddr structure.
Bind() returns 0 on success and -1 if an error occurs.
Examples:
1.)Using Connect
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(){
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set the IP address to desired host to connect to */
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.17");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
recv(clientSocket, buffer, 1024, 0);
/*---- Print the received message ----*/
printf("Data received: %s",buffer);
return 0;
}
2.)Bind Example:
int main()
{
struct sockaddr_in source, destination = {}; //two sockets declared as previously
int sock = 0;
int datalen = 0;
int pkt = 0;
uint8_t *send_buffer, *recv_buffer;
struct sockaddr_storage fromAddr; // same as the previous entity struct sockaddr_storage serverStorage;
unsigned int addrlen; //in the previous example socklen_t addr_size;
struct timeval tv;
tv.tv_sec = 3; /* 3 Seconds Time-out */
tv.tv_usec = 0;
/* creating the socket */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
printf("Failed to create socket\n");
/*set the socket options*/
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
/*Inititalize source to zero*/
memset(&source, 0, sizeof(source)); //source is an instance of sockaddr_in. Initialization to zero
/*Inititalize destinaton to zero*/
memset(&destination, 0, sizeof(destination));
/*---- Configure settings of the source address struct, WHERE THE PACKET IS COMING FROM ----*/
/* Address family = Internet */
source.sin_family = AF_INET;
/* Set IP address to localhost */
source.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY = 0.0.0.0
/* Set port number, using htons function to use proper byte order */
source.sin_port = htons(7005);
/* Set all bits of the padding field to 0 */
memset(source.sin_zero, '\0', sizeof source.sin_zero); //optional
/*bind socket to the source WHERE THE PACKET IS COMING FROM*/
if (bind(sock, (struct sockaddr *) &source, sizeof(source)) < 0)
printf("Failed to bind socket");
/* setting the destination, i.e our OWN IP ADDRESS AND PORT */
destination.sin_family = AF_INET;
destination.sin_addr.s_addr = inet_addr("127.0.0.1");
destination.sin_port = htons(7005);
//Creating a Buffer;
send_buffer=(uint8_t *) malloc(350);
recv_buffer=(uint8_t *) malloc(250);
addrlen=sizeof(fromAddr);
memset((void *) recv_buffer, 0, 250);
memset((void *) send_buffer, 0, 350);
sendto(sock, send_buffer, 20, 0,(struct sockaddr *) &destination, sizeof(destination));
pkt=recvfrom(sock, recv_buffer, 98,0,(struct sockaddr *)&destination, &addrlen);
if(pkt > 0)
printf("%u bytes received\n", pkt);
}
I hope that clarifies the difference
Please note that the socket type that you declare will depend on what you require, this is extremely important
Too Long; Don't Read: The difference is whether the source (local) or the destination address/port is being set. In short, bind() set the source and connect() set the destination. Regardless of TCP or UDP.
bind()
bind() set the socket's local (source) address. This is the address where packets are received. Packets sent by the socket carry this as the source address, so the other host will know where to send back its packets.
If receive is not needed the socket source address is useless. Protocols like TCP require receiving enabled in order to send properly, as the destination host send back a confirmation when one or more packets have arrived (i.e. acknowledgement).
connect()
TCP has a "connected" state. connect() triggers the TCP code to try to establish a connection to the other side.
UDP has no "connected" state. connect() only set a default address to where packets are sent when no address is specified. When connect() is not used, sendto() or sendmsg() must be used containing the destination address.
When connect() or a send function is called, and no address is bound, Linux automatically bind the socket to a random port. For technical details, take a look at inet_autobind() in Linux kernel source code.
Side notes
listen() is TCP only.
In AF_INET family, the socket's source or destination address (struct sockaddr_in) is composed by an IP address (see IP header), and TCP or UDP port (see TCP and UDP header).

How to ping using C sockets

Compiler: Code::Blocks(GNU GCC)
Platform: Windows(x86)
Includes: winsock.h winsock2.h (ws2_32 is linked as well)
I am currently trying to write a program that will read a text file containing a list of IP-Addresses and ping each IP-Addresses respectively. If the host responds to the ping then the host's IP-Address will be copied to a seconded file specified by the user. Unfourtantly this is the first time I have used C's socket library and I cannot find a good tutorial about how to ping using C. From what I understand of the couple tutorials I did find. I need to included a ICMP header, which is a struct containg the ICMP type, code, and checksum, in a IP datagram. But I have no idea how to go about doing so, should I declare the struct myself or is it declared in a header file? I am assuming that it is in a header but the tutorials contradicted each other about exactly where it is declared. I tired including icmp.h and netinet/icmp.h but my compiler complained that they don't exist so I created my own struct.
struct echo_request
{
char type; // Type
char code; // Code
short checksum; // Checksum
short id; // Identification
short seq; // Sequence
int time; // Time
char data[16]; // Data
};
I thought that I might be able to get away with it but I wasn't even able to compile my program because my compiler says that in_cksum()(checksum generator) is undefined.
To sum up my questions, what header files should I include, how do I create a ping packet, am I using the correct checksum generator function, should a ping be directed to port 80, and should the socket I use be RAW or DGRAM?
This is what I have so far, please note that I have purposely left out error checking.
int socket_descriptor = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
struct sockaddr_in address; //Initialize address struct
memset(&address, 0, sizeof(address)); //Clear address struct
//Declare address
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(ipaddress);
address.sin_port = htons(80);
//Bind socket to address
bind(socket_descriptor, (struct sockaddr *)&address, sizeof(address));
//Create packet
struct echo_request packet; //See above for declaration of struct
memset(packet.data, 1, 16);
packet.type = 8; //ECHO_REQUEST
packet.code = 0;
packet.time = gettime();
packet.checksum = 0;
packet.checksum = in_cksum(packet, sizeof(packet));
If you don't have to implement the ping from scratch and you want only Windows solution, I'd second Anton's suggestion for IcmpSendEcho. If you have to implement ping, look at how POCO ICMP package is implemented. It is portable code and it runs fine on Windows.
In regards to the specific questions, here are the answers:
what header files should I include
#include <winsock2.h>
how do I create a ping packet
See ICMPv4PacketImpl::initPacket() for an example of IPv4 packet.
am I using the correct checksum generator function
Not for windows. See ICMPPacketImpl::checksum() for an example of checksum function.
should a ping be directed to port 80
No. There's no such thing as port when it comes to ICMP. See Does ICMP use a specific port?
should the socket I use be RAW or DGRAM
It should be RAW.
It looks like you want a real solution, not just reimplementing PING for the sake of it.
I recommend using IP helper (ICMP.dll on pre-WinXP systems), specifically, IcmpSendEcho (or its enhanced versions, IcmpSendEcho2, IcmpSendEcho2Ex, for asynchronous operations).
There is a complete example of "pinging" a host on MSDN. It may be a good starting point.
Update: for GCC (mingw), link with -liphlpapi.

C, Linux: Receiving data from multiple multicast address on same port - how to distinguish them? [duplicate]

I have an application that is receiving data from multiple multicast sources on the same port. I am able to receive the data. However, I am trying to account for statistics of each group (i.e. msgs received, bytes received) and all the data is getting mixed up. Does anyone know how to solved this problem? If I try to look at the sender's address, it is not the multicast address, but rather the IP of the sending machine.
I am using the following socket options:
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("224.1.2.3");
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
and also:
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
After some years facing this linux strange behaviour, and using the bind workaround describe in previous answers, I realize that the ip(7) manpage describe a possible solution :
IP_MULTICAST_ALL (since Linux 2.6.31)
This option can be used to modify the delivery policy of
multicast messages to sockets bound to the wildcard INADDR_ANY
address. The argument is a boolean integer (defaults to 1).
If set to 1, the socket will receive messages from all the
groups that have been joined globally on the whole system.
Otherwise, it will deliver messages only from the groups that
have been explicitly joined (for example via the
IP_ADD_MEMBERSHIP option) on this particular socket.
Then you can activate the filter to receive messages of joined groups using :
int mc_all = 0;
if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) {
perror("setsockopt() failed");
}
This problem and the way to solve it enabling IP_MULTICAST_ALL is discussed in Redhat Bug 231899, this discussion contains test programs to reproduce the problem and to solve it.
[Edited to clarify that bind() may in fact include a multicast address.]
So the application is joining several multicast groups, and receiving messages sent to any of them, to the same port. SO_REUSEPORT allows you to bind several sockets to the same port. Besides the port, bind() needs an IP address. INADDR_ANY is a catch-all address, but an IP address may also be used, including a multicast one. In that case, only packets sent to that IP will be delivered to the socket. I.e. you can create several sockets, one for each multicast group. bind() each socket to the (group_addr, port), AND join group_addr. Then data addressed to different groups will show up on different sockets, and you'll be able to distinguish it that way.
I tested that the following works on FreeBSD:
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
const char *group = argv[1];
int s = socket(AF_INET, SOCK_DGRAM, 0);
int reuse = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
fprintf(stderr, "setsockopt: %d\n", errno);
return 1;
}
/* construct a multicast address structure */
struct sockaddr_in mc_addr;
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = inet_addr(group);
mc_addr.sin_port = htons(19283);
if (bind(s, (struct sockaddr*) &mc_addr, sizeof(mc_addr)) == -1) {
fprintf(stderr, "bind: %d\n", errno);
return 1;
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
char buf[1024];
int n = 0;
while ((n = read(s, buf, 1024)) > 0) {
printf("group %s fd %d len %d: %.*s\n", group, s, n, n, buf);
}
}
If you run several such processes, for different multicast addresses, and send a message to one of the addresses, only the relevant process will receive it. Of course, in your case, you probably will want to have all the sockets in one process, and you'll have to use select or poll or equivalent to read them all.
Use setsockopt() and IP_PKTINFO or IP_RECVDSTADDR depending on your platform, assuming IPv4. This combined with recvmsg() or WSARecvMsg() allows you to find the source and destination address of every packet.
Unix/Linux, note FreeBSD uses IP_RECVDSTADDR whilst both support IP6_PKTINFO for IPv6.
http://www.kernel.org/doc/man-pages/online/pages/man7/ip.7.html
Windows, also has IP_ORIGINAL_ARRIVAL_IF
http://msdn.microsoft.com/en-us/library/ms741645(v=VS.85).aspx
Replace
mc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
with
mc_addr.sin_addr.s_addr = inet_addr (mc_addr_str);
it's help for me (linux), for each application i receive separate mcast stream from separate mcast group on one port.
Also you can look into VLC player source, it show many mcast iptv channel from different mcast group on one port, but i dont know, how it separetes channel.
I have had to use multiple sockets each looking at different multicast group addresses, and then count statistics on each socket individually.
If there is a way to see the "receiver's address" as mentioned in the answer above, I can't figure it out.
One important point that also took me awhile - when I bound each of my individual sockets to a blank address like most python examples do:
sock[i].bind(('', MC_PORT[i])
I got all the multicast packets (from all multicast groups) on each socket, which didn't help. To fix this, I bound each socket to it's own multicast group
sock[i].bind((MC_GROUP[i], MC_PORT[i]))
And it then worked.
IIRC recvfrom() gives you a different read address/port for each sender.
You can also put a header in each packet identifying the source sender.
The Multicast address will be the receiver's address not sender's address in the packet. Look at the receiver's IP address.
You can separate the multicast streams by looking at the destination IP addresses of the received packets (which will always be the multicast addresses). It is somewhat involved to do this:
Bind to INADDR_ANY and set the IP_PKTINFO socket option. You then have to use recvmsg() to receive your multicast UDP packets and to scan for the IP_PKTINFO control message. This gives you some side band information of the received UDP packet:
struct in_pktinfo {
unsigned int ipi_ifindex; /* Interface index */
struct in_addr ipi_spec_dst; /* Local address */
struct in_addr ipi_addr; /* Header Destination address */
};
Look at ipi_addr: This will be the multicast address of the UDP packet you just received. You can now handle the received packets specific for each multicast stream (multicast address) you are receiving.

Resources