1 /* 2 * RCONFIG/SERVER.C 3 * 4 * $DragonFly: src/sbin/rconfig/server.c,v 1.1 2004/06/18 02:46:46 dillon Exp $ 5 */ 6 7 #include "defs.h" 8 9 static void server_connection(int fd); 10 static void service_packet_loop(int fd); 11 static void server_chld_exit(int signo); 12 static int nconnects; 13 14 void 15 doServer(void) 16 { 17 tag_t tag; 18 19 /* 20 * Listen on one or more UDP and TCP addresses, fork for each one. 21 */ 22 signal(SIGCHLD, SIG_IGN); 23 for (tag = AddrBase; tag; tag = tag->next) { 24 struct sockaddr_in sain; 25 char *host; 26 int lfd; 27 int fd; 28 int on = 1; 29 30 bzero(&sain, sizeof(sain)); 31 if (tag->name == NULL) { 32 sain.sin_addr.s_addr = INADDR_ANY; 33 host = "<any>"; 34 } else { 35 host = strdup(tag->name); 36 if (inet_aton(host, &sain.sin_addr) == 0) { 37 struct hostent *hp; 38 if ((hp = gethostbyname2(host, AF_INET)) == NULL) { 39 fprintf(stderr, "Unable to resolve %s\n", host); 40 exit(1); 41 } 42 bcopy(hp->h_addr_list[0], &sain.sin_addr, hp->h_length); 43 free(host); 44 host = strdup(hp->h_name); 45 endhostent(); 46 } 47 } 48 sain.sin_port = htons(257); 49 sain.sin_len = sizeof(sain); 50 sain.sin_family = AF_INET; 51 fflush(stdout); 52 if (fork() == 0) { 53 if ((lfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { 54 fprintf(stderr, "%s: socket: %s\n", host, strerror(errno)); 55 exit(1); 56 } 57 setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 58 if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) { 59 fprintf(stderr, "%s: bind: %s\n", host, strerror(errno)); 60 exit(1); 61 } 62 if (listen(lfd, 20) < 0) { 63 fprintf(stderr, "%s: listen: %s\n", host, strerror(errno)); 64 exit(1); 65 } 66 signal(SIGCHLD, server_chld_exit); 67 for (;;) { 68 int slen = sizeof(sain); 69 fd = accept(lfd, (void *)&sain, &slen); 70 if (fd < 0) { 71 if (errno != EINTR) 72 break; 73 continue; 74 } 75 ++nconnects; /* XXX sigblock/sigsetmask */ 76 if (fork() == 0) { 77 close(lfd); 78 server_connection(fd); 79 exit(0); 80 } 81 close(fd); 82 } 83 exit(0); 84 } 85 if (fork() == 0) { 86 if ((lfd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) { 87 fprintf(stderr, "%s: socket: %s\n", host, strerror(errno)); 88 exit(1); 89 } 90 if (bind(lfd, (void *)&sain, sizeof(sain)) < 0) { 91 fprintf(stderr, "%s: bind: %s\n", host, strerror(errno)); 92 exit(1); 93 } 94 service_packet_loop(lfd); 95 exit(1); 96 } 97 } 98 while (wait(NULL) > 0 || errno != EINTR) 99 ; 100 } 101 102 static 103 void 104 server_chld_exit(int signo) 105 { 106 while (wait3(NULL, WNOHANG, NULL) > 0) 107 --nconnects; 108 } 109 110 static 111 void 112 server_connection(int fd) 113 { 114 FILE *fi; 115 FILE *fo; 116 char buf[256]; 117 char *scan; 118 const char *cmd; 119 const char *name; 120 121 fi = fdopen(fd, "r"); 122 fo = fdopen(dup(fd), "w"); 123 124 if (gethostname(buf, sizeof(buf)) == 0) { 125 fprintf(fo, "108 HELLO SERVER=%s\r\n", buf); 126 } else { 127 fprintf(fo, "108 HELLO\r\n", buf); 128 } 129 fflush(fo); 130 131 while (fgets(buf, sizeof(buf), fi) != NULL) { 132 scan = buf; 133 cmd = parse_str(&scan, PAS_ALPHA); 134 if (cmd == NULL) { 135 fprintf(fo, "502 Illegal Command String\r\n"); 136 } else if (strcasecmp(cmd, "VAR") == 0) { 137 fprintf(fo, "100 OK\r\n"); 138 } else if (strcasecmp(cmd, "TAG") == 0) { 139 if ((name = parse_str(&scan, PAS_ALPHA|PAS_NUMERIC)) == NULL) { 140 fprintf(fo, "401 Illegal Tag\r\n"); 141 } else { 142 char *path = NULL; 143 FILE *fp; 144 asprintf(&path, "%s/%s.sh", TagDir, name); 145 if ((fp = fopen(path, "r")) == NULL) { 146 fprintf(fo, "402 '%s' Not Found\r\n", name); 147 } else { 148 long bytes; 149 int n; 150 int error = 0; 151 152 fseek(fp, 0L, 2); 153 bytes = ftell(fp); 154 fseek(fp, 0L, 0); 155 fprintf(fo, "201 SIZE=%ld\r\n", bytes); 156 while (bytes > 0) { 157 n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes; 158 n = fread(buf, 1, n, fp); 159 if (n <= 0) { 160 error = 1; 161 break; 162 } 163 if (fwrite(buf, 1, n, fo) != n) { 164 error = 1; 165 break; 166 } 167 bytes -= n; 168 } 169 fclose(fp); 170 if (bytes > 0 && ferror(fo) == 0) { 171 bzero(buf, sizeof(buf)); 172 while (bytes > 0) { 173 n = (bytes > sizeof(buf)) ? sizeof(buf) : bytes; 174 if (fwrite(buf, 1, n, fo) != n) 175 break; 176 bytes -= n; 177 } 178 } 179 fprintf(fo, "202 ERROR=%d\r\n", error); 180 } 181 free(path); 182 } 183 } else if (strcasecmp(cmd, "IDLE") == 0) { 184 if ((name = parse_str(&scan, PAS_ANY)) == NULL) { 185 fprintf(fo, "401 Illegal String\r\n"); 186 } else { 187 fprintf(fo, "109 %s\r\n", name); 188 } 189 } else if (strcasecmp(cmd, "QUIT") == 0) { 190 fprintf(fo, "409 Bye!\r\n"); 191 break; 192 } else { 193 fprintf(fo, "501 Unknown Command\r\n"); 194 } 195 fflush(fo); 196 } 197 fclose(fi); 198 fclose(fo); 199 } 200 201 /* 202 * UDP packet loop. For now just handle one request per packet. Note that 203 * since the protocol is designed to be used in a broadcast environment, 204 * we only respond when we have something to contribute. 205 */ 206 static 207 void 208 service_packet_loop(int fd) 209 { 210 struct sockaddr_in sain; 211 char ibuf[256+1]; 212 char obuf[256+1]; 213 int sain_len; 214 int n; 215 char *scan; 216 const char *cmd; 217 const char *name; 218 219 for (;;) { 220 sain_len = sizeof(sain); 221 n = recvfrom(fd, ibuf, sizeof(ibuf) - 1, 0, (void *)&sain, &sain_len); 222 if (n < 0) { 223 if (errno == EINTR) 224 continue; 225 break; 226 } 227 ibuf[n] = 0; 228 n = 0; 229 scan = ibuf; 230 cmd = parse_str(&scan, PAS_ALPHA); 231 if (cmd == NULL) { 232 ; 233 } else if (strcasecmp(cmd, "TAG") == 0) { 234 if ((name = parse_str(&scan, PAS_ALPHA|PAS_NUMERIC)) != NULL) { 235 char *path = NULL; 236 struct stat st; 237 asprintf(&path, "%s/%s.sh", TagDir, name); 238 if (stat(path, &st) == 0) { 239 snprintf(obuf, sizeof(obuf), "101 TAG=%s\r\n", name); 240 n = strlen(obuf); 241 } 242 free(path); 243 } 244 } 245 if (n) 246 sendto(fd, obuf, n, 0, (void *)&sain, sain_len); 247 } 248 } 249 250