/* TCP/IP based server for HyperText TCPServer.c ** --------------------------------- ** ** History: ** 2 Oct 90 Written TBL. Include filenames for VM from RTB. */ /* Module parameters: ** ----------------- ** ** These may be undefined and redefined by syspec.h */ #define LISTEN_BACKLOG 2 /* Number of pending connect requests (TCP)*/ #define MAX_CHANNELS 20 /* Number of channels we will keep open */ #define BUFFER_SIZE 4096 /* Arbitrary size for efficiency */ #define WILDCARD '*' /* Wildcard used in addressing */ #define NETCLOSE close /* Routine to close a TCP-IP socket */ #define NETREAD read /* Routine to read from a TCP-IP socket */ #define NETWRITE write /* Routine to write to a TCP-IP socket */ #define FIRST_TCP_PORT 5000 /* When using dynamic allocation */ #define LAST_TCP_PORT 5999 #ifdef NeXT #define SELECT /* Handle >1 channel if we can. */ #include /* NeXT has all this packaged up */ #define ntohs(x) (x) #define htons(x) (x) #include #else #include /* VM doesn't have a built-in predefined token, so we cheat: */ #ifdef __STDIO__ #define VM #else #include /* For bzero etc - not NeXT or VM */ #endif #define SELECT /* Handle >1 channel if we can. */ #endif #ifndef VM #include #include #include #include /* Must be after netinet/in.h */ #include #include /* independent */ #include /* independent */ #define TOASCII(c) (c) #define FROMASCII(c) (c) #else /* VM */ #include #include #include #include #include #include #include /* independent */ extern char asciitoebcdic[], ebcdictoascii[]; #define TOASCII(c) (c=='\n' ? 10 : ebcdictoascii[c]) #define FROMASCII(c) (c== 10 ? '\n' : asciitoebcdic[c]) #include #define index(a,b) my_index(a,b) /* Why index() doesn't work I don't know */ #endif #include "utilities.h" /* Coding convention macros */ /* Default macros for manipulating masks for select() */ #ifndef FD_SET typedef unsigned int fd_set; #define FD_SET(fd,pmask) (*(pmask)) |= (1=s;p--) { if(SPACE(*p)) *p=0; /* Zap trailing blanks */ else break; } while(SPACE(*s))s++; /* Strip leading blanks */ return s; } /* Send a string down a socket ** --------------------------- ** ** The trailing zero is not sent. ** There is a maximum string length. */ PRIVATE int write_ascii(int soc, char * s) { char * p; char ascii[255]; char *q = ascii; for (p=s; *p; p++) { *q++ = TOASCII(*p); } return write(soc, ascii, p-s); } /* Handle one message ** ------------------ ** ** On entry, ** soc A file descriptor for input and output. ** On exit, ** returns >0 Channel is still open. ** 0 End of file was found, please close file ** Keyword Index\n"); if (*filename) { write_ascii(soc, "This index covers groups: `"); write_ascii(soc, filename); } else { write_ascii(soc, "This is the general CERN public document index"); } write_ascii(soc, ".

Use a keyword search to get documents, help files, etc.

