-
-
Save hostilefork/f7cae3dc33e7416f2dd25a402857b6c6 to your computer and use it in GitHub Desktop.
// | |
// Simple listener.c program for UDP multicast | |
// | |
// Adapted from: | |
// http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html | |
// | |
// Changes: | |
// * Compiles for Windows as well as Linux | |
// * Takes the port and group on the command line | |
// | |
#ifdef _WIN32 | |
#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict | |
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast | |
#include <Windows.h> | |
#else | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <time.h> | |
#endif | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#define MSGBUFSIZE 256 | |
int main(int argc, char *argv[]) | |
{ | |
if (argc != 3) { | |
printf("Command line args should be multicast group and port\n"); | |
printf("(e.g. for SSDP, `listener 239.255.255.250 1900`)\n"); | |
return 1; | |
} | |
char* group = argv[1]; // e.g. 239.255.255.250 for SSDP | |
int port = atoi(argv[2]); // 0 if error, which is an invalid port | |
#ifdef _WIN32 | |
// | |
// Initialize Windows Socket API with given VERSION. | |
// | |
WSADATA wsaData; | |
if (WSAStartup(0x0101, &wsaData)) { | |
perror("WSAStartup"); | |
return 1; | |
} | |
#endif | |
// create what looks like an ordinary UDP socket | |
// | |
int fd = socket(AF_INET, SOCK_DGRAM, 0); | |
if (fd < 0) { | |
perror("socket"); | |
return 1; | |
} | |
// allow multiple sockets to use the same PORT number | |
// | |
u_int yes = 1; | |
if ( | |
setsockopt( | |
fd, SOL_SOCKET, SO_REUSEADDR, (char*) &yes, sizeof(yes) | |
) < 0 | |
){ | |
perror("Reusing ADDR failed"); | |
return 1; | |
} | |
// set up destination address | |
// | |
struct sockaddr_in addr; | |
memset(&addr, 0, sizeof(addr)); | |
addr.sin_family = AF_INET; | |
addr.sin_addr.s_addr = htonl(INADDR_ANY); // differs from sender | |
addr.sin_port = htons(port); | |
// bind to receive address | |
// | |
if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) { | |
perror("bind"); | |
return 1; | |
} | |
// use setsockopt() to request that the kernel join a multicast group | |
// | |
struct ip_mreq mreq; | |
mreq.imr_multiaddr.s_addr = inet_addr(group); | |
mreq.imr_interface.s_addr = htonl(INADDR_ANY); | |
if ( | |
setsockopt( | |
fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mreq, sizeof(mreq) | |
) < 0 | |
){ | |
perror("setsockopt"); | |
return 1; | |
} | |
// now just enter a read-print loop | |
// | |
while (1) { | |
char msgbuf[MSGBUFSIZE]; | |
int addrlen = sizeof(addr); | |
int nbytes = recvfrom( | |
fd, | |
msgbuf, | |
MSGBUFSIZE, | |
0, | |
(struct sockaddr *) &addr, | |
&addrlen | |
); | |
if (nbytes < 0) { | |
perror("recvfrom"); | |
return 1; | |
} | |
msgbuf[nbytes] = '\0'; | |
puts(msgbuf); | |
} | |
#ifdef _WIN32 | |
// | |
// Program never actually gets here due to infinite loop that has to be | |
// canceled, but since people on the internet wind up using examples | |
// they find at random in their own code it's good to show what shutting | |
// down cleanly would look like. | |
// | |
WSACleanup(); | |
#endif | |
return 0; | |
} |
// | |
// Simple sender.c program for UDP | |
// | |
// Adapted from: | |
// http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html | |
// | |
// Changes: | |
// * Compiles for Windows as well as Linux | |
// * Takes the port and group on the command line | |
// | |
// Note that what this program does should be equivalent to NETCAT: | |
// | |
// echo "Hello World" | nc -u 239.255.255.250 1900 | |
#ifdef _WIN32 | |
#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict | |
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast | |
#include <Windows.h> | |
#else | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <unistd.h> // for sleep() | |
#endif | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
int main(int argc, char *argv[]) | |
{ | |
if (argc != 3) { | |
printf("Command line args should be multicast group and port\n"); | |
printf("(e.g. for SSDP, `sender 239.255.255.250 1900`)\n"); | |
return 1; | |
} | |
char* group = argv[1]; // e.g. 239.255.255.250 for SSDP | |
int port = atoi(argv[2]); // 0 if error, which is an invalid port | |
// !!! If test requires, make these configurable via args | |
// | |
const int delay_secs = 1; | |
const char *message = "Hello, World!"; | |
#ifdef _WIN32 | |
// | |
// Initialize Windows Socket API with given VERSION. | |
// | |
WSADATA wsaData; | |
if (WSAStartup(0x0101, &wsaData)) { | |
perror("WSAStartup"); | |
return 1; | |
} | |
#endif | |
// create what looks like an ordinary UDP socket | |
// | |
int fd = socket(AF_INET, SOCK_DGRAM, 0); | |
if (fd < 0) { | |
perror("socket"); | |
return 1; | |
} | |
// set up destination address | |
// | |
struct sockaddr_in addr; | |
memset(&addr, 0, sizeof(addr)); | |
addr.sin_family = AF_INET; | |
addr.sin_addr.s_addr = inet_addr(group); | |
addr.sin_port = htons(port); | |
// now just sendto() our destination! | |
// | |
while (1) { | |
char ch = 0; | |
int nbytes = sendto( | |
fd, | |
message, | |
strlen(message), | |
0, | |
(struct sockaddr*) &addr, | |
sizeof(addr) | |
); | |
if (nbytes < 0) { | |
perror("sendto"); | |
return 1; | |
} | |
#ifdef _WIN32 | |
Sleep(delay_secs * 1000); // Windows Sleep is milliseconds | |
#else | |
sleep(delay_secs); // Unix sleep is seconds | |
#endif | |
} | |
#ifdef _WIN32 | |
// | |
// Program never actually gets here due to infinite loop that has to be | |
// canceled, but since people on the internet wind up using examples | |
// they find at random in their own code it's good to show what shutting | |
// down cleanly would look like. | |
// | |
WSACleanup(); | |
#endif | |
return 0; | |
} |
Thanks :) Couldn't figure out how to use UDP in C
Due to binding to INADDR_ANY
in listener here, the listener receives not only multicast traffic but also unicast from any IP.
setsockopt: No error
Thanks for this example. Can this be used to have a single sender and multiple receivers, all on the same machine/interface? I am going to try it to find out, but if someone is listening, please let me know if this is possible.
I test, It Works.
I faced a situation then the client only receiving data when we explicitly define source IP, just in case if someone has issues with receiving data.
So the block at line https://gist.github.com/hostilefork/f7cae3dc33e7416f2dd25a402857b6c6#file-listener-c-L88 should look like this:
struct ip_mreq_source mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_sourceaddr.s_addr = inet_addr("yyy.xxx.253.232"); // real IP address of a sender
if ( setsockopt(fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char*) &mreq, sizeof(mreq)) < 0) {
perror("setsockopt");
return 1;
}
I faced a situation then the client only receiving data when we explicitly define source IP, just in case if someone has issues with receiving data.
Probably because you are using IGMPv3, which has support for Source Specific Multicast (SSM), a security feature. If you are having this problem too, you can try to set the IGMP version to use IGMPv2.
In linux it can be done this way:
echo "2" > /proc/sys/net/ipv4/conf/<your_interface>/force_igmp_version
@iamfahad43 I used it two weeks ago and had no problems, check your routing is what I would recommend. You can try running the application as an admin or enabling the passthrough through your firewall port.