#include #include #include #include #include #include #include #include #include #include #include #include #define TEMP_FAILURE_RETRY(expression) \ (__extension__ \ ({ long int __result; \ do __result = (long int) (expression); \ while (__result == -1L && errno == EINTR); \ __result; })) struct termios tmpattr; void settermattr (char client_connected) { if (client_connected) { struct termios attr; attr = tmpattr; attr.c_iflag = 0; attr.c_lflag &= ~(ICANON|ECHO|ISIG); tcsetattr(STDIN_FILENO, TCSANOW, &attr); } else { tcsetattr(STDIN_FILENO, TCSANOW, &tmpattr); } } int sock, client = -1; void handler_sigint (int signum) { if (client > -1) close(client); close(sock); settermattr(0); fprintf(stderr, "Catched SIGINT, quitting...\n\n"); exit(EXIT_SUCCESS); } #define UINT_TO_CHARBUFFER(num,buf) { \ (buf)[0] = (num >> 24) & 0xff; \ (buf)[1] = (num >> 16) & 0xff; \ (buf)[2] = (num >> 8) & 0xff; \ (buf)[3] = (num) & 0xff; \ } void handler_sigwinch (int signum) { int tmperrno = errno; if (client == -1) return; struct winsize ws; if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) goto exit; char buffer[18]; buffer[0] = 0x00; buffer[1] = 0x01; // setting window size UINT_TO_CHARBUFFER((unsigned int) ws.ws_row, &buffer[2]); UINT_TO_CHARBUFFER((unsigned int) ws.ws_col, &buffer[6]); UINT_TO_CHARBUFFER((unsigned int) ws.ws_xpixel, &buffer[10]); UINT_TO_CHARBUFFER((unsigned int) ws.ws_ypixel, &buffer[14]); write(client, buffer, 18); exit: errno = tmperrno; } int main (int argc, char ** argv) { fd_set active_set, read_set; struct sockaddr_in name; unsigned short port; if (argc < 2) { printf("usage: %s port\n\n", argv[0]); exit(EXIT_FAILURE); } name.sin_family = AF_INET; name.sin_addr.s_addr = htonl(INADDR_ANY); name.sin_port = htons(atoi(argv[1])); sock = socket(PF_INET, SOCK_STREAM, 0); unsigned int sockopt = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) < 0) { perror("setsockopt"); close(sock); exit(EXIT_FAILURE); } if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { perror("bind"); close(sock); exit(EXIT_FAILURE); } if (listen(sock, 1)) { perror("listen"); close(sock); exit(EXIT_FAILURE); } FD_ZERO(&active_set); FD_SET(sock, &active_set); FD_SET(STDIN_FILENO, &active_set); signal(SIGINT, handler_sigint); signal(SIGWINCH, handler_sigwinch); tcgetattr(STDIN_FILENO, &tmpattr); while (1) { read_set = active_set; if (TEMP_FAILURE_RETRY(select(FD_SETSIZE, &read_set, NULL, NULL, NULL)) < 0) { perror("select"); exit(EXIT_FAILURE); } if (FD_ISSET(sock, &read_set)) { struct sockaddr_in clientname; socklen_t len; int n = accept(sock, (struct sockaddr *) &clientname, &len); if (n < 0) { perror("accept"); } else { char clientip[16]; inet_ntop(AF_INET, (void *) &clientname.sin_addr, (char *) &clientip, 16); fprintf(stderr, "Accepted %s:%i... ", clientip, ntohs(clientname.sin_port)); if (client > -1) { fprintf(stderr, "rejecting!\n"); close(n); } else { client = n; unsigned char magic[4] = {0x12, 0x34, 0x56, 0x78}; unsigned char cmp[4]; if (read(client, cmp, 4) <= 0) { fprintf(stderr, "cannot read magic number!\n"); goto close_client; } if (strncmp(magic, cmp, 4)) { fprintf(stderr, "magic number verification failed!\n"); goto close_client; } if (write(client, magic, 4) <= 0) { fprintf(stderr, "cannot write magic number!\n"); goto close_client; } fprintf(stderr, "connected\n"); FD_SET(client, &active_set); settermattr(1); raise(SIGWINCH); } } } if (FD_ISSET(STDIN_FILENO, &read_set)) { char buffer[1028]; ssize_t len; do { len = read(STDIN_FILENO, buffer+4, 1024); if (len <= 0) goto exit_std; if (client > -1) { buffer[0] = buffer[1] = 0x00; buffer[2] = (len >> 8) & 0xff; buffer[3] = len & 0xff; if (write(client, buffer, len+4) <= 0) goto close_client; } } while (len == 1024); } if (client > -1 && FD_ISSET(client, &read_set)) { char buffer[1024]; ssize_t len; do { len = read(client, buffer, 1024); if (len <= 0) goto close_client; if (write(STDOUT_FILENO, buffer, len) <= 0) goto exit_std; } while (len == 1024); } continue; close_client: FD_CLR(client, &active_set); if (client > -1) close(client); client = -1; settermattr(0); fprintf(stderr, "Closing connection with client!\n"); } exit_std: perror("standard IO error"); if (client > -1) close(client); close(sock); settermattr(0); exit(EXIT_FAILURE); }