home *** CD-ROM | disk | FTP | other *** search
- /*
- This software is copyrighted by the University of Pennsylvania.
- Read COPYRIGHT for details.
- */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <time.h>
- #include <sys/resource.h>
- #include <signal.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <string.h>
-
- #include "network.h"
- #include "pdb.h"
- #include "node.h"
- #include "gophernodes.h"
-
- extern int addednewnodes;
- extern int tables_changed;
- extern short todaysdate;
- extern pid_t savedatastruct_pid;
- extern struct s1 *getnode_bygopherinfo(char **fields);
- extern struct s1 *init_gopher_node (char **fields, long nid, short lastu,
- int chkexists);
- extern void nio_send_file(int s, char *fn, long stpt, long req, int isnlist);
- extern void send_empty_document (int s);
- extern void send_empty_menu (int s);
- extern char *nodeinfostr(long nid, struct s1 *node, int flgfmt);
-
-
- extern CONN conntab[];
- #define conn_established(cn) (conntab[cn].c_socket != -1)
-
- extern void remove_helper(WAITFORHELPER *ptr)
- {
- int i, found;
-
- if (ptr == NULL)
- return;
-
- kill (ptr->pid, SIGTERM); /* just in case child is out there */
- do_free (ptr->file);
- do_free (ptr->cachefile);
- /* DONT free the ptr->node, it's part of the datastruct */
-
- for (i=0, found = 0; !found && i < FD_SETSIZE; ) {
- if (conntab[i].c_hptr == ptr)
- found = 1;
- else
- i++;
- }
- free (ptr);
- if (found)
- conntab[i].c_hptr = NULL;
- return;
- }
-
- int next_id;
-
- /* increments next id in memory + on disk */
- /* assumes that get_nextid() has been called already */
- static void
- inc_nextid(void)
- {
- char line[20];
- int dfd;
-
- if ((dfd = open(NEXTID_FILE, O_WRONLY | O_TRUNC | O_CREAT)) <= 0)
- {
- printf("error incrementing next id\n");
- return;
- }
- next_id++;
- sprintf(line, "%d\n", next_id);
- write(dfd, line, strlen(line));
- close(dfd);
- return;
- }
-
- /* reads the next id from disk */
- extern void
- get_nextid(void)
- {
- char line[20];
- int red;
- int dfd;
-
- if ((dfd = open(NEXTID_FILE, O_RDONLY)) <= 0){
- printf("error getting next id\n");
- return;
- }
- red = read(dfd, line, 20);
- if (red <= 0){
- printf("error reading next id\n");
- return;
- }
- line[red] = '\0';
- next_id = atoi(line);
- close(dfd);
- return;
- }
-
- static void conv_textfile(FILE *ifile, char *filnam)
- {
- FILE *ofile;
- char line[NLINE_MAXLEN];
- char *cp;
-
- ofile = fopen(filnam, "w");
- if (ofile == NULL) {
- fprintf (stderr, "Unable to open temp nlist file\n");
- perror(filnam);
- return;
- }
- while (fgets (line,NLINE_MAXLEN-1,ifile) != NULL) {
- cp = rindex (line, '\r');
- if (cp)
- if (*(cp+1) == '\n') {
- *cp = '\n';
- *(cp+1) = 0;
- }
- /* gopher protocol: text file ends with a . on a line by itself */
- if (strcmp(line, ".\n") == 0)
- break;
- else
- fprintf (ofile, "%s", line);
- }
- fclose (ofile);
- }
-
-
- static void child_punt (char gophertype, long nodeid, int sock, int flgsfmt)
- {
- char *cp;
-
- if (gophertype == GOPHTYP_TEXT || gophertype == GOPHTYP_GIF ||
- gophertype == GOPHTYP_IMAGE) {
- send_empty_document(sock);
- }
- else if (gophertype == GOPHTYP_MENU) {
- /* send this-
- 2:
- 0:nodeinfo of node we were working on
- 1:nodeinfo of reserved node that says "menu not available"
- */
- cp = (char *) malloc (2*BUFSIZ);
- sprintf (cp, "2:\n0:%s\n", nodeinfostr(nodeid, NULL, flgsfmt));
- strcat (cp, "1:");
- strcat (cp, nodeinfostr(MENU_NOT_AVAILABLE, NULL, flgsfmt));
- strcat (cp, "\n.\r\n");
- sendbuf(cp, strlen(cp), sock);
- /* sendbuf will free cp */
- }
- else {
- send_empty_menu (sock);
- }
- }
-
- static int create_cached_nlist (FILE *ifile, char *tempname)
- {
- FILE *tempfile;
- char line[BUFSIZ];
- char *gophfields[NUMFIELDS_GOPHER];
- int numf;
- struct s1 *node;
- int numlines;
-
- tempfile = fopen (tempname, "w");
- if (tempfile == NULL) {
- fprintf (stderr, "Unable to write temp output nlist file\n");
- perror (tempname);
- return 0;
- }
-
- /* ifile is an already open FILE */
- for (rewind (ifile), numlines = 0;
- fgets(line, sizeof(line)-1, ifile) != NULL; ) {
- if (*line != GOPHTYP_DUPSRV) {
- parsefields (line, gophfields, &numf, GOPHER_DLM, NUMFIELDS_GOPHER);
- if (numf >= NUMFIELDS_GOPHER) {
- node = getnode_bygopherinfo(gophfields);
- if (node == NULL) { /* create a new node in tables */
- get_nextid();
- node = init_gopher_node (gophfields, next_id, todaysdate, 0);
- inc_nextid();
- addednewnodes++;
- tables_changed++;
- }
-
- /* gopher info is already known, therefore just use the existing nodeid */
-
- fprintf (tempfile, "%ld\n", node->nodeid);
- numlines++;
- } /* enough gopher fields */
- } /* it wasn't a dupl server line */
- } /* foreach line of ifile */
- fclose (tempfile);
- return 1;
- }
-
-
-
-
-
- static int find_helper_conn (pid_t pid)
- {
- int found;
- int con;
-
- for (found = 0, con = 0; con < FD_SETSIZE && !found;) {
- if (conn_established(con) && (conntab[con].c_hptr) &&
- (conntab[con].c_hptr)->pid == pid) {
- found = 1;
- }
- else
- con++;
- }
- if (!found)
- return -1;
- else
- return con;
- }
-
-
- extern void catch_child (void)
- {
- pid_t pid;
- union wait status;
- struct rusage rusage;
- int c, found;
- FILE *childfile;
- WAITFORHELPER *hptr;
- char *filename2;
- sigset_t currmask;
-
- pid = wait3 (&status, WNOHANG, &rusage);
-
- if (pid == 0) {
- fprintf (stderr, "Funny, wait3 returned pid 0!\n");
- return; /* don't know if there's a connect out there waiting */
- }
- else if (pid < 0) {
- fprintf (stderr, "wait3 returned %d\n", pid);
- perror ("wait3");
- return; /* don't know if there's a connect out there waiting */
- }
-
- /* (pid > 0) */
-
- fprintf (stderr, "\nT=%d. Caught pid %d, exitstat = %d. ",
- time(0), pid, WEXITSTATUS(status));
-
- if ((c=find_helper_conn (pid)) < 0) {
- if (pid != savedatastruct_pid)
- fprintf (stderr, "Unknown what connection %d went with\n", pid);
- else {
- savedatastruct_pid = 0;
- fprintf(stderr, "save_datastruct child.\n");
- }
- return;
- }
- else
- fprintf (stderr, "Goes with conn #%d, sock %d\n", c, conntab[c].c_socket);
-
-
- hptr = conntab[c].c_hptr;
- /* Assumption: c_hptr->node still points to a valid node in a1[] */
-
- /* if child exited with non-zero status, must be an error */
- if (WEXITSTATUS(status) != 0) {
- child_punt((hptr->node)->gophertype, (hptr->node)->nodeid,
- conntab[c].c_socket, conntab[c].c_output_fmt);
- unlink (hptr->file);
- return;
- }
-
- childfile = fopen (hptr->file,"r");
- if (childfile == NULL) { /* File wasn't there ??? */
- fprintf (stderr, "Could not open child's output file\n");
- perror (hptr->file);
- child_punt ((hptr->node)->gophertype, (hptr->node)->nodeid,
- conntab[c].c_socket, conntab[c].c_output_fmt);
- return;
- }
- else {
- filename2 = tempnam(CACHEDIR, "convert");
- /* has to be the same dir as the cache because rename() needs that */
-
- switch ((hptr->node)->gophertype) {
- case GOPHTYP_IMAGE:
- case GOPHTYP_GIF:
- /* No conversion is needed for GIF files */
- fclose (childfile);
- rename (hptr->file, hptr->cachefile);
- nio_send_file(conntab[c].c_socket, hptr->cachefile,
- hptr->startpoint, hptr->requested, 0);
- remove_helper(hptr);
- do_free(filename2);
- break;
-
- case GOPHTYP_TEXT:
- conv_textfile (childfile, filename2);
- rename (filename2, hptr->cachefile);
- nio_send_file(conntab[c].c_socket, hptr->cachefile,
- hptr->startpoint, hptr->requested, 0);
- fclose (childfile); /* conv_... did NOT close file */
- unlink (hptr->file); /* remove child's file */
- remove_helper(hptr);
- do_free (filename2);
- break;
-
- case GOPHTYP_MENU:
- case GOPHTYP_SEARCH:
- if (!create_cached_nlist (childfile, filename2)) {
- child_punt((hptr->node)->gophertype,
- (hptr->node)->nodeid,
- conntab[c].c_socket, conntab[c].c_output_fmt);
- }
- else {
- rename (filename2, hptr->cachefile);
- send_cached_nlist (hptr->node, conntab[c].c_socket, hptr->cachefile,
- conntab[c].c_output_fmt);
- }
- fclose (childfile);
- unlink (hptr->file); /* remove child's file from the filesystem */
- remove_helper(hptr); /* remove the buf associated with child */
- do_free(filename2);
- break;
-
- default:
- fprintf (stderr, "catch_child() doesn't handle type '%c'.",
- (hptr->node)->gophertype);
- child_punt ((hptr->node)->gophertype, (hptr->node)->nodeid,
- conntab[c].c_socket, conntab[c].c_output_fmt);
- fclose (childfile); /* close file */
- unlink (hptr->file); /* remove child's file */
- remove_helper(hptr);
- do_free (filename2);
- break;
- }
- } /* childfile was okay */
- }
-