\n"); return 0; } strcpy(system_command,"EXEC NICFIND1 "); strcat(system_command, keywords); if (*filename) { strcat(system_command, " ( "); strcat(system_command, filename); } } else { strcpy(system_command,"EXEC NICFOUN1 "); strcat(system_command, filename); } lines = system(system_command); if (TRACE) printf("Command `%s' returned %i lines.\n", system_command, lines); if (lines")==0) break; */ for(p=buffer; *p; p++) *p = TOASCII(*p); write(soc, buffer, p-buffer); } return 0; } /* if FIND */ #else fd = open(arg, O_RDONLY, 0 ); /* un*x open @@ */ if (fdSmall network access test v1.01\n"); write_ascii(soc, "\n\nThe (unrecognised) command used was `"); write_ascii(soc, command); write_ascii(soc, "'.\n\n"); if (TRACE) printf("Return test string written back'\n"); return 0; /* End of file - please close socket */ } /* for */ } /* handle */ /*_____________________________________________________________________________________ */ /* Encode INET status (as in sys/errno.h) inet_status() ** ------------------ ** ** On entry, ** where gives a description of what caused the error ** global errno gives the error number in the unix way. ** ** On return, ** returns a negative status in the unix way. */ #ifdef vms extern int uerrno; /* Deposit of error info (as perr errno.h) */ extern int vmserrno; /* Deposit of VMS error info */ extern volatile noshare int errno; /* noshare to avoid PSECT conflict */ #else #ifndef errno extern int errno; #endif #endif PRIVATE int inet_status(where) char *where; { CTRACE(tfp, "TCP: Error %d in `errno' after call to %s() failed.\n", errno, where); #ifdef vms CTRACE(tfp, " Unix error number (uerrno) = %ld dec\n", uerrno); CTRACE(tfp, " VMS error (vmserrno) = %lx hex\n", vmserrno); #endif return -errno; } /* Parse a cardinal value parse_cardinal() ** ---------------------- ** ** On entry, ** *pp points to first character to be interpreted, terminated by ** non 0:9 character. ** *pstatus points to status already valid ** maxvalue gives the largest allowable value. ** ** On exit, ** *pp points to first unread character ** *pstatus points to status updated iff bad */ PRIVATE unsigned int parse_cardinal(pstatus, pp, max_value) int *pstatus; char **pp; unsigned int max_value; { int n; if ( (**pp'9')) { /* Null string is error */ *pstatus = -3; /* No number where one expeceted */ return 0; } n=0; while ((**pp>='0') && (**ppmax_value) { *pstatus = -4; /* Cardinal outside range */ return 0; } return n; } /* Bind to a TCP port ** ------------------ ** ** On entry, ** tsap is a string explaining where to take data from. ** "" means data is taken from stdin. ** "*:1729" means "listen to anyone on port 1729" ** ** On exit, ** returns Negative value if error. */ int do_bind(const char * tsap) { FD_ZERO(&open_sockets); /* Clear our record of open sockets */ num_sockets = 0; /* Deal with PASSIVE socket: ** ** A passive TSAP is one which has been created by the inet daemon. ** It is indicated by a void TSAP name. In this case, the inet ** daemon has started this process and given it, as stdin, the connection ** which it is to use. */ if (*tsap == 0) { /* void tsap => passive */ dynamic_allocation = FALSE; /* not dynamically allocated */ role = passive; /* Passive: started by daemon */ #ifdef vms { unsigned short channel; /* VMS I/O channel */ struct string_descriptor { /* This is NOT a proper descriptor*/ int size; /* but it will work. */ char *ptr; /* Should be word,byte,byte,long */ } sys_input = {10, "SYS$INPUT:"}; int status; /* Returned status of assign */ extern int sys$assign(); status = sys$assign(&sys_input, &channel, 0, 0); com_soc = channel; /* The channel is stdin */ CTRACE(tfp, "IP: Opened PASSIVE socket %d\n", channel); return -BAD(status); } #else com_soc = 0; /* The channel is stdin */ CTRACE(tfp, "IP: PASSIVE socket 0 assumed from inet daemon\n"); return 0; /* Good */ #endif /* Parse the name (if not PASSIVE) */ } else { /* Non-void TSAP */ char *p; /* pointer to string */ char *q; struct hostent *phost; /* Pointer to host - See netdb.h */ char buffer[256]; /* One we can play with */ register struct sockaddr_in* sin = &soc_address; strcpy(buffer, tsap); p = buffer; /* Set up defaults: */ sin->sin_family = AF_INET; /* Family = internet, host order */ sin->sin_port = 0; /* Default: new port, */ dynamic_allocation = TRUE; /* dynamically allocated */ role = passive; /* by default */ /* Check for special characters: */ if (*p == WILDCARD) { /* Any node */ role = master; p++; } /* Strip off trailing port number if any: */ for(q=p; *q; q++) if (*q==':') { int status; *q++ = 0; /* Terminate node string */ sin->sin_port = htons((unsigned short)parse_cardinal( &status, &q, (unsigned int)65535)); if (statussin_addr.s_addr = INADDR_ANY; /* Default: any address */ } else if (*p>='0' && *psin_addr.s_addr = inet_addr(p); /* See arpa/inet.h */ } else { /* Alphanumeric node name: */ phost=gethostbyname(p); /* See netdb.h */ if (!phost) { CTRACE(tfp, "IP: Can't find internet node name `%s'.\n",p); return inet_status("gethostbyname"); /* Fail? */ } memcpy(&sin->sin_addr, phost->h_addr, phost->h_length); } CTRACE(tfp, "TCP: Parsed address as port %4x, inet %d.%d.%d.%d\n", (unsigned int)ntohs(sin->sin_port), (int)*((unsigned char *)(&sin->sin_addr)+0), (int)*((unsigned char *)(&sin->sin_addr)+1), (int)*((unsigned char *)(&sin->sin_addr)+2), (int)*((unsigned char *)(&sin->sin_addr)+3)); } /* scope of p */ /* Master socket for server: */ if (role == master) { /* Create internet socket */ master_soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (master_soc num_sockets) num_sockets=master_soc+1; return master_soc; } /* if master */ return -1; /* unimplemented role */ } /* do_bind */ /* Handle incomming messages do_action() ** ------------------------- ** ** On entry: ** ** timeout -1 for infinite, 0 for poll, else in units of 10ms ** ** On exit, ** returns The status of the operation, =0) { max_wait.tv_sec = timeout/100; max_wait.tv_usec = (timeout%100)*10000; } for (com_soc=-1; com_soc= 0 ? &max_wait : 0); if (nfound num_sockets) num_sockets=tcp_status+1; nfound--; } /* end if new connection */ /* If a message has arrived on one of the channels, take that channel: */ if(nfound) { int i; for(i=0;;i++) if(FD_ISSET(i, &read_chans)) { if (TRACE) printf("Got new socket %i\n", i); com_soc = i; /* Got one! */ break; } break; /* Found input socket com_soc */ } /* if message waiting */ } /* loop on event */ #else /* SELECT not supported */ if (com_socmdp.soc_tcp.soc_address, &rsoc->mdp.soc_tcp.soc_addrlen); if (tcp_status