1 #include <errno.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <unistd.h> 6 #include <sys/types.h> 7 #include <sys/socket.h> 8 #include <sys/ioctl.h> 9 #include <netinet/in.h> 10 #include <arpa/inet.h> 11 #include <signal.h> 12 #include <termios.h> 13 14 #define TEMP_FAILURE_RETRY(expression) \ 15 (__extension__ \ 16 ({ long int __result; \ 17 do __result = (long int) (expression); \ 18 while (__result == -1L && errno == EINTR); \ 19 __result; })) 20 21 struct termios tmpattr; 22 23 void settermattr (char client_connected) { 24 if (client_connected) { 25 struct termios attr; 26 attr = tmpattr; 27 attr.c_iflag = 0; 28 attr.c_lflag &= ~(ICANON|ECHO|ISIG); 29 tcsetattr(STDIN_FILENO, TCSANOW, &attr); 30 } else { 31 tcsetattr(STDIN_FILENO, TCSANOW, &tmpattr); 32 } 33 } 34 35 int sock, client = -1; 36 37 void handler_sigint (int signum) { 38 if (client > -1) 39 close(client); 40 close(sock); 41 settermattr(0); 42 fprintf(stderr, "Catched SIGINT, quitting...\n\n"); 43 exit(EXIT_SUCCESS); 44 } 45 46 #define UINT_TO_CHARBUFFER(num,buf) { \ 47 (buf)[0] = (num >> 24) & 0xff; \ 48 (buf)[1] = (num >> 16) & 0xff; \ 49 (buf)[2] = (num >> 8) & 0xff; \ 50 (buf)[3] = (num) & 0xff; \ 51 } 52 53 void handler_sigwinch (int signum) { 54 int tmperrno = errno; 55 if (client == -1) 56 return; 57 struct winsize ws; 58 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) 59 goto exit; 60 char buffer[18]; 61 buffer[0] = 0x00; 62 buffer[1] = 0x01; // setting window size 63 UINT_TO_CHARBUFFER((unsigned int) ws.ws_row, &buffer[2]); 64 UINT_TO_CHARBUFFER((unsigned int) ws.ws_col, &buffer[6]); 65 UINT_TO_CHARBUFFER((unsigned int) ws.ws_xpixel, &buffer[10]); 66 UINT_TO_CHARBUFFER((unsigned int) ws.ws_ypixel, &buffer[14]); 67 write(client, buffer, 18); 68 exit: 69 errno = tmperrno; 70 } 71 72 int main (int argc, char ** argv) { 73 fd_set active_set, read_set; 74 struct sockaddr_in name; 75 unsigned short port; 76 77 if (argc < 2) { 78 printf("usage: %s port\n\n", argv[0]); 79 exit(EXIT_FAILURE); 80 } 81 82 name.sin_family = AF_INET; 83 name.sin_addr.s_addr = htonl(INADDR_ANY); 84 name.sin_port = htons(atoi(argv[1])); 85 86 sock = socket(PF_INET, SOCK_STREAM, 0); 87 unsigned int sockopt = 1; 88 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) < 0) { 89 perror("setsockopt"); 90 close(sock); 91 exit(EXIT_FAILURE); 92 } 93 94 if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { 95 perror("bind"); 96 close(sock); 97 exit(EXIT_FAILURE); 98 } 99 100 if (listen(sock, 1)) { 101 perror("listen"); 102 close(sock); 103 exit(EXIT_FAILURE); 104 } 105 106 FD_ZERO(&active_set); 107 FD_SET(sock, &active_set); 108 FD_SET(STDIN_FILENO, &active_set); 109 110 signal(SIGINT, handler_sigint); 111 signal(SIGWINCH, handler_sigwinch); 112 113 tcgetattr(STDIN_FILENO, &tmpattr); 114 115 while (1) { 116 read_set = active_set; 117 if (TEMP_FAILURE_RETRY(select(FD_SETSIZE, &read_set, NULL, NULL, NULL)) < 0) { 118 perror("select"); 119 exit(EXIT_FAILURE); 120 } 121 if (FD_ISSET(sock, &read_set)) { 122 struct sockaddr_in clientname; 123 socklen_t len; 124 int n = accept(sock, (struct sockaddr *) &clientname, &len); 125 if (n < 0) { 126 perror("accept"); 127 } else { 128 char clientip[16]; 129 inet_ntop(AF_INET, (void *) &clientname.sin_addr, (char *) &clientip, 16); 130 fprintf(stderr, "Accepted %s:%i... ", clientip, ntohs(clientname.sin_port)); 131 if (client > -1) { 132 fprintf(stderr, "rejecting!\n"); 133 close(n); 134 } else { 135 client = n; 136 unsigned char magic[4] = {0x12, 0x34, 0x56, 0x78}; 137 unsigned char cmp[4]; 138 if (read(client, cmp, 4) <= 0) { 139 fprintf(stderr, "cannot read magic number!\n"); 140 goto close_client; 141 } 142 if (strncmp(magic, cmp, 4)) { 143 fprintf(stderr, "magic number verification failed!\n"); 144 goto close_client; 145 } 146 if (write(client, magic, 4) <= 0) { 147 fprintf(stderr, "cannot write magic number!\n"); 148 goto close_client; 149 } 150 fprintf(stderr, "connected\n"); 151 FD_SET(client, &active_set); 152 settermattr(1); 153 raise(SIGWINCH); 154 } 155 } 156 } 157 if (FD_ISSET(STDIN_FILENO, &read_set)) { 158 char buffer[1028]; 159 ssize_t len; 160 do { 161 len = read(STDIN_FILENO, buffer+4, 1024); 162 if (len <= 0) 163 goto exit_std; 164 if (client > -1) { 165 buffer[0] = buffer[1] = 0x00; 166 buffer[2] = (len >> 8) & 0xff; 167 buffer[3] = len & 0xff; 168 if (write(client, buffer, len+4) <= 0) 169 goto close_client; 170 } 171 } while (len == 1024); 172 } 173 if (client > -1 && FD_ISSET(client, &read_set)) { 174 char buffer[1024]; 175 ssize_t len; 176 do { 177 len = read(client, buffer, 1024); 178 if (len <= 0) 179 goto close_client; 180 if (write(STDOUT_FILENO, buffer, len) <= 0) 181 goto exit_std; 182 } while (len == 1024); 183 } 184 continue; 185 close_client: 186 FD_CLR(client, &active_set); 187 if (client > -1) 188 close(client); 189 client = -1; 190 settermattr(0); 191 fprintf(stderr, "Closing connection with client!\n"); 192 } 193 exit_std: 194 perror("standard IO error"); 195 if (client > -1) 196 close(client); 197 close(sock); 198 settermattr(0); 199 exit(EXIT_FAILURE); 200 } 201