# /* request.c */ /* EMACS_MODES: c !fill */ /* This file contains the routines necessary to handle user requests. * The routines included are: * do_req find all pending request files * process_req process a request file * req_err handle errors in request files * gg_e_done ggp echo completion routine * ic_e_done icmp echo completion routine * ic_t_done icmp timestamp completion routine * str_save save a string in a calloc'ed location */ #include #include #include #include "params.h" #include "request.h" #include "extern.h" #include "icmp_codes.h" #include "ip.h" #include "icmp.h" do_req (dirfile) /* Process all pending user requests. Scan the request file directory, * looking for all files whose names begin with 'R' - these are request * files. If you find one, call a routine to process it. * * Arguments: */ reg FILE *dirfile; /* directory file pointer */ { struct dir dirbuf[32]; /* buffer for one directory block */ /* (32 is a pdp11-dependent */ /* optimization: entries/disk blk) */ reg struct dir *ptr; /* ptr. to current dir. entry */ reg int noent; /* no. of directory entries */ fseek (dirfile, 0L, 0L); while ((noent = fread (&dirbuf[0], sizeof (struct dir), 32, dirfile)) > 0) for (ptr = &dirbuf[0]; ptr < &dirbuf[noent]; ptr++) if (ptr->d_ino != 0 && ptr->d_name[0] == RQCHAR) process_req (ptr->d_name); } process_req (name) /* Process the user request contained in the specified file. The format * of a request file is: * - One line containing the function requested. The only functions * presently available are: * "ggp echo" * "icmp echo" * "timestamp" * - One line containing the foreign host name (or number) * Responses are returned by appending lines containing them to the end * of the request file. The standard response format is: * - One line containing termination code, in the format: * "Termination code = %d" * where the valid termination codes are the system standard error * codes (if the code is positive) or those listed in "icmp_codes.h" * (if the code is negative). * - Zero or more lines of character string response. * It is assumed that there are two links in the icmp daemon's directory * to each request file, named 'Rxxxx' and 'rxxxx'. The daemon scans for * files named 'Rxxxx'; when it finds one, it removes that link and uses * the file named 'rxxxx' as the request file. Typically the requestor * waits for the size of the request file to change to determine when * the processing of the request is complete. * * Arguments: */ char *name; /* request file name */ { reg FILE *rqfile; /* request file pointer */ char func[NAMESIZE]; /* requested function */ char host[NAMESIZE]; /* foreign host */ int stat; /* request status */ struct in_name faddr; /* foreign host address */ reg char *sname; /* saved request file name */ char *shost; /* saved host name */ if ((sname = str_save (name)) == NULL) { logdate (); printf ("can't allocate string space; aborting!\n"); abort (); } sname[0] = tolower(sname[0]); unlink (name); if ((rqfile = fopen (sname, "r")) == NULL) { if (log & LOG_ERR) { stat = errno; logdate (); printf ("error opening request file %s, %d\n", name, stat); } cfree (sname); return; } if ((fgets (func, NAMESIZE, rqfile) == NULL) || (fgets (host, NAMESIZE, rqfile) == NULL)) { if (log & LOG_ERR) { stat = errno; logdate (); printf ("request file read error, stat = %d\n", stat); } cfree (sname); fclose (rqfile); return; } fclose (rqfile); func[strlen (func) - 1] = '\0'; /* eliminate trailing newline */ host[strlen (host) - 1] = '\0'; /* eliminate trailing newline */ if (!resolve_name (host, &faddr)) { if (log & LOG_ERR) { logdate (); printf ("unknown host name %s specified\n", host); } req_err (sname, TBADHOST); cfree (sname); return; } if ((shost = str_save (host)) == NULL) { logdate (); printf ("can't allocate string space; aborting!\n"); abort (); } if (log & LOG_LOC) { logdate (); printf ("doing a %s to %s, trans = %d\n", func, host, ident); } if (strcmp (func, "ggp echo") == 0) { ggp_send_echo (&faddr, RETRIES, TIMEOUT, gg_e_done, shost, sname); } else if (strcmp (func, "icmp echo") == 0) { icmp_send_echo (&faddr, RETRIES, TIMEOUT, ic_e_done, shost, sname); } else if (strcmp (func, "timestamp") == 0) { icmp_timestamp (&faddr, RETRIES, TIMEOUT, ic_t_done, shost, sname); } else { if (log & LOG_ERR) { logdate (); printf ("unknown function %s\n", func); } req_err (sname, TBADFUNC); cfree (sname); cfree (shost); return; } } req_err (name, tcode) /* This routine is called to return an error response to a user request. * If the termination code is positive, it represents a system standard * error code; so the routine appends a line containing it to the request * file. Otherwise, the code is an icmp-specific error code, in which case * it appends two lines, containing the termination code and an * error string, to the specified request file. * * Arguments: */ reg char *name; /* request file name */ reg int tcode; /* termination code */ { reg FILE *rqfile; /* request file pointer */ int rfd; /* fd for req file */ if ((rfd = open (name, 2)) < 0 || (rqfile = fcons (rfd, "a")) == NULL) { if (log & LOG_ERR) { logdate (); printf("error reopening request file %s, %d\n", name, errno); } return; } fprintf (rqfile, "Termination code = %d\n", tcode); if (tcode < 0) fprintf (rqfile, "%s\n", tstrings[-tcode]); fclose (rqfile); return; } gg_e_done (ppkt, host, name, stat) /* This routine is called either when a ggp echo request times out or * when a reply to it is successfully received. If the request * was successful, ppkt contains a pointer to the packet containing * the response, and stat contains the termination code TSUCCESS. * Otherwise, stat contains an error code and ppkt is null. The * name parameter contains the name of the request file for this * request, and host is the host name (from the request file); both * were saved in alloc'ed space (which now needs to be freed) by * the request originator. * The routine is responsible for freeing the response packet and * the host and request filename strings. * This routine returns the appropriate response to the requester. * * Arguments: */ caddr_t ppkt; /* ptr. to rcvd. packet */ char *host; /* host name */ reg char *name; /* request file name */ reg int stat; /* request status */ { reg FILE *rqfile; /* request file pointer */ int rfd; /* fd for req file */ if (stat != TSUCCESS) req_err (name, stat); else { if ((rfd = open (name, 2)) < 0 || (rqfile = fcons (rfd, "a")) == NULL) { if (log & LOG_ERR) { logdate (); printf ("can't open request file %s, %d\n", name, errno); } } else { fprintf (rqfile, "Termination code = %d\n\ %s responding\n", stat, host); fclose (rqfile); } in_free (ppkt); } cfree (host); cfree (name); } ic_e_done (ppkt, host, name, stat) /* This routine is called either when a icmp echo request times out or * when a reply to it is successfully received. If the request * was successful, ppkt contains a pointer to the packet containing * the response, and stat contains the termination code TSUCCESS. * Otherwise, stat contains an error code and ppkt is null. The * name parameter contains the name of the request file for this * request, and host is the host name (from the request file); both * were saved in calloc'ed space (which now needs to be cfreed) by * the request originator. * The routine is responsible for freeing the response packet and * the host and request filename strings. * This routine returns the appropriate response to the requester. * * Arguments: */ caddr_t ppkt; /* ptr. to rcvd. packet */ char *host; /* host name */ reg char *name; /* request file name */ reg int stat; /* request status */ { reg FILE *rqfile; /* request file pointer */ int rfd; /* fd for req file */ if (stat != TSUCCESS) req_err (name, stat); else { if ((rfd = open (name, 2)) < 0 || (rqfile = fcons (rfd, "a")) == NULL) { if (log & LOG_ERR) { logdate (); printf ("can't open request file %s, %d\n", name, errno); } } else { fprintf (rqfile, "Termination code = %d\n\ %s responding\n", stat, host); fclose (rqfile); } in_free (ppkt); } cfree (host); cfree (name); } ic_t_done (ppkt, host, name, stat) /* This routine is called either when a icmp timestamp request times out or * when a reply to it is successfully received. If the request * was successful, ppkt contains a pointer to the packet containing * the response, and stat contains the termination code TSUCCESS. * Otherwise, stat contains an error code and ppkt is null. The * name parameter contains the name of the request file for this * request, and host is the host name (from the request file); both * were saved in calloc'ed space (which now needs to be cfreed) by * the request originator. * The routine is responsible for freeing the response packet and * the host and request filename strings. * This routine returns the appropriate response to the requester. * * Arguments: */ caddr_t ppkt; /* ptr. to rcvd. packet */ char *host; /* host name */ char *name; /* request file name */ reg int stat; /* request status */ { reg FILE *rqfile; /* request file pointer */ reg struct icmp *picmp; /* ptr. to icmp data */ int iclen; /* icmp data length */ int tvec[3]; /* current time */ long now; /* finish time */ int rfd; /* fd for req file */ if (stat != TSUCCESS) req_err (name, stat); else { picmp = in_find_data (ppkt, &iclen); if ((rfd = open (name, 2)) < 0 || (rqfile = fcons (rfd, "a")) == NULL) { if (log & LOG_ERR) { logdate (); printf ("can't open request file %s, %d\n", name, errno); } } else { qtime (tvec); now = tvec_to_ut(tvec); fprintf (rqfile, "Termination code = %d\n", stat); fprintf (rqfile, "Timestamp from %s:\n", host); fprintf (rqfile, " Orig: %D", picmp->ic_data.ic_time.tm_orig); fprintf (rqfile, " Rcvd: %D", picmp->ic_data.ic_time.tm_recv); fprintf (rqfile, " Xmtd: %D", picmp->ic_data.ic_time.tm_trans); fprintf (rqfile, " Done: %D\n", now); fclose (rqfile); } in_free (ppkt); } cfree (host); cfree (name); } char *str_save (str) /* Save the string pointed to by str in a safe place (generated by calloc) * for later use. Return a pointer to the saved string, or NULL if the * calloc fails. * * Arguments: */ reg char *str; { reg char *saved_str; /* saved string */ if ((saved_str = calloc (1, strlen (str) + 1)) == -1) return (NULL); strcpy (saved_str, str); return (saved_str); }