source of highlighter
plain | download
    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