Skip to content

Instantly share code, notes, and snippets.

@rmanis
Created July 25, 2015 02:33
Show Gist options
  • Save rmanis/d5a69d39ab10ab953c7e to your computer and use it in GitHub Desktop.
Save rmanis/d5a69d39ab10ab953c7e to your computer and use it in GitHub Desktop.
Multicast chat, for sharing links over a lan.
/*
* mc - multicast chat
*
* Usage :
* mc [multicast-group [port]]
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#define DEFAULT_GROUP "224.11.12.13"
#define DEFAULT_PORT "50000"
#define MAX_PACKET_SIZE 65507
int yes = 1;
void setup_listener(int *sockfd, int argc, char **argv);
void setup_sender(int *sockfd, struct sockaddr_in *addr, int argc, char **argv);
void setup_select(fd_set *readfds, int sockfd);
int main(int argc, char *argv[]) {
int outsock;
int insock;
int ready;
struct sockaddr_in destination_addr;
struct sockaddr_in sender_addr;
fd_set readfds;
ssize_t bytes_read;
ssize_t addrlen = sizeof(struct sockaddr_in);
socklen_t sender_size = sizeof(struct sockaddr_in);
char running = 1;
char buffer[65507];
setup_listener(&insock, argc, argv);
setup_sender(&outsock, &destination_addr, argc, argv);
while (running) {
setup_select(&readfds, insock);
ready = select(insock + 1, &readfds, NULL, NULL, NULL);
if (ready) {
memset(buffer, 0, sizeof(buffer));
if (FD_ISSET(0, &readfds)) {
// ready stdin
bytes_read = read(0, buffer, sizeof(buffer));
if (bytes_read > 0) {
sendto(outsock, buffer, bytes_read, 0,
(struct sockaddr *) &destination_addr, addrlen);
} else if (bytes_read < 0) {
perror("STDIN read");
} else {
running = 0;
}
} else if (FD_ISSET(insock, &readfds)) {
// ready socket
bytes_read = recvfrom(insock, buffer, sizeof(buffer), 0,
(struct sockaddr *)&sender_addr, &sender_size);
printf("[%s:%d]: %s", inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port), buffer);
}
}
}
return 0;
}
// 0 1 2
// mc [addr [port]]
void setup_listener(int *sockfd, int argc, char **argv) {
struct ip_mreq mreq;
struct sockaddr_in addr;
char *group = argc >= 2 ? argv[1] : DEFAULT_GROUP;
char *port = argc >= 3 ? argv[2] : DEFAULT_PORT;
*sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (*sockfd < 0) {
perror("in socket");
exit(1);
}
if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(int)) < 0) {
perror("Reuse address");
exit(5);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(port));
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(*sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
exit(2);
}
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(*sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("Add membership");
exit(3);
}
}
void setup_sender(int *sockfd, struct sockaddr_in *addr, int argc, char **argv) {
char *group = argc >= 2 ? argv[1] : DEFAULT_GROUP;
char *port = argc >= 3 ? argv[2] : DEFAULT_PORT;
*sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (*sockfd < 0) {
perror("out socket");
exit(1);
}
memset(addr, 0, sizeof(struct sockaddr_in));
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(group);
addr->sin_port = htons(atoi(port));
}
void setup_select(fd_set *readfds, int sockfd) {
FD_ZERO(readfds);
FD_SET(0, readfds);
FD_SET(sockfd, readfds);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment