| 1 | /* | 
|---|
| 2 | ******************************************************************************* | 
|---|
| 3 | * Authors: | 
|---|
| 4 | *     Maxime Villard, 2017 | 
|---|
| 5 | *     Jankovic Marco, 01/07/2014 | 
|---|
| 6 | ******************************************************************************* | 
|---|
| 7 | */ | 
|---|
| 8 |  | 
|---|
| 9 | #include "common.h" | 
|---|
| 10 |  | 
|---|
| 11 | /* | 
|---|
| 12 | * tab containing all the slave side of a dev/pts | 
|---|
| 13 | * this part is swappable with other device | 
|---|
| 14 | */ | 
|---|
| 15 | int slave_fd[NB_CHANNELS]; | 
|---|
| 16 |  | 
|---|
| 17 | /* | 
|---|
| 18 | * tab containing all the masters that come from /dev/pts/ptmx | 
|---|
| 19 | * this part is swappable with other device | 
|---|
| 20 | */ | 
|---|
| 21 | int master_fd[NB_CHANNELS]; | 
|---|
| 22 |  | 
|---|
| 23 | /* | 
|---|
| 24 | * file descriptor of fifo rx and tx | 
|---|
| 25 | * file descriptor device_fd | 
|---|
| 26 | * nb_channels to multiplex | 
|---|
| 27 | */ | 
|---|
| 28 | int fifo_rx_fd; | 
|---|
| 29 | int fifo_tx_fd; | 
|---|
| 30 |  | 
|---|
| 31 | #if TEST_BENCH | 
|---|
| 32 | int test_rx_fd; // file descriptor that simulates RX buffer | 
|---|
| 33 | int test_tx_fd; // file descriptor that simulates TX buffer | 
|---|
| 34 | #else | 
|---|
| 35 | int device_fd; | 
|---|
| 36 | #endif | 
|---|
| 37 |  | 
|---|
| 38 | pthread_t tid[3]; | 
|---|
| 39 |  | 
|---|
| 40 | /* | 
|---|
| 41 | * Function that opens an xterm. You need a master side and a slave side. | 
|---|
| 42 | * master_fd -> contains master fd from /dev/ptmx | 
|---|
| 43 | * slavename -> slave name from /dev/pts | 
|---|
| 44 | */ | 
|---|
| 45 | static int exec_xterm(int *master_fd, char *slavename, int tty_id) | 
|---|
| 46 | { | 
|---|
| 47 | char buf[64]; | 
|---|
| 48 | char tty_name[64]; | 
|---|
| 49 |  | 
|---|
| 50 | *master_fd = posix_openpt(O_RDWR); | 
|---|
| 51 | grantpt(*master_fd); | 
|---|
| 52 | unlockpt(*master_fd); | 
|---|
| 53 |  | 
|---|
| 54 | if (ptsname_r(*master_fd, slavename, 64) != 0) | 
|---|
| 55 | perror("ptsname_r"); | 
|---|
| 56 |  | 
|---|
| 57 | printf("-> master_fd: %d\n", *master_fd); | 
|---|
| 58 | printf("-> slavename: %s\n", slavename); | 
|---|
| 59 |  | 
|---|
| 60 | snprintf(buf, sizeof(buf), "-S%s/%d", strrchr(slavename,'/')+1, *master_fd); | 
|---|
| 61 | snprintf(tty_name, sizeof(buf), "tty_%d", tty_id); | 
|---|
| 62 | if (!fork()) { | 
|---|
| 63 | execlp("xterm", "xterm", | 
|---|
| 64 | buf, | 
|---|
| 65 | "-T", tty_name, | 
|---|
| 66 | "-bg", "black", | 
|---|
| 67 | "-fg", "green", | 
|---|
| 68 | "-geometry", "80x25", | 
|---|
| 69 | NULL); | 
|---|
| 70 | _exit(1); | 
|---|
| 71 | } | 
|---|
| 72 |  | 
|---|
| 73 | return 0; | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | /* | 
|---|
| 77 | * Function that closes all file descriptors, kills all the threads and resets | 
|---|
| 78 | * the rs 232 port. | 
|---|
| 79 | */ | 
|---|
| 80 | void termination_handler(int signum) | 
|---|
| 81 | { | 
|---|
| 82 | int i; | 
|---|
| 83 | printf("termination handler %d \n",signum); | 
|---|
| 84 |  | 
|---|
| 85 | for (i = 0; i < 3; i++) { | 
|---|
| 86 | if (pthread_kill(tid[i], SIGTERM) < 0) | 
|---|
| 87 | err(1, "pthread_kill"); | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | if (close(fifo_rx_fd) < 0) | 
|---|
| 91 | err(1, "close"); | 
|---|
| 92 | if (close(fifo_tx_fd) < 0) | 
|---|
| 93 | err(1, "close"); | 
|---|
| 94 |  | 
|---|
| 95 | #if TEST_BENCH | 
|---|
| 96 | if (close(test_tx_fd) < 0) | 
|---|
| 97 | err(1, "close"); | 
|---|
| 98 | if (close(test_rx_fd) < 0) | 
|---|
| 99 | err(1, "close"); | 
|---|
| 100 | #else | 
|---|
| 101 | if (close(device_fd) < 0) | 
|---|
| 102 | err(1, "close"); | 
|---|
| 103 | #endif | 
|---|
| 104 |  | 
|---|
| 105 | for (i = 0; i < NB_CHANNELS; i++) { | 
|---|
| 106 | if (close(slave_fd[i]) < 0) | 
|---|
| 107 | err(1, "close"); | 
|---|
| 108 | if (close(master_fd[i]) < 0) | 
|---|
| 109 | err(1, "close"); | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 | exit(0); | 
|---|
| 113 | } | 
|---|
| 114 |  | 
|---|
| 115 | static void init_tio(struct termios *tio) | 
|---|
| 116 | { | 
|---|
| 117 | // Input flags - Turn off input processing | 
|---|
| 118 | // convert break to null byte, no CR to NL translation, | 
|---|
| 119 | // no NL to CR translation, don't mark parity errors or breaks | 
|---|
| 120 | // no input parity check, don't strip high bit off, | 
|---|
| 121 | // no XON/XOFF software flow control | 
|---|
| 122 | tio->c_cflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON | CRTSCTS); | 
|---|
| 123 | tio->c_cflag |= (CLOCAL | CREAD); | 
|---|
| 124 |  | 
|---|
| 125 | // Output flags - Turn off output processing | 
|---|
| 126 | // // no CR to NL translation, no NL to CR-NL translation, | 
|---|
| 127 | // // no NL to CR translation, no column 0 CR suppression, | 
|---|
| 128 | // // no Ctrl-D suppression, no fill characters, no case mapping, | 
|---|
| 129 | // // no local output processing | 
|---|
| 130 | tio->c_oflag &=~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OLCUC | OPOST); | 
|---|
| 131 | tio->c_oflag = 0; | 
|---|
| 132 |  | 
|---|
| 133 | //// No line processing: | 
|---|
| 134 | //// echo off, echo newline off, canonical mode off, | 
|---|
| 135 | //// extended input processing off, signal chars off | 
|---|
| 136 | //// | 
|---|
| 137 | tio->c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); | 
|---|
| 138 |  | 
|---|
| 139 | //// | 
|---|
| 140 | //// Turn off character processing | 
|---|
| 141 | //// clear current char size mask, no parity checking, | 
|---|
| 142 | //// no output processing, force 8 bit input | 
|---|
| 143 | //// 8N1 | 
|---|
| 144 | //// | 
|---|
| 145 | tio->c_cflag &= ~(CSIZE |PARENB|CSTOPB); | 
|---|
| 146 | tio->c_cflag |= CS8; | 
|---|
| 147 | //// | 
|---|
| 148 |  | 
|---|
| 149 | tio->c_iflag &= ~(IXON | IXOFF | IXANY | INPCK | ISTRIP ); | 
|---|
| 150 |  | 
|---|
| 151 | //// | 
|---|
| 152 | //// One input byte is enough to return from read() | 
|---|
| 153 | //// Inter-character timer off | 
|---|
| 154 | //// | 
|---|
| 155 | tio->c_cc[VMIN]  = 1; | 
|---|
| 156 | tio->c_cc[VTIME] = 0; | 
|---|
| 157 |  | 
|---|
| 158 | /* set baudrate */ | 
|---|
| 159 | if (cfsetispeed(tio, BAUDRATE) < 0 || cfsetospeed(tio, BAUDRATE) < 0) | 
|---|
| 160 | err(1, "error setting baudrate"); | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | int main(void) | 
|---|
| 164 | { | 
|---|
| 165 | char slavename[NB_CHANNELS][64]; | 
|---|
| 166 | int i; | 
|---|
| 167 | char buf[64]; | 
|---|
| 168 |  | 
|---|
| 169 | pthread_attr_t thread_attr; | 
|---|
| 170 |  | 
|---|
| 171 | /******************** signal handler ****************/ | 
|---|
| 172 | sigset_t sig_set; | 
|---|
| 173 | sigset_t sig_set_act; | 
|---|
| 174 |  | 
|---|
| 175 | sigemptyset(&sig_set); | 
|---|
| 176 | sigfillset(&sig_set); | 
|---|
| 177 | sigdelset(&sig_set, SIGINT); | 
|---|
| 178 | sigprocmask(SIG_BLOCK, &sig_set, NULL); | 
|---|
| 179 |  | 
|---|
| 180 | sigemptyset(&sig_set_act); | 
|---|
| 181 |  | 
|---|
| 182 | struct sigaction action; | 
|---|
| 183 | action.sa_handler = termination_handler; | 
|---|
| 184 | action.sa_mask = sig_set_act; | 
|---|
| 185 | action.sa_flags = 0; | 
|---|
| 186 | sigaction(SIGINT, &action, NULL); | 
|---|
| 187 |  | 
|---|
| 188 | /****************************************************/ | 
|---|
| 189 | printf("[+] device path: %s\n", DEVICE_PATH); | 
|---|
| 190 | printf("[+] nb_channels: %d\n", NB_CHANNELS); | 
|---|
| 191 |  | 
|---|
| 192 | /* | 
|---|
| 193 | * Opening 2 FIFOs: one fifo for input data and the other one for | 
|---|
| 194 | * output data. | 
|---|
| 195 | */ | 
|---|
| 196 | if (mkfifo(FIFO_RX, S_IRWXU) < 0) | 
|---|
| 197 | err(1, "mkfifo"); | 
|---|
| 198 | if (mkfifo(FIFO_TX, S_IRWXU) < 0) | 
|---|
| 199 | err(1, "mkfifo"); | 
|---|
| 200 |  | 
|---|
| 201 | if ((fifo_rx_fd = open(FIFO_RX, O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) | 
|---|
| 202 | err(1, "open"); | 
|---|
| 203 | if ((fifo_tx_fd = open(FIFO_TX, O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) | 
|---|
| 204 | err(1, "open"); | 
|---|
| 205 | /*******************************************************************/ | 
|---|
| 206 |  | 
|---|
| 207 | printf("[+] Opening the xterms\n"); | 
|---|
| 208 |  | 
|---|
| 209 | for (i = 0; i < NB_CHANNELS; i++) { | 
|---|
| 210 | exec_xterm(&master_fd[i], slavename[i], i); | 
|---|
| 211 | slave_fd[i] = open(slavename[i], O_RDWR|O_SYNC, 0777); | 
|---|
| 212 | do { | 
|---|
| 213 | read(slave_fd[i], buf, 1); | 
|---|
| 214 | } while (*buf != '\n' && *buf != '\r'); | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | #if TEST_BENCH | 
|---|
| 218 | printf("opening test files\n"); | 
|---|
| 219 | if (mkfifo("test_rx.txt", S_IRWXU) < 0) | 
|---|
| 220 | err(1, "mkfifo"); | 
|---|
| 221 | if (mkfifo("test_tx.txt", S_IRWXU) < 0) | 
|---|
| 222 | err(1, "mkfifo"); | 
|---|
| 223 | if ((test_rx_fd = open("test_rx.txt", O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) | 
|---|
| 224 | err(1, "open"); | 
|---|
| 225 | if ((test_tx_fd = open("test_tx.txt", O_RDWR|O_SYNC|O_NONBLOCK, 0777)) < 0) | 
|---|
| 226 | err(1, "open"); | 
|---|
| 227 | #else | 
|---|
| 228 | printf("[+] Opening %s\n", DEVICE_PATH); | 
|---|
| 229 | if ((device_fd = open(DEVICE_PATH, O_RDWR|O_NOCTTY|O_NDELAY)) < 0) | 
|---|
| 230 | err(1, "open"); | 
|---|
| 231 | fcntl(device_fd, F_SETFL, 0); | 
|---|
| 232 |  | 
|---|
| 233 | /* | 
|---|
| 234 | * Set the rs232 port | 
|---|
| 235 | */ | 
|---|
| 236 | struct termios newtio; | 
|---|
| 237 |  | 
|---|
| 238 | printf("[+] Setting %s rs232 port\n", DEVICE_PATH); | 
|---|
| 239 |  | 
|---|
| 240 | memset(&newtio, 0, sizeof(newtio)); | 
|---|
| 241 | init_tio(&newtio); | 
|---|
| 242 |  | 
|---|
| 243 | if (tcsetattr(device_fd, TCSAFLUSH, &newtio) < 0) | 
|---|
| 244 | err(1, "tcsetattr"); | 
|---|
| 245 | #endif | 
|---|
| 246 |  | 
|---|
| 247 | printf("[+] Launching the threads\n"); | 
|---|
| 248 |  | 
|---|
| 249 | /* | 
|---|
| 250 | * Initialize the thread attributes. | 
|---|
| 251 | */ | 
|---|
| 252 | if (pthread_attr_init(&thread_attr) != 0) | 
|---|
| 253 | err(1, "pthread_attr_init"); | 
|---|
| 254 | if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) | 
|---|
| 255 | err(1, "pthread_attr_setdetachstate"); | 
|---|
| 256 |  | 
|---|
| 257 | /* | 
|---|
| 258 | * Launch the threads. | 
|---|
| 259 | */ | 
|---|
| 260 | if (pthread_create(tid, &thread_attr, thread_mux_demux, NULL) != 0) | 
|---|
| 261 | err(1, "pthread_create"); | 
|---|
| 262 | if (pthread_create(tid + 1, &thread_attr, thread_read_rx, NULL) != 0) | 
|---|
| 263 | err(1, "pthread_create"); | 
|---|
| 264 | if (pthread_create(tid + 2, &thread_attr, thread_write_tx, NULL) != 0) | 
|---|
| 265 | err(1, "pthread_create"); | 
|---|
| 266 |  | 
|---|
| 267 | #if TEST_BENCH | 
|---|
| 268 | char buftest[2]; | 
|---|
| 269 | unsigned char pkt[PACKET_SIZE]; | 
|---|
| 270 |  | 
|---|
| 271 | sleep(1); | 
|---|
| 272 |  | 
|---|
| 273 | while (1) { | 
|---|
| 274 | printf("ttyid> "); | 
|---|
| 275 |  | 
|---|
| 276 | buftest[0] = getchar(); | 
|---|
| 277 | buftest[1] = '\n'; | 
|---|
| 278 | getchar(); | 
|---|
| 279 |  | 
|---|
| 280 | pkt[PKT_TTY] = 0x80 | atoi(buftest); | 
|---|
| 281 |  | 
|---|
| 282 | printf("cmd> "); | 
|---|
| 283 | do { | 
|---|
| 284 | pkt[PKT_DAT] = getchar(); | 
|---|
| 285 | write(test_rx_fd, pkt, PACKET_SIZE); | 
|---|
| 286 | } while (pkt[PKT_DAT] != '\n'); | 
|---|
| 287 | } | 
|---|
| 288 | #else | 
|---|
| 289 | while(1) | 
|---|
| 290 | sleep(1); | 
|---|
| 291 | #endif | 
|---|
| 292 |  | 
|---|
| 293 | return 0; | 
|---|
| 294 | } | 
|---|
| 295 |  | 
|---|