bcast/net.c

414 lines
10 KiB
C

#include "net.h"
int initNetwork() {
// Load in Windows' socket networking support
#if defined(WIN32)
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
}
#endif
// @@TODO: move port initialization elswhere
setConfig("port", "7332");
// Get the env USER and hostname then build user@hostname nickname
char *username = getenv("USER");
char hostname[15]; // cap hostname to 16 chars, I guess
gethostname(hostname, 16);
size_t nick_length = strlen(hostname)+strlen(username)+1;
char nick[nick_length];
int i = 0;
int j = 0;
while(j<strlen(username)) {
nick[i++] = username[j++];
}
nick[i++] = '@';
j = 0;
while(j<strlen(hostname)) {
nick[i++] = hostname[j++];
}
nick[i] = '\0';
setConfig("nick", nick);
return 0;
}
int openListenSocket() {
int ip_hash = generateHash("ip", CONFIG_HASH_SIZE);
int port_hash = generateHash("port", CONFIG_HASH_SIZE);
setAttribute(MAGENTA);
setAttribute(UNDERSCORE);
printf("--openListenSocket--\n");
clearAttributes();
setAttribute(GREEN);
printf("IP: %s\n", config[ip_hash]);
printf("port: %s\n", config[port_hash]);
clearAttributes();
printf("open: ");
// Create our IPv4 datagram socket
listen_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (listen_socket < 0) {
perror("error");
return -1;
} else {
printf("success\n");
}
// Allow the socket to be reusable
int reuse = 1;
printf("SO_REUSEADDR set: ");
if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0) {
perror("error");
return -2;
} else {
printf("success\n");
}
// Join the broadcast group for 226.1.1.1
if (!is_group_socket_set) {
memset((char *) &group_socket, 0, sizeof(group_socket));
group_socket.sin_family = AF_INET;
//group_socket.sin_port = htons(7332);
group_socket.sin_port = htons((unsigned short)strtoul(config[port_hash], NULL, 0));
group_socket.sin_addr.s_addr = inet_addr("226.1.1.1");
is_group_socket_set = 1;
}
// Bind to the socket w/ our group information
printf("bind: ");
if (bind(listen_socket, (struct sockaddr*)&group_socket, sizeof(group_socket))) {
perror("error");
return -3;
} else {
printf("success\n");
}
// join our group to user's selected IP
group.imr_multiaddr.s_addr = inet_addr("226.1.1.1");
group.imr_interface.s_addr = inet_addr(config[ip_hash]);
printf("IP_ADD_MEMBERSHIP: ");
if (setsockopt(listen_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
perror("error");
return -4;
} else {
printf("success\n");
}
// TODO: move this
is_listening = 1;
/* add to master_fds? */
listen_tv.tv_sec=0;
listen_tv.tv_usec=0;
//FD_ZERO(&master_fds);
FD_SET(listen_socket, &master_fds);
max_fd = listen_socket;
return 0;
};
int closeListenSocket() {
max_fd--;
close(listen_socket);
is_listening = 0;
printf("closed listen_socket\n");
return 0;
}
int openSendSocket() {
int ip_hash = generateHash("ip", CONFIG_HASH_SIZE);
int port_hash = generateHash("port", CONFIG_HASH_SIZE);
setAttribute(MAGENTA);
setAttribute(UNDERSCORE);
printf("--openSendSocket--\n");
clearAttributes();
setAttribute(GREEN);
printf("IP: %s\n", config[ip_hash]);
printf("port: %s\n", config[port_hash]);
clearAttributes();
printf("open: ");
send_socket = socket(PF_INET, SOCK_DGRAM, 0);
if (send_socket < 0) {
perror("error");
return -1;
} else {
printf("success\n");
}
// FIXME: doesn't actually disable? :S
printf("disable loopback: ");
char loopback_char = 0;
if (setsockopt(send_socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopback_char, sizeof(loopback_char)) < 0) {
perror("error");
return -2;
} else {
printf("success\n");
}
local_interface.s_addr = inet_addr(config[ip_hash]);
//local_interface.s_addr = inet_addr("192.168.182.51");
printf("local_interface set (%s): ", inet_ntoa(local_interface));
if (setsockopt(send_socket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&local_interface, sizeof(local_interface)) < 0) {
perror("error:");
return -3;
} else {
printf("success\n");
}
/* init sockaddr */
if (!is_group_socket_set) {
memset((char *) &group_socket, 0, sizeof(group_socket));
group_socket.sin_family = PF_INET;
group_socket.sin_addr.s_addr = inet_addr("226.1.1.1");
//group_socket.sin_port = htons(7332);
group_socket.sin_port = htons((unsigned short)strtoul(config[port_hash], NULL, 0));
is_group_socket_set = 1;
}
is_sending = 1;
return 0;
}
int closeSendSocket() {
close(send_socket);
is_sending = 0;
printf("closed send_socket\n");
return 0;
}
int setString(char *destination, const char source[]) {
size_t len = strlen(source);
size_t i = 0;
while (source[i] != '\n' && i < len) {
destination[i] = source[i];
i++;
}
destination[len] = '\0';
return 0;
}
char *stripString(const char string[]) {
char *result = malloc(15);
size_t len = strlen(string);
size_t i = 0;
char current_char = string[i];
while (current_char != '\n' && current_char != '\0' && i < len) {
result[i] = current_char;
i++;
current_char = string[i];
}
result[15] = '\0';
return result;
}
void restartSockets(const char *value) {
if (value) {
if (!strcmp(value, START_LISTEN_COMMAND)) {
if (is_listening) {
stopListenSocket();
startListenSocket();
}
} else if (!strcmp(value, START_SEND_COMMAND)) {
if (is_listening) {
stopSendSocket();
startSendSocket();
}
}
} else {
if (is_listening) {
stopListenSocket();
startListenSocket();
}
if (is_listening) {
stopSendSocket();
startSendSocket();
}
}
}
void startSockets(const char *value) {
if (value) {
if (!strcmp(value, START_LISTEN_COMMAND)) {
startListenSocket();
} else if (!strcmp(value, START_SEND_COMMAND)) {
startSendSocket();
}
} else {
startListenSocket();
startSendSocket();
}
}
void stopSockets(const char *value) {
if (value) {
if (!strcmp(value, STOP_LISTEN_COMMAND)) {
stopListenSocket();
} else if (!strcmp(value, STOP_SEND_COMMAND)) {
stopSendSocket();
}
} else {
stopListenSocket();
stopSendSocket();
}
}
int startListenSocket() {
if (!is_listening) {
return (openListenSocket());
} else {
printf("already listening - 'stop' or 'restart' first\n");
}
return 0;
}
int stopListenSocket() {
if (is_listening) {
return (closeListenSocket());
} else {
printf("already stopped - 'start' first\n");
}
return 0;
}
int startSendSocket() {
if (!is_sending) {
return(openSendSocket());
} else {
printf("already sending - 'stop' or 'restart' first\n");
}
return 0;
}
int stopSendSocket() {
if (is_sending) {
return(closeSendSocket());
} else {
printf("already stopped - 'start' first\n");
}
return 0;
}
int handleOpenMessage(const char packet[]) {
uint8_t nick_size;
//uint8_t message_id;
//uint8_t payload_type;
uint8_t payload_size;
int offset = 1; // skip past message_type
nick_size = packet[offset++];
char nick[nick_size];
int j = 0;
while(j < nick_size) {
nick[j++] = packet[offset++];
}
//message_id = packet[offset++];
offset++;
//payload_type = packet[offset++];
offset++;
payload_size = packet[offset++];
char payload[payload_size];
j = 0;
while(j < payload_size) {
payload[j++] = packet[offset++];
}
printf("%s: %s", nick, payload);
return 0;
}
void sendOpen(char buffer[]) {
int packet_size = 0;
// Build our packet's length in bytes first
uint8_t message_type = MESSAGE_OPEN;
packet_size++; // for message_type
int nick_hash = generateHash("nick", CONFIG_HASH_SIZE);
uint8_t nick_size = strlen(config[nick_hash])+1; // +1 for \0
packet_size++; // for nick_length;
packet_size += nick_size; // for nick itself
uint8_t message_id = 9;
packet_size++; // for message_id
uint8_t payload_type = 1; // chat type
packet_size++; // for payload type
uint8_t buffer_size = strlen(buffer)+1;
packet_size++; // for string_length char
packet_size += buffer_size; // for payload itself
//printf("packet size will be %d\n", packet_size);
// Populate our packet
int i = 0;
int packet_offset = 0;
char packet[packet_size];
packet[packet_offset++] = message_type;
packet[packet_offset++] = nick_size;
while (i < nick_size) {
packet[packet_offset++] = config[nick_hash][i++];
}
packet[packet_offset++] = message_id;
packet[packet_offset++] = payload_type;
packet[packet_offset++] = buffer_size;
i = 0;
while (i < buffer_size) {
packet[packet_offset++] = buffer[i++];
}
receiveOpen(packet, DATAGRAM_SIZE);
sendMulticast(send_socket, &group_socket, packet, packet_offset);
}
void receiveOpen(const char packet[], size_t packet_size) {
if (packet[0] == MESSAGE_OPEN) {
handleOpenMessage(packet);
}
}
int sendMulticast(int send_socket, struct sockaddr_in *group_socket, char data_buffer[], int data_length) {
if (sendto(send_socket, data_buffer, data_length, 0, (struct sockaddr*)group_socket, sizeof((*group_socket))) < 0) {
perror("sendto error");
return -1;
}
return 0;
}
// FIXME: interface list & IPs broken on OS X - perhaps due to IPV6 being active?
void getInterfaces() {
int i;
int test_socket = socket(AF_INET, SOCK_STREAM, 0);
if (test_socket < 0) {
return;
}
ifconf.ifc_buf = (char *) ifreq;
// Set ifconf's ifc_len to the length of our array of interface ifreqs.
ifconf.ifc_len = sizeof ifreq;
// Populate ifconf.ifc_buf (ifreq) with a list of interface names and addresses.
if (ioctl(test_socket, SIOCGIFCONF, &ifconf) == -1)
return;
// Divide the length of the interface list by the size of each entry.
// This gives us the number of interfaces on the system.
interfaces = ifconf.ifc_len / sizeof(ifreq[0]);
for (i = 0; i < interfaces; i++) {
char ip[INET_ADDRSTRLEN];
struct sockaddr_in *address = (struct sockaddr_in *) &ifreq[i].ifr_addr;
// Convert the binary IP address into a readable string.
if (!inet_ntop(AF_INET, &address->sin_addr, ip, sizeof(ip)))
return;
ip_list[i] = malloc(strlen(ip));
setString(ip_list[i], ip);
printf("%s - %s\n", ifreq[i].ifr_name, ip);
dev_list[i] = malloc(strlen(ifreq[i].ifr_name));
setString(dev_list[i], ifreq[i].ifr_name);
}
close(test_socket);
setConfig("ip", ip_list[interfaces-1]);
}
void freeInterfaces() {
int i;
for (i = 0;i < interfaces;i++) {
if (ip_list[i]) {
free(ip_list[i]);
}
}
}