#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(jsin_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]); } } }