/* ******************************************************************************* * Authors: * Maxime Villard, 2017 * Jankovic Marco, 01/07/2014 ******************************************************************************* */ #include "common.h" /* * tab containing all the slave side of a dev/pts * this part is swappable with other device */ int slave_fd[NB_CHANNELS]; /* * tab containing all the masters that come from /dev/pts/ptmx * this part is swappable with other device */ int master_fd[NB_CHANNELS]; /* * file descriptor of fifo rx and tx * file descriptor device_fd * nb_channels to multiplex */ int fifo_rx_fd; int fifo_tx_fd; #if TEST_BENCH int test_rx_fd; // file descriptor that simulates RX buffer int test_tx_fd; // file descriptor that simulates TX buffer #else int device_fd; #endif pthread_t tid[3]; /* * Function that opens an xterm. You need a master side and a slave side. * master_fd -> contains master fd from /dev/ptmx * slavename -> slave name from /dev/pts */ static int exec_xterm(int *master_fd, char *slavename, int tty_id) { char buf[64]; char tty_name[64]; *master_fd = posix_openpt(O_RDWR); grantpt(*master_fd); unlockpt(*master_fd); if (ptsname_r(*master_fd, slavename, 64) != 0) perror("ptsname_r"); printf("-> master_fd: %d\n", *master_fd); printf("-> slavename: %s\n", slavename); snprintf(buf, sizeof(buf), "-S%s/%d", strrchr(slavename,'/')+1, *master_fd); snprintf(tty_name, sizeof(buf), "tty_%d", tty_id); if (!fork()) { execlp("xterm", "xterm", buf, "-T", tty_name, "-bg", "black", "-fg", "green", "-geometry", "80x25", NULL); _exit(1); } return 0; } /* * Function that closes all file descriptors, kills all the threads and resets * the rs 232 port. */ void termination_handler(int signum) { int i; printf("termination handler %d \n",signum); for (i = 0; i < 3; i++) { if (pthread_kill(tid[i], SIGTERM) < 0) err(1, "pthread_kill"); } if (close(fifo_rx_fd) < 0) err(1, "close"); if (close(fifo_tx_fd) < 0) err(1, "close"); #if TEST_BENCH if (close(test_tx_fd) < 0) err(1, "close"); if (close(test_rx_fd) < 0) err(1, "close"); #else if (close(device_fd) < 0) err(1, "close"); #endif for (i = 0; i < NB_CHANNELS; i++) { if (close(slave_fd[i]) < 0) err(1, "close"); if (close(master_fd[i]) < 0) err(1, "close"); } exit(0); } static void init_tio(struct termios *tio) { // Input flags - Turn off input processing // convert break to null byte, no CR to NL translation, // no NL to CR translation, don't mark parity errors or breaks // no input parity check, don't strip high bit off, // no XON/XOFF software flow control tio->c_cflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON | CRTSCTS); tio->c_cflag |= (CLOCAL | CREAD); // Output flags - Turn off output processing // // no CR to NL translation, no NL to CR-NL translation, // // no NL to CR translation, no column 0 CR suppression, // // no Ctrl-D suppression, no fill characters, no case mapping, // // no local output processing tio->c_oflag &=~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OLCUC | OPOST); tio->c_oflag = 0; //// No line processing: //// echo off, echo newline off, canonical mode off, //// extended input processing off, signal chars off //// tio->c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); //// //// Turn off character processing //// clear current char size mask, no parity checking, //// no output processing, force 8 bit input //// 8N1 //// tio->c_cflag &= ~(CSIZE |PARENB|CSTOPB); tio->c_cflag |= CS8; //// tio->c_iflag &= ~(IXON | IXOFF | IXANY | INPCK | ISTRIP ); //// //// One input byte is enough to return from read() //// Inter-character timer off //// tio->c_cc[VMIN] = 1; tio->c_cc[VTIME] = 0; /* set baudrate */ if (cfsetispeed(tio, BAUDRATE) < 0 || cfsetospeed(tio, BAUDRATE) < 0) err(1, "error setting baudrate"); } int main(void) { char slavename[NB_CHANNELS][64]; int i; char buf[64]; pthread_attr_t thread_attr; /******************** signal handler ****************/ sigset_t sig_set; sigset_t sig_set_act; sigemptyset(&sig_set); sigfillset(&sig_set); sigdelset(&sig_set, SIGINT); sigprocmask(SIG_BLOCK, &sig_set, NULL); sigemptyset(&sig_set_act); struct sigaction action; action.sa_handler = termination_handler; action.sa_mask = sig_set_act; action.sa_flags = 0; sigaction(SIGINT, &action, NULL); /****************************************************/ printf("[+] device path: %s\n", DEVICE_PATH); printf("[+] nb_channels: %d\n", NB_CHANNELS); /* * Opening 2 FIFOs: one fifo for input data and the other one for * output data. */ if (mkfifo(FIFO_RX, S_IRWXU) < 0) err(1, "mkfifo"); if (mkfifo(FIFO_TX, S_IRWXU) < 0) err(1, "mkfifo"); if ((fifo_rx_fd = open(FIFO_RX, O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) err(1, "open"); if ((fifo_tx_fd = open(FIFO_TX, O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) err(1, "open"); /*******************************************************************/ printf("[+] Opening the xterms\n"); for (i = 0; i < NB_CHANNELS; i++) { exec_xterm(&master_fd[i], slavename[i], i); slave_fd[i] = open(slavename[i], O_RDWR|O_SYNC, 0777); do { read(slave_fd[i], buf, 1); } while (*buf != '\n' && *buf != '\r'); } #if TEST_BENCH printf("opening test files\n"); if (mkfifo("test_rx.txt", S_IRWXU) < 0) err(1, "mkfifo"); if (mkfifo("test_tx.txt", S_IRWXU) < 0) err(1, "mkfifo"); if ((test_rx_fd = open("test_rx.txt", O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) err(1, "open"); if ((test_tx_fd = open("test_tx.txt", O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) err(1, "open"); #else printf("[+] Opening %s\n", DEVICE_PATH); if ((device_fd = open(DEVICE_PATH, O_RDWR|O_NOCTTY|O_NDELAY)) < 0) err(1, "open"); fcntl(device_fd, F_SETFL, 0); /* * Set the rs232 port */ struct termios newtio; printf("[+] Setting %s rs232 port\n", DEVICE_PATH); memset(&newtio, 0, sizeof(newtio)); init_tio(&newtio); if (tcsetattr(device_fd, TCSAFLUSH, &newtio) < 0) err(1, "tcsetattr"); #endif printf("[+] Launching the threads\n"); /* * Initialize the thread attributes. */ if (pthread_attr_init(&thread_attr) != 0) err(1, "pthread_attr_init"); if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) err(1, "pthread_attr_setdetachstate"); /* * Launch the threads. */ if (pthread_create(tid, &thread_attr, thread_mux_demux, NULL) != 0) err(1, "pthread_create"); if (pthread_create(tid + 1, &thread_attr, thread_read_rx, NULL) != 0) err(1, "pthread_create"); if (pthread_create(tid + 2, &thread_attr, thread_write_tx, NULL) != 0) err(1, "pthread_create"); #if TEST_BENCH char buftest[2]; unsigned char pkt[PACKET_SIZE]; sleep(1); while (1) { printf("ttyid> "); buftest[0] = getchar(); buftest[1] = '\n'; getchar(); pkt[PKT_TTY] = 0x80 | atoi(buftest); printf("cmd> "); do { pkt[PKT_DAT] = getchar(); write(test_rx_fd, pkt, PACKET_SIZE); } while (pkt[PKT_DAT] != '\n'); } #else while(1) sleep(1); #endif return 0; }