/* server.c -- server TCP program, adapted from Comer's book */ /* Usage: srv [-d] [port] [amplcmd] */ #ifndef unix #define WIN32 #include #include #else #include #include #include #include #include #include #endif #include #include #include #include #include FILE *logfp = stderr; int port = 5194; /* unlikely port */ char *amplcmd[] = { "ampl", "-b", 0 }; #define dfprintf if (dbg) fprintf int dbg = 1; #define eq(s1, s2) (strcmp(s1, s2) == 0) int inetd = 0; /* 1 => running from inetd */ #define QLEN 5 /* input queue length */ struct protoent *ptrp; /* protocol table entry */ struct sockaddr_in sad; /* server adr */ struct sockaddr_in cad; /* client adr */ void fatal(char *); int start(char **prog, int *fdw, int *fdr); int runsrv(int sd2); int runampl(int); int main(int argc, char *argv[]) { int val, sd; if (argc > 1 && eq(argv[1], "-?")) { fprintf(stderr, "Usage: srv [-d] [port] [amplcmd]\n"); exit(0); } for ( ; argc > 1 && argv[1][0] == '-'; argc--, argv++) { if (eq(argv[1], "-d")) { dbg = 0; } else if (strcmp(argv[1], "-cd") == 0) { chdir(argv[2]); argc--; argv++; } else if (eq(argv[1], "-l")) { time_t now; time(&now); logfp = freopen(argv[2], "a", stderr); fprintf(logfp, "\n%s\n", ctime(&now)); argc--; argv++; } else if (eq(argv[1], "-i")) { /* start from inetd */ inetd++; } } memset((char *) &sad, 0, sizeof(sad)); sad.sin_family = AF_INET; /* internet */ sad.sin_addr.s_addr = INADDR_ANY; /* local IP address */ if (argc > 1 && atoi(argv[1]) > 0) port = atoi(argv[1]); if (argc > 2) amplcmd[0] = argv[2]; if (inetd) { fprintf(logfp, "srv: running from inetd\n"); runsrv(0); exit(1); } if (port > 0) sad.sin_port = htons((u_short) port); if ((ptrp = getprotobyname("tcp")) == NULL) { fprintf(logfp, "srv: can't map TCP to protocol number\n"); perror(""); exit(1); } if ((sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto)) < 0) { fprintf(logfp, "srv: socket creation failed\n"); perror(""); exit(1); } if (bind(sd, (struct sockaddr *) &sad, sizeof(sad)) < 0) { fprintf(logfp, "srv: bind %d failed\n", port); perror(""); exit(1); } val = 1; setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(int)); if (listen(sd, QLEN) < 0) { fprintf(logfp, "srv: listen failed\n"); perror(""); exit(1); } for (;;) { int alen = sizeof(cad), sd2; fprintf(logfp, "about to accept\n"); if ((sd2 = accept(sd, (struct sockaddr *) &cad, &alen)) < 0) { fprintf(logfp, "srv: accept failed\n"); perror(""); exit(1); } fprintf(logfp, "srv: accepted\n"); if (fork() == 0) { close(sd); /* child does this */ runsrv(sd2); exit(0); } close(sd2); /* parent does this */ } } void filenames(char *pat, char *buf) /* long list of filenames */ { DIR *dp; struct dirent *dirp; char *MODELDIR = "."; /* for now */ buf[0] = 0; if ((dp = opendir(MODELDIR)) == NULL) { strcat(buf, "\n"); return; } for ( ; (dirp = readdir(dp)) != NULL; ) { if (eq(pat, dirp->d_name + strlen(dirp->d_name)-strlen(pat))) { strcat(buf, dirp->d_name); strcat(buf, "\n"); } } closedir(dp); } int getline(int fd, char *buf) /* unbuffered input */ { char c; int i; for (i = c = 0; read(fd, &c, 1) > 0 && c != '\n'; i++) buf[i] = c; buf[i] = 0; return (c == '\n') ? i : -1; } int runsrv(int sd2) { char cmd[100], opt[100], buf[2000], buf2[2000]; for (; getline(sd2, buf) >= 0; ) { /* weird botched protocol: rcv expects to see "type\nreal data" */ /* so files, get (and ultimately others) add this at front. */ sscanf(buf, "%*s %s %s", cmd, opt); /* skip count */ dfprintf(logfp, "srv got [%s] [%s] [%s]\n", buf, cmd, opt); if (eq(cmd, "files")) { /* filenames */ filenames(opt, buf2); /* opt is .mod or .dat */ sprintf(buf, "%d files\n%s", 6+strlen(buf2), buf2); write(sd2, buf, strlen(buf)); } else if (eq(cmd, "cd")) { chdir(opt); } else if (eq(cmd, "echo")) { strcat(buf, "\n"); sprintf(buf2, "%d %s", strlen(buf), buf); write(sd2, buf2, strlen(buf2)); } else if (eq(cmd, "ampl")) { sprintf(buf, "%d %s", strlen("prompt1\n"), "prompt1\n"); write(sd2, buf, strlen(buf)); runampl(sd2); } else if (eq(cmd, "get")) { /* content of file */ int i, c; FILE *fin; fin = fopen(opt, "r"); for (i = 0; (c = getc(fin)) != EOF; i++) buf2[i] = c; buf2[i] = 0; sprintf(buf, "%d get\n%s", 4+strlen(buf2), buf2); write(sd2, buf, strlen(buf)); } else { sprintf(buf, "%d %s", strlen("srv cmd error\n"), "srv cmd error\n"); write(sd2, buf, strlen(buf)); } sprintf(buf, "%d %s", strlen("prompt1\n"), "prompt1\n"); write(sd2, buf, strlen(buf)); } return 0; } int runampl(int sd2) { int fdr, fdw, i, n, done; pid_t apid; char buf[50000], buf2[50000]; /* SLEAZE! */ if ((apid = start(amplcmd, &fdw, &fdr)) == 0) { fprintf(logfp, "srv: start %s failed\n", amplcmd[0]); perror(""); exit(1); } fprintf(logfp, "started %s\n", amplcmd[0]); /* absorb initial output from ampl */ for (i = n = 0; read(fdr, &buf[i], 1) > 0 && isdigit(buf[i]); i++) n = 10 * n + buf[i] - '0'; read(fdr, buf, n); buf[n] = 0; dfprintf(logfp, "srv read initial ampl %d [%s]\n", n, buf); for (done = 0; done == 0; ) { dfprintf(logfp, "top of srv read loop\n"); /* read 1 cmd from client */ n = 0; for (i = 0; read(sd2, &buf[i], 1) > 0 && isdigit(buf[i]); i++) n = 10 * n + buf[i] - '0'; read(sd2, buf, n); buf[n] = 0; dfprintf(logfp, "srv read %d [%s] from cli\n", n, buf); sprintf(buf2, "%d %s", n, buf); write(fdw, buf2, strlen(buf2)); /* read replies from ampl until prompt: */ while (done == 0) { n = 0; for (i = 0; read(fdr, &buf[i], 1) > 0 && isdigit(buf[i]); i++) n = 10 * n + buf[i] - '0'; if (n <= 0) { fprintf(logfp, "ampl says %d\n", n); done = 1; break; } if (done) break; read(fdr, buf, n); buf[n] = 0; dfprintf(logfp, "srv read [%s] from ampl\n", buf); sprintf(buf2, "%d %s", n, buf); write(sd2, buf2, strlen(buf2)); if (strncmp(buf, "prompt", 6) == 0) break; if (strncmp(buf, "exit\n", 5) == 0) { done = 1; break; } } } /* kill apid? */ return 0; } int start(char **prog, int *fdw, int *fdr) { int fd1[2], fd2[2]; pid_t pid; if (pipe(fd1) < 0 || pipe(fd2) < 0) fatal("pipe error"); if ((pid = fork()) < 0) fatal("forking error"); if (pid == 0) { /* child */ close(fd1[1]); close(fd2[0]); if (fd1[0] != STDIN_FILENO) { if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) fatal("dup2 error to stdin"); close(fd1[0]); } if (fd2[1] != STDOUT_FILENO) { if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) fatal("dup2 error to stdout"); close(fd2[1]); } if (execvp(prog[0], prog) < 0) fatal("exec error"); } else { /* parent */ close(fd1[0]); close(fd2[1]); *fdw = fd1[1]; *fdr = fd2[0]; } return pid; } void fatal(char *msg) { fprintf(logfp, "srv: fatal: %s\n", msg); perror(""); exit(1); }