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 }