int tc_multiconnect(TCDevice * dev_ptr, char *my_tag, char *other_tag, TrickErrorHndlr * not_used) { int status; int num_try = 0; TCDevice *server_device; char name[80]; int size; char *cptr; /* Multicast vars */ struct sockaddr_in addr; int fd, nbytes; struct ip_mreq mreq; BC_INFO bc_info, *bc_copy; SEND_ME read_me; int i_am_client; int value; int num_attempts = 10; int found_conn; #ifdef __WIN32__ HANDLE thread; DWORD threadId; int curr_pid; WSADATA wsaData; #else pthread_t thread; pid_t curr_pid; #endif (void) not_used; /* unused */ if (!dev_ptr) { TrickErrorHndlr *temp_error_hndlr = NULL; trick_error_report(temp_error_hndlr, TRICK_ERROR_ALERT, __FILE__, __LINE__, "Trying to connect a NULL device"); return (-1); } if (dev_ptr->disabled != 0) { trick_error_report(dev_ptr->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "[33m%s| cannot connect disabled device %s[00m\n", my_tag, other_tag); return (TC_SUCCESS); } trick_error_report(dev_ptr->error_handler, TRICK_ERROR_ADVISORY, __FILE__, __LINE__, "[36m%s| multiconnecting to %s[00m\n", my_tag, other_tag); /* Create a TrickComm listen device Determine port for listen device */ server_device = (TCDevice *) malloc(sizeof(TCDevice)); memset((void *) server_device, '\0', sizeof(TCDevice)); server_device->error_handler = dev_ptr->error_handler; server_device->port = 0; if ((status = tc_init(server_device)) != TC_SUCCESS) { trick_error_report(server_device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not open listen device!\n"); return (status); } /* * Initialize Broadcast Info Structure */ gethostname(name, (size_t) 80); strcpy(bc_info.send_me.addr, name); bc_info.send_me.port = server_device->port; bc_info.send_me.pid = curr_pid = getpid(); bc_info.send_me.conn_initiated = 0; if (my_tag != (char *) NULL) { strncpy(bc_info.send_me.my_tag, my_tag, (size_t) TC_TAG_LENGTH); bc_info.send_me.my_tag[TC_TAG_LENGTH - 1] = '\0'; } else { bc_info.send_me.my_tag[0] = '\0'; } if (other_tag != (char *) NULL) { strncpy(bc_info.send_me.other_tag, other_tag, (size_t) TC_TAG_LENGTH); bc_info.send_me.other_tag[TC_TAG_LENGTH - 1] = '\0'; } else { bc_info.send_me.other_tag[0] = '\0'; } bc_info.device = dev_ptr; #ifdef __WIN32__ /* Initiate use of the Windows socket DLL */ if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR) { perror("tc_multiconnect: WSAStartup"); WSACleanup(); return (TC_COULD_NOT_ACCEPT); } #endif /* Create the broadcast socket */ if ((bc_info.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("tc_multiconnect socket"); } /* Set up destination address */ memset(&bc_info.addr, 0, sizeof(bc_info.addr)); bc_info.addr.sin_family = AF_INET; bc_info.addr.sin_addr.s_addr = inet_addr(TC_MULT_GROUP); bc_info.addr.sin_port = htons(TC_MULT_PORT); /* * Create socket to listen for connections */ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("tc_multiconnect socket"); } value = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, (socklen_t) sizeof(value)) < 0) { perror("setsockopt: reuseaddr"); } #ifdef SO_REUSEPORT if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value, sizeof(value)) < 0) { perror("setsockopt: reuseport"); } #endif /* Set up destination address */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(TC_MULT_PORT); /* Bind to receive address */ if (bind(fd, (struct sockaddr *) &addr, (socklen_t) sizeof(addr)) < 0) { perror("tc_multiconnect bind"); } /* Use setsockopt() to request that the kernel join a multicast group */ mreq.imr_multiaddr.s_addr = inet_addr(TC_MULT_GROUP); mreq.imr_interface.s_addr = htonl(INADDR_ANY); size = sizeof(mreq); cptr = (char *) &mreq; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, cptr, (socklen_t) size) < 0) { #ifdef __WIN32__ TCHAR szError[100]; // Error message string wsprintf(szError, TEXT("setsockopt failed! Error: %d"), WSAGetLastError()); MessageBox(NULL, szError, TEXT("Error"), MB_OK); #endif perror("setsockopt: ip_add_membership"); } /* Create thread that will continually broadcast connection info on multicast port for prospective clients. */ /* make a copy of info to broadcast */ bc_copy = (BC_INFO *) malloc(sizeof(BC_INFO)); memcpy(bc_copy, &bc_info, sizeof(BC_INFO)); #ifdef __WIN32__ thread = CreateThread(NULL, 0, tc_broadcast_conninfo, &bc_copy, 0, &threadId); #else pthread_create(&thread, NULL, tc_broadcast_conninfo, bc_copy); #endif /* Wait for other peers wanting to connect to me */ i_am_client = 0; found_conn = 0; while (found_conn == 0) { do { nbytes = recvfrom(fd, &read_me, sizeof(SEND_ME), 0, NULL, NULL); } while ((nbytes == -1) && (tc_errno == TRICKCOMM_EINTR)); if (nbytes == sizeof(read_me)) { /* * Read information from peer */ read_me.port = ntohl((uint32_t) read_me.port); read_me.pid = ntohl((uint32_t) read_me.pid); read_me.conn_initiated = ntohl((uint32_t) read_me.conn_initiated); /* May I connect with this peer? Rules: Don't connect to myself! Don't connect to someone with same tag as myself Do connect to someone with same "other tag" */ if (curr_pid != read_me.pid && strcmp(bc_info.send_me.my_tag, read_me.my_tag) && !strcmp(bc_info.send_me.other_tag, read_me.other_tag)) { /* Decide who will function as client Whoever has smaller pid will be the client If same pid, decide by a string compare */ if (curr_pid < read_me.pid) { i_am_client = 1; } else if (curr_pid == read_me.pid) { i_am_client = (strcmp(name, read_me.addr) > 0) ? 1 : 0; } /* * Client Peer initiates the connection */ if (i_am_client == 1) { /* Save off addr and port to connect */ size = strlen(read_me.addr) + 1; dev_ptr->hostname = (char *) malloc((size_t) size); strcpy(dev_ptr->hostname, read_me.addr); dev_ptr->port = read_me.port; read_me.conn_initiated = 1; read_me.port = htonl((uint32_t) read_me.port); read_me.pid = htonl((uint32_t) read_me.pid); read_me.conn_initiated = htonl((uint32_t) read_me.conn_initiated); sendto(bc_info.fd, (char *) &read_me, sizeof(SEND_ME), 0, (struct sockaddr *) &bc_info.addr, (socklen_t) sizeof(bc_info.addr)); found_conn = 1; } } else if (curr_pid == read_me.pid && !strcmp(bc_info.send_me.addr, read_me.addr) && !strcmp(bc_info.send_me.my_tag, read_me.my_tag) && !strcmp(bc_info.send_me.other_tag, read_me.other_tag) && read_me.conn_initiated == 1) { found_conn = 1; } } } if (other_tag != (char *) NULL) { strncpy(dev_ptr->client_tag, other_tag, (size_t) TC_TAG_LENGTH); dev_ptr->client_tag[TC_TAG_LENGTH - 1] = '\0'; } if (i_am_client == 1) { /* Client connects */ /* Disconnect unneeded listen device */ tc_disconnect(server_device); free((void *) server_device); tc_set_blockio_timeout_limit(dev_ptr, MAX_BLOCKIO_TIMEOUT_LIMIT); status = 1; while ((status != TC_SUCCESS) && (num_try < num_attempts)) { status = tc_connect(dev_ptr); #if __WIN32__ Sleep(200); #else usleep(200000); #endif num_try++; } } else { /* * Server accepts */ status = 1; while (status != TC_SUCCESS && (num_try < num_attempts)) { if (tc_listen(server_device)) { status = tc_accept(server_device, dev_ptr); if (dev_ptr != NULL) { tc_set_blockio_timeout_limit(dev_ptr, MAX_BLOCKIO_TIMEOUT_LIMIT); } } num_try++; #if __WIN32__ Sleep(200); #else usleep(200000); #endif } tc_disconnect(server_device); free((void *) server_device); } if (status != TC_SUCCESS) { trick_error_report(server_device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not open connection!\n"); return (status); } /* Shutdown the broadcast */ shutdown(bc_info.fd, 2); /* Return the pointer to the TCDevice as the tc_id. */ return (TC_SUCCESS); }
/** @main Application entry-point. */ int main(int argc, char* argv[]) { int c; strcpy(initcmd, DEF_CMD_INIT); while (true) { static struct option long_options[] = { {"adapter", required_argument, 0, 'a'}, {"remote-adapter", required_argument, 0, 'b'}, {"close", no_argument, 0, 'c'}, {"blink-on-receive", no_argument, 0, 'k'}, {"log-packets", no_argument, 0, 'p'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long (argc, argv, "a:b:ckpvV?", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; switch (c) { case 'a': tc_eth_adapter = optarg; break; case 'b': tc_eth_remoteAdapter = optarg; break; case 'c': exitReason = 0; break; case 'p': dbg_logPackets = true; break; case 'v': dbg_debugOut = true; break; case 'k': dbg_blinkOnReceive = true; break; case 'V': printf("Asus-TCCI (TrendChip Command Interpreter), version %s, build %s\n", VERSION, VERSION_BUILD); printf(" by %s. Sources and updates: %s\n", AUTHOR, URL); return EC_NORMAL; case 'h': /* getopt_long already printed an error message. */ printf("usage: %s -V|--version\n", argv[0]); printf("or: %s [-a|--adapter=\"%s\"] [-b|--remote-adapter=\"%s\"] [-c|--close] [-p|--log-packets] [-v|--verbose] [-k|--blink-on-receive] [<%s>]\n", argv[0], tc_eth_adapter, tc_eth_remoteAdapter, initcmd); return EC_NORMAL; default: return 9; } } /* Print any remaining command line arguments (not options). */ if (optind < argc) { initcmd[0] = '\0'; // Clear string while (optind < argc) strncat(initcmd, argv[optind++], sizeof(initcmd)); } debugf("-- Starting...\n"); // Initialize in-socket tc_eth_sockIn = socket(AF_INET, SOCK_DGRAM, 0); if (tc_eth_sockIn < 0) { errorf("-- E: Input socket init failed!\n"); return EC_APIFAIL; } /*debugf("-- dbg_debugOut = %d, dbg_logPackets = %d, tc_eth_adapter = \"%s\", initcmd = \"%s\"\n", dbg_debugOut, dbg_logPackets, tc_eth_adapter, initcmd);*/ // Initialize adapter eth_adapterId = if_nametoindex(tc_eth_adapter); initAdapter(tc_eth_adapter); // Initialize out-socket tc_eth_sockOut = socket(AF_PACKET,SOCK_RAW, htons(ETH_P_ALL)); if (tc_eth_sockOut < 0) { errorf("-- E: Output socket init failed!\n"); return EC_APIFAIL; } // Acquired MACs debugf("Remote (TrendChip) MAC: "); printmac(debugf, tc_eth_remoteMac); debugf("\nLocal (terminal) MAC: "); printmac(debugf, tc_eth_localMac); // Initial command execution debugf("\n-- Phase 2 - Perform init-command (%s)\n", initcmd); if (!tc_exec(initcmd)) return EC_NETFAIL; // Interactive shell char inbuff[TC_CMD_MAX_LEN]; fd_set rfds; struct timeval tv; int retval; while(exitReason < 0) { FD_ZERO(&rfds); FD_SET(0, &rfds); tv.tv_sec = 0; tv.tv_usec = 100000; //100ms retval = select(1, &rfds, NULL, NULL, &tv); if (retval == -1){ perror("-- select(stdin)"); return EC_APIFAIL; } else if (retval){ debugf("-- Gathering input... "); char* cmd = fgets(inbuff, TC_CMD_MAX_LEN, stdin); if (cmd[strlen(cmd)-1] == '\n') cmd[strlen(cmd)-1] = '\0'; // Trim the trailing '\n' char. debugf("Got '%s'\n", cmd); if (cmd[0] == '\0') {} // Do nothing on blank lines. else if (strcmp(cmd, "!q") == 0 || strcmp(cmd, "!quit") == 0) exitReason = EC_NORMAL; else if (strcmp(cmd, "!v") == 0 || strcmp(cmd, "!verbose") == 0) errorf("-- Verbose output is now %s.\n", (dbg_debugOut = !dbg_debugOut) ? "ON" : "OFF"); else if (strcmp(cmd, "!p") == 0 || strcmp(cmd, "!logpackets") == 0) errorf("-- Packet logging is now %s.\n", (dbg_logPackets = !dbg_logPackets) ? "ON" : "OFF"); else if (strcmp(cmd, "!k") == 0 || strcmp(cmd, "!blink") == 0) errorf("-- Blink-on-receive is now %s.\n", (dbg_blinkOnReceive = !dbg_blinkOnReceive) ? "ON" : "OFF"); else if (strcmp(cmd, "!h") == 0 || strcmp(cmd, "!help") == 0) errorf("-- Valid client commands: \n-- ![blin]k, !h[elp], ![log]p[ackets], !q[uit], !v[erbose].\n"); else if (cmd[0] == '!') errorf("-- Unrecognized client command. Please try \"!help\" if you aren't sure.\n"); else if (!tc_exec(cmd)) errorf("-- W: Command request fail!\n"); //exitReason = EC_NETFAIL; // I/O error? } if (!tc_listen()) exitReason = EC_NETFAIL; } if (tc_eth_sockIn) close(tc_eth_sockIn); else debugf("-- W: Input socket already closed!"); if (tc_eth_sockOut) close(tc_eth_sockOut); else debugf("-- W: Output socket already closed!"); debugf("-- Connection closed, reason = %d (-1).\n", exitReason); return exitReason-1; }