-
-
Save rmanis/d5a69d39ab10ab953c7e to your computer and use it in GitHub Desktop.
Multicast chat, for sharing links over a lan.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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