469 lines
12 KiB
C
469 lines
12 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
|
|
|
|
from_address_length = sizeof(struct sockaddr_in);
|
|
// malloc the following so we don't QQ later
|
|
//current_message.nick = realloc(current_message.nick, sizeof(char)+1);
|
|
//current_message.nick = malloc(sizeof(char)+1);
|
|
|
|
// @@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;
|
|
}
|
|
|
|
void handleNetInput(const char *data_buffer) {
|
|
//Message message = buildMessage(data_buffer, &from_address);
|
|
//free(current_message.nick); // free old malloc'd char array
|
|
current_message = buildMessage(data_buffer, &from_address);
|
|
inet_ntop(AF_INET, &(current_message.address), from_address_string, INET_ADDRSTRLEN);
|
|
if (!checkUser(&user_list, current_message.nick, current_message.address)) {
|
|
addUser(&user_list, current_message.nick, current_message.address);
|
|
} else {
|
|
//updateUser(message.username, message.address, currentTime());
|
|
updateUser(&user_list, current_message.nick, current_message.address);
|
|
}
|
|
}
|
|
|
|
Message buildMessage(const char *data_buffer, struct sockaddr_in *socket) {
|
|
// free the old malloc'd ish
|
|
freeMessage(¤t_message);
|
|
Message message;
|
|
message.address = socket->sin_addr;
|
|
int offset = 0;
|
|
message.type = data_buffer[offset++];
|
|
message.nick_size = data_buffer[offset++];
|
|
int j = 0;
|
|
//message.nick = realloc(message.nick, sizeof(char)*message.nick_size);
|
|
message.nick = malloc(sizeof(char)*message.nick_size);
|
|
while(j < message.nick_size) {
|
|
message.nick[j++] = data_buffer[offset++];
|
|
}
|
|
//message.nick[j-1] = '\0'; // add NUL terminator
|
|
message.id = data_buffer[offset++];
|
|
message.payload_type = data_buffer[offset++];
|
|
message.payload_size = data_buffer[offset++];
|
|
j = 0;
|
|
while(j < message.payload_size) {
|
|
message.payload[j++] = data_buffer[offset++];
|
|
}
|
|
return message;
|
|
}
|
|
|
|
int freeMessage(Message *message) {
|
|
free(message->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");
|
|
}
|
|
|
|
// Don't disable loopback, as we want user's own messages handled, as well as
|
|
// other users on the same system.
|
|
/* 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 {
|
|
if (is_running)
|
|
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 {
|
|
if (is_running)
|
|
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);
|
|
if (is_running)
|
|
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]);
|
|
}
|
|
if (dev_list[i]) {
|
|
free(dev_list[i]);
|
|
}
|
|
}
|
|
}
|