📄 lpcomm.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)lpcomm.c 4.2 ULTRIX 11/15/90";#endif/* * lpcomm.c -- Communication routines * * Author: Mike Augeri * Date: 05-APR-1990 * * History: * 12-APR-1990 mva Change "ifdef ULTRIX" to "ifndef VMS" so that sources * will compile on non-ULTRIX UNIX systems. Also, put * my print statements behind an "ifdef VMS" and * "if (debug > n)" statement. * 15-MAY-1990 mva Fixed the problem with hibernate returning while ast * completed was still not true. The hibernate was * returning immediately due to an outstanding wake from * an earlier exit from the ast handler. Also, change * debug options. * 15-MAY-1990 mva Fixed the problem with uninitialized value of retval in * LP_C_probe routine. Also changed LP_C_gets and * LP_C_getc routines to use global stdinFD as index rather * than using fileno(stdin) as index. * 16-MAY-1990 mva Modified LP_C_getc routine for use with the lprc module. * The lprc module is somewhat unique in that it has two * open channels, one of them the network as usual, the * other is stdin for reading input form keyboard. Using * sys$qio to read stdin is what made the change to the * routine necessary. * 11-JUL-1990 mva Remove extern from stdinFD declaration. * 11-JUL-1990 mva Change to paprelay.h. * 13-JUL-1990 mva Move issue_read and ast_handler to vms_utilities. * 13-JUL-1990 mva Add include for ultrix_utilities.h * 16-JUL-1990 mva Initialize stdinFD to -1 * 23-JUL-1990 jwfm Replace second two instance of strncpy w/ memcpy * so we can pass binary data. Change the debug code * in LP_C_send so it uses fwrite instead of fprintf. * 23-AUG-1990 jwfm Add file discripter mapping. Map VMS file discriptors * to a number from 0 to 31 so we don't 64k buffers. * 05-NOV-1990 mva Many changes including a rewrite of the LP_C_getc * routine for VMS and modification of the LP_C_probe * routine; some cleanup done, but much more can be done. *//* $Header: lpcomm.c,v 4.0 88/12/12 14:50:54 reid Exp $ $Source: /mnt/reid/skunkworks/src/RCS/lpcomm.c,v $This module contains communications subroutines used by the client programs.The client programs include the relay server, the lpd filters, and thevarious accounting listeners.The communication between server and client is via a packet protocoldescribed in the Relay Protocol document. That packet protocol is implementedon top of whatever network mechanism is available.This version of the comm software implements the packet protocol on top ofTCP/IP. Brian Reid DEC Western Research * */#ifndef VMS#include <sys/file.h>#include <sys/types.h> /* system data types */#include <sys/socket.h>#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/time.h>#include <signal.h> /* signal handler */#include <setjmp.h> /* unwind handler */#include "ultrix_utilities.h"#define SETJMP_LOADED#else VMS#include <iodef.h> /* i/o definitions */#include <ssdef.h> /* system service defintions */#include "vms_utilities.h"#endif VMS#include <stdio.h> /* standard i/o definitions */#include <string.h>#include "lps.h"#include "paprelay.h"/* definitions of external procedures and variables */int stdinFD = -1;static char *inputBuffers[AD]; /* p. 82 of K&R says these guaranteed =0 */static int firstUnused[AD]; /* pointer to first unused byte in buffer */static int lastByteIn[AD]; /* last byte in buffer memory *//* temporarily make probeCache non-static so can see in vms_utilities module */int probeCache[AD]; /* avoid redundant calls to select() */static int sendFlag=0; /* for sending urgent data */#ifdef VMSextern char *qioBuffers[AD]; /* used by ast qio read operation */extern int rcv_pending[AD];extern int ast_completed[AD];extern word fd_map[AD]; /* One entry for each "ULTRIX" fd, holds VMS fd so we can map it back for sys calls */extern char fd_used[AD]; /* Data structure to keep track of which slots in fd_map are used. USED if used, EMPTY other wise */#endif VMS/* * L P _ C _ r e c v * * Read and parse one message from a socket open for input. These messages * can come either from server or client. Because of the peculiar structure * of the messages, it is necessary to parse them in order to locate their * end (the end of a message is determined by a count field imbedded in the * middle of the record). * * This procedure and its subroutine incP embody all of the complexity of the * stream-to-record conversion, and are in theory the only things that will * have to change if (when) the semantics of the network channel changes. * * Inputs: int ServerFD, *Opcode, *ID, *Length; char *Data * Outputs: same * Return: >0 if a message was available, 0 if no message * available, and <0 if EOF * Action: If no messages are available from the server, * return immediately with a return value of False. * If there are messages, then the oldest message is * removed from the arrival queue and unpacked into * the four variables provided. * Side effects: Removes one message from the arrival message queue. * */ LP_C_recv (ServerFD, Opcode, ID, Length, Data)int ServerFD;char *Opcode;int *ID, *Length;char *Data; { int *jsub; /* pointer to buffer subscript */ char *jc; /* char pointer to buffer origin */ char *startField; /* flag beginning of each field */#ifdef VMS if (debug > 7) fprintf(stderr,"Entering LP_C_recv, ast_completed[%d] = %d\n", ServerFD,ast_completed[ServerFD]);#endif VMS/* test to see if there is a buffer allocated for this FD, and if there is not, then create an empty buffer. */ if (inputBuffers[ServerFD] == (char *) 0) { inputBuffers[ServerFD] = (char *) malloc (1+PACKET_BUFFER_SIZE); lastByteIn[ServerFD] = -1; firstUnused[ServerFD] = 0; probeCache[ServerFD] = FALSE; } jc = inputBuffers[ServerFD]; jsub = &firstUnused[ServerFD]; if (incrP(ServerFD,0)) {#ifdef VMS if (debug > 7) fprintf(stderr,"Exiting LP_C_recv via incrP preload check, ast_completed[%d] = %d\n", ServerFD,ast_completed[ServerFD]);#endif VMS goto endfile; /* preload the buffer */ } /* * sync on packet beginning; if this is necessary, there is a bug * somewhere, but in the interests of resilience we put this in here * anyhow. * * mva -- I believe the following fprintf is responsible for putting * "garbage" (e.g., nulls) into logFile or stderr. */ while (jc[*jsub] != RELAY_SOM) { fprintf(stderr,"%c",jc[*jsub]); if(incrP(ServerFD,1)) {#ifdef VMS if (debug > 7) fprintf(stderr,"Exiting LP_C_recv via incrP RELAY_SOM check, ast_completed[%d] = %d\n", ServerFD,ast_completed[ServerFD]);#endif VMS goto endfile; } } /* Get field 1 */ if(incrP(ServerFD,1)) goto endfile; while (jc[*jsub] == ' ') if(incrP(ServerFD,1)) goto endfile; startField = &jc[*jsub]; while (jc[*jsub] != ' ') if(incrP(ServerFD,1)) goto endfile; jc[*jsub] = (char) NULL; strncpy(Opcode,startField,OP_MAX_SIZE); /* Get field 2 */ if(incrP(ServerFD,1)) goto endfile; while (jc[*jsub] == ' ') if(incrP(ServerFD,1)) goto endfile; startField = &jc[*jsub]; while (jc[*jsub] != ' ') if(incrP(ServerFD,1)) goto endfile; jc[*jsub] = (char) NULL; *ID = atoi(startField); /* Get field 3 */ if(incrP(ServerFD,1)) goto endfile; while (jc[*jsub] == ' ') if(incrP(ServerFD,1)) goto endfile; startField = &jc[*jsub]; while (jc[*jsub] != ' ') if(incrP(ServerFD,1)) goto endfile; jc[*jsub] = (char) NULL; *Length = atoi(startField); /* Get field 4 */ if (*Length > 0) { if(incrP(ServerFD,1)) goto endfile; startField = &jc[*jsub]; /* because incrP guarantees that the resulting incremented pointer will point to valid data, we want to increment by one less than the actual buffer size here, to avoid issuing a (blocking) read for the data that is actually in the next frame. This makes the count off by one */ if(incrP(ServerFD,(*Length)-1)) goto endfile; memcpy(Data,startField, *Length); /* here we repair the count so that it is no longer off by one */ firstUnused[ServerFD]++; } Data[*Length] = (char) NULL;/* We have now finished processing this packet. Slide the data in the buffer so that the next call will have lots of buffer space. */ if (firstUnused[ServerFD] > DECNET_MAX_FRAME) { register char *ip,*jp; register int n,shiftAmount; /* debug code */ char c1,cn; int i1,in; /* end debug code */ /* first check to make sure that there actually is data in the buffer */ if (firstUnused[ServerFD] > lastByteIn[ServerFD]) { firstUnused[ServerFD] = 0; lastByteIn[ServerFD] = -1; } else { ip = &(inputBuffers[ServerFD][firstUnused[ServerFD]]); jp = inputBuffers[ServerFD]; /* debug code */ c1 = *ip; cn = inputBuffers[ServerFD][lastByteIn[ServerFD]]; i1 = firstUnused[ServerFD]; in = lastByteIn[ServerFD]; /* end debug code */ shiftAmount = lastByteIn[ServerFD] - firstUnused[ServerFD] + 1; for(n=0; n <= shiftAmount; n++) *jp++ = *ip++; lastByteIn[ServerFD] = lastByteIn[ServerFD] - firstUnused[ServerFD]; firstUnused[ServerFD] = 0; /* debug code */ if(debug > 7) { if ( (c1 != inputBuffers[ServerFD][0]) || (cn != inputBuffers[ServerFD][lastByteIn[ServerFD]]) ) { fprintf(stderr,"%s %s: bad buffer shift invariant: (%d-%d) '%c'-'%c' became (0-%d) '%c'-'%c'\n", progName, LPStime(), i1,in,c1,cn,lastByteIn[ServerFD], inputBuffers[ServerFD][0], inputBuffers[ServerFD][lastByteIn[ServerFD]]); } } /* end debug code */ } } if (debug > 6) fprintf(stderr,"%s %s: %d->rmsg(%s,%d,%d,%s)\n", progName, LPStime(), ServerFD,Opcode, *ID, *Length, Data);#ifdef VMS if (debug > 7) fprintf(stderr,"Exiting LP_C_recv via TRUE return, ast_completed[%d] = %d\n", ServerFD,ast_completed[ServerFD]);#endif VMS return(1);/* We branch here when the channel-handling subroutine detects an EOF */endfile: #ifdef VMS if (debug > 7) fprintf(stderr,"Exiting LP_C_recv via endfile, ast_completed[%d] = %d\n", ServerFD,ast_completed[ServerFD]);#endif VMS return(-1);}/* * i n c r P * * Increment the buffer pointer for the specified FD, and make sure that * there is data for it to point to. * * Inputs: int ServerFD, delta * Outputs: none * Action: Increments the input buffer pointer for the file * denoted by ServerFD by "delta". If the result of * that incrementation causes the buffer pointer to * point off the end of the message, then read more * characters until there is data under the new pointer. * Side Effects: Reads data from ServerFD if necessary. Does not * return until enough data is available. */static incrP(FD,delta)int FD,delta;{ char *buf; int spaceRemaining; int ReadStatus;#ifdef VMS char *tmp;#endif VMS#ifdef VMS if (debug > 8) fprintf(stderr,"Entering incrP, ast_completed[%d] = %d\n", FD,ast_completed[FD]);#endif VMS firstUnused[FD] += delta; probeCache[FD] = FALSE; while (firstUnused[FD] > lastByteIn[FD]) { buf = inputBuffers[FD]; spaceRemaining = PACKET_BUFFER_SIZE - lastByteIn[FD] + 1;#ifndef VMS ReadStatus = recv(FD, &buf[1+lastByteIn[FD]], spaceRemaining, 0); if (ReadStatus < 0) { sprintf(errbuf,"%s %s: recv(%d) failed %d", progName,LPStime(),FD,ReadStatus); perror(errbuf); return(TRUE); /* signal EOF */ } if (ReadStatus == 0) return(TRUE); lastByteIn[FD] += ReadStatus;#else VMS /* * The following bcopy is expedient, but may not be the best thing to * do as far as performance is concerned. At this time I don't have * any other ideas. I considered copying pointers instead of buffers, * but the code works on the assumption that messages are appended to * the input buffer. (Check to see how we know when the buffer has to * be flushed -- spaceRemaining?) */ if (!ast_completed[FD]) { if (debug > 8) fprintf(stderr,"Exiting incrP return TRUE, ast_completed[%d] = %d\n", FD,ast_completed[FD]); return(TRUE); } /* Else we have a message, so copy it to input buffer */ bcopy(qioBuffers[FD],&buf[1+lastByteIn[FD]],qio_transfer_size(FD)); lastByteIn[FD] += qio_transfer_size(FD); rcv_pending[FD] = FALSE; ast_completed[FD] = FALSE;#endif VMS }#ifdef VMS if (debug > 8)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -