github.com/nycdavid/zeus@v0.0.0-20201208104106-9ba439429e03/vagrant/ext/file-listener/file-listener.cpp (about)

     1  #include <set>
     2  #include <string>
     3  using namespace std;
     4  
     5  #include <arpa/inet.h>
     6  #include <errno.h>
     7  #include <stdarg.h>
     8  #include <stdio.h>
     9  #include <stdlib.h>
    10  #include <string.h>
    11  #include <sys/types.h>
    12  #include <sys/select.h>
    13  #include <sys/socket.h>
    14  #include <time.h>
    15  #include <unistd.h>
    16  
    17  set<string> watched_files;
    18  
    19  void log(const char *fmt, ...)
    20  {
    21  #ifdef DEBUG
    22      va_list ap;
    23      FILE *logfile;
    24  
    25      va_start(ap, fmt);
    26  
    27      logfile = fopen("/tmp/zeus-debug.log", "a");
    28      vfprintf(logfile, fmt, ap);
    29      fclose(logfile);
    30  
    31      va_end(ap);
    32  #endif
    33  }
    34  
    35  int start_server(int port)
    36  {
    37      int sock, ssock, opt;
    38      struct sockaddr_in addr;
    39      socklen_t addrlen;
    40  
    41      sock = socket(AF_INET, SOCK_STREAM, 0);
    42      if (sock == -1) {
    43          log("error creating socket: %s\n", strerror(errno));
    44          return -1;
    45      }
    46  
    47      opt = 1;
    48      if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
    49          log("error setting socket options: %s\n", strerror(errno));
    50          close(sock);
    51          return -1;
    52      }
    53  
    54      memset(&addr, 0, sizeof(addr));
    55      addr.sin_family = AF_INET;
    56      addr.sin_port = htons(port);
    57      addrlen = sizeof(addr);
    58      if (bind(sock, (struct sockaddr *)&addr, addrlen)) {
    59          log("error binding to port %d: %s\n", port, strerror(errno));
    60          close(sock);
    61          return -1;
    62      }
    63  
    64      if (listen(sock, 0)) {
    65          log("error listening on socket: %s\n", strerror(errno));
    66          close(sock);
    67          return -1;
    68      }
    69  
    70      ssock = accept(sock, (struct sockaddr *)&addr, &addrlen);
    71      if (ssock == -1) {
    72          log("error while accepting a connection: %s\n", strerror(errno));
    73          close(sock);
    74          return -1;
    75      }
    76      close(sock);
    77  
    78      return ssock;
    79  }
    80  
    81  int handle_modified_file(int sock)
    82  {
    83      ssize_t bytes;
    84      char buf[4096];
    85  
    86      bytes = recv(sock, buf, sizeof(buf) - 1, 0);
    87      if (bytes == -1) {
    88          log("error in recv: %s\n", strerror(errno));
    89      }
    90      else {
    91          buf[bytes] = '\0';
    92          if (bytes > 0 && buf[bytes - 1] == '\n') {
    93              buf[bytes - 1] = '\0';
    94          }
    95          if (watched_files.count(string(buf))) {
    96              log("*** reloading ***\n");
    97              printf("%s\n", buf);
    98              fflush(stdout);
    99          }
   100      }
   101  
   102      return bytes;
   103  }
   104  
   105  int handle_file_to_watch(int fd, int sock)
   106  {
   107      char buf[4096];
   108  
   109      if (!fgets(buf, 4096, stdin)) {
   110          log("error in read: %s\n", strerror(errno));
   111          return 0;
   112      }
   113      else {
   114          size_t len;
   115  
   116          len = strlen(buf);
   117          if (len > 0) {
   118              if (send(sock, buf, len, 0) == -1) {
   119                  log("failed to send '%s' to the socket: %s",
   120                      buf, strerror(errno));
   121              }
   122              buf[len - 1] = '\0';
   123              log("starting to watch '%s'\n", buf);
   124              watched_files.insert(string(buf));
   125          }
   126  
   127          return len;
   128      }
   129  }
   130  
   131  int main(int argc, char *argv[])
   132  {
   133      int arg;
   134      unsigned short port;
   135  
   136      if (argc < 2) {
   137          log("usage: %s <port>\n", argv[0]);
   138          exit(1);
   139      }
   140      arg = atoi(argv[1]);
   141      if (arg <= 0 || arg >= 65536) {
   142          log("invalid port %s\n", argv[1]);
   143          log("usage: %s <port>\n", argv[0]);
   144          exit(1);
   145      }
   146      port = arg;
   147  
   148      for (;;) {
   149          int ssock;
   150  
   151          ssock = start_server(port);
   152          if (ssock == -1) {
   153              struct timespec tm;
   154              tm.tv_sec = 0;
   155              tm.tv_nsec = 100000000;
   156              nanosleep(&tm, NULL);
   157              continue;
   158          }
   159  
   160          for (;;) {
   161              fd_set fds;
   162              int ret;
   163  
   164              FD_ZERO(&fds);
   165              FD_SET(0, &fds);
   166              FD_SET(ssock, &fds);
   167              ret = select(ssock + 1, &fds, NULL, NULL, NULL);
   168              if (ret == -1) {
   169                  continue;
   170              }
   171              else {
   172                  if (feof(stdin)) {
   173                      log("stdin was closed, exiting");
   174                      exit(1);
   175                  }
   176                  if (FD_ISSET(0, &fds)) {
   177                      ret = handle_file_to_watch(0, ssock);
   178                      if (ret <= 0) {
   179                          log("lost stdin, exiting");
   180                          exit(1);
   181                      }
   182                  }
   183                  if (FD_ISSET(ssock, &fds)) {
   184                      ret = handle_modified_file(ssock);
   185                      if (ret <= 0) {
   186                          break;
   187                      }
   188                  }
   189              }
   190          }
   191  
   192          close(ssock);
   193      }
   194  }