| 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 | |
|---|