home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-11-10 | 54.7 KB | 2,001 lines |
- Newsgroups: comp.sources.misc
- From: brendan@cygnus.com (Brendan Kehoe)
- Subject: v33i050: archie - A client to query the Archie FTP databases, v1.4.1, Part01/07
- Message-ID: <csm-v33i050=archie.145604@sparky.IMD.Sterling.COM>
- X-Md4-Signature: f72fa1a60a8684951e575c05203ad538
- Date: Thu, 5 Nov 1992 20:59:05 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: brendan@cygnus.com (Brendan Kehoe)
- Posting-number: Volume 33, Issue 50
- Archive-name: archie/part01
- Environment: UNIX, VMS, DOS
- Supersedes: archie: Volume 27, Issue 79-84
-
- [ Version 1.4.1 ]
-
- Enclosed you'll find a Prospero client for the archie service. It'll
- let you query the archie databases without actually using an
- interactive process on the remote server's machine (e.g., archie.ans.net),
- resulting in a MUCH better response time. It also helps lessen the
- load on the archie server itself.
-
- What's Archie? It's a system that will let you check a database containing
- thousands of entries for the files that're available at FTP sites around
- the world.
-
- This is a third child of Clifford Neuman's Prospero project. It's really
- the Archie client that's included in the prospero stuff, but I've taken out
- everything that's unnecessary for this client to work. (Aka, you don't
- have to build all of Prospero to get the Archie client.) Khun Yee Fung
- wrote an archie client in Perl, George Ferguson has written a client
- for use with XWindows, based in part upon this code. Also, Scott
- Stark wrote a NeXT-Step client for the NeXT.
-
- Also included in this release is a GNU Emacs Lisp front-end to the
- archie client. Note that it requires the Ange FTP package to work
- properly. You can retrieve it from archive.cis.ohio-state.edu in the
- directory /pub/gnu/emacs/elisp-archive/packages as ange-ftp.tar.Z.
-
- Using the Archie Prospero interface in its true form will probably be of
- interest---check out the file `Prospero' for an example of its interface.
- If you find it intriguing, you should probably get the full prospero kit
- from the University of Washington on cs.washington.edu in pub/prospero.tar.Z.
-
- Suffice to say, there are now a number of ways to query Archie without
- bogging a server down with your logins.
-
- Check out the man page (or archie.doc, if you're using VMS or DOS)
- for instructions on how to use this archie client. VMS users please
- note that you have to put quotes around args that are capital letters;
- for example, `$ ARCHIE "-L"' to list the available servers.
-
- Please check to make sure you don't have "archie" aliased or modified
- in some way to do a telnet or rlogin (which you may've done before
- this command-line ability came into being).
-
- If Archie consistently hangs (at different times of day with
- different queries), it's possible that your site has UDP traffic on
- ports > 1000 blocked, for security reasons. Contact your local
- system administrator.
-
- Write to archie-group@cc.mcgill.ca with questions about Archie itself.
- Write to info-prospero@isi.edu about the Prospero protocol.
- Write to brendan@cygnus.com with questions about this specific package.
- -----------
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: README README.ALEX README.dos msdos vms vms/in.h
- # vms_support.c
- # Wrapped by kent@sparky on Thu Nov 5 12:53:07 1992
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 1 (of 7)."'
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(2529 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X[ Version 1.4 ]
- X
- X Enclosed you'll find a Prospero client for the archie service. It'll
- Xlet you query the archie databases without actually using an
- Xinteractive process on the remote server's machine (e.g., archie.ans.net),
- Xresulting in a MUCH better response time. It also helps lessen the
- Xload on the archie server itself.
- X
- X What's Archie? It's a system that will let you check a database containing
- Xthousands of entries for the files that're available at FTP sites around
- Xthe world.
- X
- X This is a third child of Clifford Neuman's Prospero project. It's really
- Xthe Archie client that's included in the prospero stuff, but I've taken out
- Xeverything that's unnecessary for this client to work. (Aka, you don't
- Xhave to build all of Prospero to get the Archie client.) Khun Yee Fung
- Xwrote an archie client in Perl, George Ferguson has written a client
- Xfor use with XWindows, based in part upon this code. Also, Scott
- XStark wrote a NeXT-Step client for the NeXT.
- X
- X Also included in this release is a GNU Emacs Lisp front-end to the
- Xarchie client. Note that it requires the Ange FTP package to work
- Xproperly. You can retrieve it from archive.cis.ohio-state.edu in the
- Xdirectory /pub/gnu/emacs/elisp-archive/packages as ange-ftp.tar.Z.
- X
- X Using the Archie Prospero interface in its true form will probably be of
- Xinterest---check out the file `Prospero' for an example of its interface.
- XIf you find it intriguing, you should probably get the full prospero kit
- Xfrom the University of Washington on cs.washington.edu in pub/prospero.tar.Z.
- X
- X Suffice to say, there are now a number of ways to query Archie without
- Xbogging a server down with your logins.
- X
- X Check out the man page (or archie.doc, if you're using VMS or DOS)
- Xfor instructions on how to use this archie client. VMS users please
- Xnote that you have to put quotes around args that are capital letters;
- Xfor example, `$ ARCHIE "-L"' to list the available servers.
- X
- X Please check to make sure you don't have "archie" aliased or modified
- Xin some way to do a telnet or rlogin (which you may've done before
- Xthis command-line ability came into being).
- X
- X If Archie consistently hangs (at different times of day with
- Xdifferent queries), it's possible that your site has UDP traffic on
- Xports > 1000 blocked, for security reasons. Contact your local
- Xsystem administrator.
- X
- X
- X Write to archie-group@cc.mcgill.ca with questions about Archie itself.
- X Write to info-prospero@isi.edu about the Prospero protocol.
- X Write to brendan@cygnus.com with questions about this specific package.
- END_OF_FILE
- if test 2529 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'README.ALEX' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README.ALEX'\"
- else
- echo shar: Extracting \"'README.ALEX'\" \(780 characters\)
- sed "s/^X//" >'README.ALEX' <<'END_OF_FILE'
- XAlex is a filesystem that lets users access files in FTP sites around
- Xthe world just like they access local files. The name Alex comes from
- Xthe ancient Library of Alexandria. Alexandria gathered information from
- Xaround the world into one easy to access location. Alex does an analogous
- Xthing in a very modern way.
- X
- XSource to Alex is now available on alex.sp.cs.cmu.edu in the `src'
- Xsubdirectory.
- X
- Xusenix.wofs92.ps - paper on Alex as published in Usenix Workshop on File Systems
- X May of 1992.
- X
- Xintro.ps - same as above paper but with updates
- X
- X
- Xnsf.poster.ps - 6 slides used for a poster session
- X
- X
- XKeywords: Alexandria, Alex, technical papers, techreport
- XMaster copy: /alex/edu/cmu/cs/sp/alex/doc/README
- X
- X
- X Vincent Cate
- X vac@cs.cmu.edu
- X
- END_OF_FILE
- if test 780 -ne `wc -c <'README.ALEX'`; then
- echo shar: \"'README.ALEX'\" unpacked with wrong size!
- fi
- # end of 'README.ALEX'
- fi
- if test -f 'README.dos' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README.dos'\"
- else
- echo shar: Extracting \"'README.dos'\" \(10680 characters\)
- sed "s/^X//" >'README.dos' <<'END_OF_FILE'
- X11/22/91 Readme.dos -- Readme file for CUTCP DOS version of Archie.
- X
- X--
- XThis version requires the use of a `standard' NCSA or CUTCP compatible
- XCONFIG.TEL file. If you are running NCSA telnet or CUTCP/CUTE telnet,
- Xyou should be able to run this program without modification.
- X
- XAs with all CUTCP programs, you may set a DOS environment variable to
- Xpoint to the location of your config.tel file.
- X
- X set CONFIGTEL=C:\net\config.tel
- X
- XYou may also set the $CUTCPnn dos environment variables to include other
- X'local' information (such as client IP address on a Novell lan).
- X
- XThis version has been compiled with the US (archie.sura.net) Prospero/Archie
- Xserver as the default. This may not be appropriate for your location. Here's
- Xhow to change it.
- X
- X
- X 1. Run the archie program with the -L argument to list known
- X archie/prospero servers.
- X
- X 2. Select the server name that is closest to your site. For this example
- X we'll pick archie.funet.fi
- X
- X 3. Edit your config.tel file and add the following lines at the end
- X of the file.
- X
- X name=archie
- X host=archie.funet.fi # actually substitute your select
- X # server name here
- X
- X 4. If you happen to know the IP address of the server, you may also
- X add the appropriate
- X
- X hostip=<insert IP address here>
- X
- X 5. If you don't enter an IP address, archie will perform a DNS lookup
- X use the domain nameserver information that is in your config.tel
- X file.
- X
- X
- XAn additional command line option (-H) has been added (vs -h) to allow the
- Xuser to specify the config.tel file location on the command line.
- X
- X archie -H c:\net\config.tel emacs
- X
- XDuring a search, you may press the <ESCAPE> key to abort the query.
- X
- X
- X
- XIf you have problems, try running archie with the -D9 option (debug).
- X
- XAs usual, bugs/comments to:
- X
- X cutcp-bugs@omnigate.clarkson.edu
- X
- XBrad Clements, Sr. Network Engineer
- XEducational Resources Center
- XClarkson University
- XPotsdam, NY 13699
- X
- Xbkc@draco.erc.clarkson.edu
- X
- X-----------
- XSample Config.tel file
- X------------------------------
- X# Example host file for ARCHIE/ CUTCP version
- X# 11/21/91
- X#
- X# Bugs to cutcp-bugs@omnigate.clarkson.edu
- X
- X#---------------------------------------------------------------------------#
- X# #
- X#** ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION **#
- X# #
- X# This sample config.tel file contains every single option that you could #
- X# possibly use. Its meant as an example only. Please Please PLEASE don't #
- X# use all these options in your working config.tel file, just the ones #
- X# that you actually need. Many options can be left out, the default action#
- X# (if defined) is shown in parens () next to the option. #
- X# #
- X# Thank you for your support #
- X#---------------------------------------------------------------------------#
- X
- X#
- X# This example file is for my=bootp, in which case the following items are
- X# determined from the bootp server: (and are thus commented out in this file)
- X# 1. This machine's IP Address
- X# 2. The network NETMASK
- X# 3. The default gateway (one or more)
- X# 4. Nameservers (one or more)
- X# 5. The domain search list (if this clients hostname is in the bootp packet)
- X#
- X# Your BOOTP server needs to be RFC 1048 compliant for this to work
- X#
- X# If you have nameservers, gateways or a domainslist already specified
- X# in this file, then the file's entry takes precedence.
- X# Extra gateways and nameservers will be added by BOOTP if found, however.
- X#----------------------------------------------------------------------------
- X# You can set a DOS environment variable CONFIGTEL to point to this file
- X# then you don't need batch files or the -h option.
- X#
- X# C> set CONFIGTEL=C:\net\myconfig.tel
- X#
- X# You may also use environment variables to include config.tel options,
- X# such as:
- X# C> set $CUTCP1=myip~197.001.42.98;netmask~255.255.252.0
- X# C> set $CUTCP2=name~x;hostip~128.163.298.2
- X#
- X# and so on up to $CUTCP99. Note that you use a tilde (~) instead of (=)
- X# in the dos set command because two ='s are not allowed by Dos.
- X#
- X# Additionally, there is a new config.tel option called include= which
- X# allows the nesting (up to 3) configuration files deep.
- X#
- X#
- X# You can use these new options on networks to make your configuration job
- X# easier. CUTCP always opens config.tel files as read-only, so you can mark
- X# your files as sharable, read only. Also, you can use the include= command
- X# in a $CUTCP environment variable, and on the command line.
- X
- X# *Note* that you can not include a machine specific parameter before
- X# name=default... This used to work in old versions, but is strictly
- X# enforced in this version.
- X# --------------------------------------------------------------------------
- X# This file is free form
- X# Separators are any char <33 and :;=
- X#
- X# The form is keyword=value for each parameter.
- X# The first set of parameters refer to the whole program's defaults.
- X# These parameter values can be in any order.
- X# Following this are the individual machine specs.
- X#
- X
- Xmyip=128.153.28.65 # (bootp)
- X # myip types are:
- X # bootp - sends out a BOOTP request for your IP
- X # rarp - Uses reverse ARp to get your IP
- X # xx.yy.zz.qq - your IP address
- X
- Xvjc=no # (no)
- X # set vjc=yes if you're running slip and
- X # you want to use Van Jacobson TCP header
- X # compression
- X
- Xsplayc=no # (no) ack. splay compression w/ vjc.. don't
- X # use it, not standard, development option only
- X
- Xmyname=userid # put your userid here, used for Rlogin
- X # PC-NFS version ignores this value and uses the name
- X # that you specified to your pcnfsd.
- X
- Xnetmask=255.255.252.0 # needed if not using BOOTP.
- X # otherwise not needed because Bootp gets your netmask
- X # for you
- X
- Xhardware=packet # (packet)
- X # harware choices
- X # 3com - 3com 3c501
- X # 3c523 - 3com 3c523
- X # wd800 - Western Digitial 800E
- X # nicpc -
- X # nicps -
- X # ni5210 - Micom Interlan NI5210 card
- X # packet - FTP packet Driver spec
- X # (currently only Ethernet and Slip class devices are supported)
- X
- Xinterrupt=2 # hardware IRQ interrupt
- Xaddress=0 # (0)
- X # base memory address or packet driver class
- X # if using packet driver (0 == default == ethernet)
- X # or class=6 for slip
- X
- Xioaddr=0 # (0)
- X # I/O address or packet int vector if using packet driver
- X # If = 0 and packet driver, telbin looks for first
- X # packet driver found between 60H and 7FH
- X
- Xnoarpme=yes # Don't arp for myself before running? (no)
- X # if yes, inhibits the initial arp request
- X # for this IP address. However, if yes, won't
- X # warn you if another user is using this IP
- X # address. For some token ring systems, you'll
- X # need noarpme=yes.
- X
- Xinclude="nul" # if you want to include another file as part
- X # of this one (you can nest up to three includes)
- X # otherwise, don't use this option
- X
- Xdomaintime=4 # domain name lookup timeout (first retry)
- Xdomainretry=4 # domain name max number of retries
- Xdomainslist="clarkson.edu,aux.clarkson.edu" # domain name search path
- X # domain name lookup will attach each of these
- X # comma seperated suffixes to
- X # the end of the name you are looking for to
- X # discover the full name and IP address.
- X # so, looking for x tries x.clarkson.edu and x.aux.clarkson.edu then just x
- X # unless you use x. which ONLY looks for x
- X
- X ## Also, the fewer suffixes in the domainslist
- X ## the less time you will have to wait if you mis-type an entry.
- X ## Finally, try not to use a suffix like . or .edu or .com this will
- X ## waste a lot of time looking for a bogus host name if you mis-type an entry.
- X
- X## ----------------------------------------------------------------- ##
- X## BEGIN MACHINE SPECIFIC PARAMETERS... ##
- X## ----------------------------------------------------------------- ##
- X
- Xname=default # default entry sets defaults for all following
- X # machines.
- X
- Xarptime=10 # arp timeout in seconds
- X #
- X
- Xretrans=1 # starting retransmit time out in ticks
- X # 1/18ths of sec MAX 100, min 1
- X
- Xmtu=1024 # maximum transmit unit in bytes
- X # outgoing packet size, MAX=1500
- X
- Xmaxseg=1024 # largest segment we can receive
- X # whatever the hardware can take, MAX=4096
- Xrwin=2048 # most bytes we can receive without ACK
- X # =TCP window size, MAX=4096
- X
- Xcontime=20 # timeout in seconds to try connection
- X # before returning error to user
- X
- X# Following are individual machine specifications
- X# Gateways are used in order that they appear in the file
- X# Nameservers rotate, #1, #2, #3, #1, #2 when a request fails
- X#
- X
- X# ********************************************************************* ###
- X# Note: If you are using BOOTP above for myip=, then you do not need
- X# to enter a default gateway, nameserver, netmask etc (unless you want to)
- X# only IF your BOOTP server is rfc_1048 compliant. (Ask your Net Manager)
- X# You can use both bootp and entries here, in which case the entries in
- X# this file over-ride what BOOTP discovers. (however, bootp nameservers
- X# and gateways are ADDED to this file's list of entries
- X# ********************************************************************* ####
- X
- X# Below this line, most of the communication parameters are obtained
- X# from the "default" host entry. Those parameters listed for a host
- X# override the default host values.
- X#
- X# These are examples, replace them with the correct values for your site.
- X#name=mynameserver
- X#host=omnigate.clarkson.edu
- X#hostip=197.001.4.2
- X#nameserver=1
- X
- X#name=backupserver
- X#host=clutx.clarkson.edu
- X#hostip=197.001.4.3
- X#nameserver=2
- X
- X#name=lastserver
- X#host=n2ngw.nyser.net
- X#hostip=128.145.198.2
- X#nameserver=3
- X
- X#name=mygateway
- X#host=nysernet.clarkson.edu
- X#hostip=197.001.4.1
- X#gateway=1
- X
- X
- Xname=archie
- Xhost=archie.funet.fi
- END_OF_FILE
- if test 10680 -ne `wc -c <'README.dos'`; then
- echo shar: \"'README.dos'\" unpacked with wrong size!
- fi
- # end of 'README.dos'
- fi
- if test ! -d 'msdos' ; then
- echo shar: Creating directory \"'msdos'\"
- mkdir 'msdos'
- fi
- if test ! -d 'vms' ; then
- echo shar: Creating directory \"'vms'\"
- mkdir 'vms'
- fi
- if test -f 'vms/in.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vms/in.h'\"
- else
- echo shar: Extracting \"'vms/in.h'\" \(1418 characters\)
- sed "s/^X//" >'vms/in.h' <<'END_OF_FILE'
- X/* netinet/in.h */
- Xstruct in_addr
- X{
- X union
- X {
- X struct
- X {
- X unsigned char s_b1, s_b2, s_b3, s_b4;
- X } S_un_b;
- X struct
- X {
- X unsigned short s_w1, s_w2;
- X } S_un_w;
- X unsigned long S_addr;
- X } S_un;
- X#define s_addr S_un.S_addr
- X#define s_host S_un.S_un_b.s_b2
- X#define s_net S_un.S_un_b.s_b1
- X#define s_imp S_un.S_un_w.s_w2
- X#define s_impno S_un.S_un_b.s_b4
- X#define s_lh S_un.S_un_b.s_b3
- X};
- X
- X#define INADDR_ANY 0x00000000
- X#define INADDR_BROADCAST 0xffffffff
- X#define INADDR_LOOPBACK 0x7f000001
- X
- Xstruct sockaddr_in
- X{
- X short sin_family;
- X unsigned short sin_port;
- X struct in_addr sin_addr;
- X char sin_zero[8];
- X};
- X
- X#define ntohl(x) (( (((unsigned long) x) >> 24)& 0x000000ff ) |\
- X ( (((unsigned long) x) >> 8) & 0x0000ff00 ) |\
- X ( (((unsigned long) x) << 8) & 0x00ff0000 ) |\
- X ( (((unsigned long) x) << 24)& 0xff000000 ))
- X#define ntohs(x) (( (((unsigned short) x) >> 8) |\
- X ( (((unsigned short) x) << 8)) & 0xffff ))
- X#define htonl(x) (( (((unsigned long) x) >> 24)& 0x000000ff ) |\
- X ( (((unsigned long) x) >> 8) & 0x0000ff00 ) |\
- X ( (((unsigned long) x) << 8) & 0x00ff0000 ) |\
- X ( (((unsigned long) x) << 24)& 0xff000000 ))
- X#define htons(x) (( (((unsigned short) x) >> 8) |\
- X ( (((unsigned short) x) << 8)) & 0xffff ))
- X
- X#define IPPORT_RESERVED 1024
- END_OF_FILE
- if test 1418 -ne `wc -c <'vms/in.h'`; then
- echo shar: \"'vms/in.h'\" unpacked with wrong size!
- fi
- # end of 'vms/in.h'
- fi
- if test -f 'vms_support.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vms_support.c'\"
- else
- echo shar: Extracting \"'vms_support.c'\" \(32780 characters\)
- sed "s/^X//" >'vms_support.c' <<'END_OF_FILE'
- X/* Emulation of 4.2 UNIX socket interface routines includes drivers for
- X Wollongong, CMU-TEK, UCX tcp/ip interface and also emulates the SUN
- X version of X.25 sockets. The TWG will also work for MultiNet. */
- X
- X/* This is from unixlib, by P.Kay@massey.ac.nz; wonderful implementation.
- X You can get the real thing on 130.123.1.4 as unixlib_tar.z. */
- X
- X#include <stdio.h>
- X#include <errno.h>
- X#include <ssdef.h>
- X#include <dvidef.h>
- X#include <signal.h>
- X#include <sys$library:msgdef.h>
- X#include <iodef.h>
- X#include <ctype.h>
- X#include <vms.h>
- X#include "[.vms]network.h"
- X
- X#define QIO_FAILED (st != SS$_NORMAL || p[s].iosb[0] != SS$_NORMAL)
- X#define QIO_ST_FAILED (st != SS$_NORMAL)
- X
- X/* Socket routine. */
- Xint
- XVMSsocket (domain, type, protocol)
- X int domain, type, protocol;
- X{
- X struct descriptor inetdesc, x25desc, mbxdesc;
- X int i, st, s, p_initialise ();
- X long ucx_sock_def;
- X char *getenv ();
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X if (p_initialised == 0)
- X {
- X for (i = 0; i < 32; i++)
- X p_initialise (i);
- X
- X p_initialised = 1;
- X }
- X
- X /* First of all, get a file descriptor and file ptr we can associate with
- X the socket, allocate a buffer, and remember the socket details. */
- X s = dup (0);
- X if (s > 31)
- X {
- X errno = EMFILE;
- X close (s);
- X return -1;
- X }
- X
- X p[s].fptr = fdopen (s, "r");
- X p[s].fd_buff = (unsigned char *) malloc (BUF_SIZE);
- X p[s].domain = domain;
- X p[s].type = type;
- X p[s].protocol = protocol;
- X
- X /* Handle the case of INET and X.25 separately. */
- X if (domain == AF_INET)
- X {
- X if (tcp_make == NONE)
- X {
- X printf ("Trying to obtain a TCP socket when we don't have TCP!\n");
- X exit (1);
- X }
- X if (tcp_make == CMU)
- X {
- X /* For CMU we need only assign a channel. */
- X inetdesc.size = 3;
- X inetdesc.ptr = "IP:";
- X if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
- X return -1;
- X }
- X else if (tcp_make == UCX)
- X {
- X /* For UCX assign channel and associate a socket with it. */
- X inetdesc.size = 3;
- X inetdesc.ptr = "BG:";
- X if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
- X return -1;
- X
- X ucx_sock_def = (domain << 24) + (type << 16) + protocol;
- X st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
- X &ucx_sock_def, 0, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X }
- X else
- X {
- X /* For TWG we assign the channel and associate a socket with it. */
- X inetdesc.size = 7;
- X inetdesc.ptr = "_INET0:";
- X
- X if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
- X return -1;
- X
- X st = sys$qiow (0, p[s].channel, IO$_SOCKET, p[s].iosb, 0, 0,
- X domain, type, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X }
- X }
- X else
- X /* We don't handle any other domains yet. */
- X return -1;
- X
- X /* For each case if we are successful we return the descriptor. */
- X return s;
- X}
- X
- X/* Bind routine. */
- XVMSbind (s, name, namelen)
- X int s;
- X union socket_addr *name;
- X int namelen;
- X{
- X char infobuff[1024], lhost[32];
- X int st;
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X if (p[s].domain == AF_INET)
- X {
- X /* One main problem with bind is that if we're given a port number
- X of 0, then we're expected to return a unique port number. Since
- X we don't KNOW, we return 1050+s and look to Lady Luck. */
- X if (tcp_make == CMU)
- X {
- X if (name->in.sin_port == 0 && p[s].type != SOCK_DGRAM)
- X name->in.sin_port = 1050 + s;
- X p[s].namelen = namelen;
- X bcopy (name, &(p[s].name), namelen);
- X
- X if (p[s].type == SOCK_DGRAM)
- X {
- X /* Another problem is that CMU still needs an OPEN request
- X even if it's a datagram socket. */
- X st = sys$qiow (0, p[s].channel, TCP$OPEN, p[s].iosb,
- X 0, 0, 0, 0, ntohs (p[s].name.in.sin_port),
- X 0, 1, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X
- X p[s].cmu_open = 1;
- X sys$qiow (0, p[s].channel, TCP$INFO, p[s].iosb,
- X 0, 0, &infobuff, 1024, 0, 0, 0, 0);
- X bcopy (infobuff + 264, &(p[s].name.in.sin_port), 2);
- X p[s].name.in.sin_port = htons (p[s].name.in.sin_port);
- X
- X /* So get it another way. */
- X bcopy (infobuff + 136, lhost, infobuff[1]);
- X lhost[infobuff[1]] = '\0';
- X sys$qiow (0, p[s].channel, GTHST, p[s].iosb,
- X 0, 0, &infobuff, 1024, 1, lhost, 0, 0);
- X bcopy (infobuff + 4, &(p[s].name.in.sin_addr), 4);
- X
- X /* Be prepared to receive a message. */
- X hang_a_read (s);
- X }
- X }
- X else if (tcp_make == UCX)
- X {
- X /* UCX will select a prot for you. If the port's number is 0,
- X translate "name" into an item_2 list. */
- X struct itemlist lhost;
- X lhost.length = namelen;
- X lhost.code = 0;
- X lhost.dataptr = (char *) name;
- X
- X st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
- X 0, 0, &lhost, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X if (p[s].type == SOCK_DGRAM)
- X hang_a_read (s);
- X
- X }
- X else
- X {
- X /* WG is more straightforward */
- X st = sys$qiow (0, p[s].channel, IO$_BIND, p[s].iosb,
- X 0, 0, name, namelen, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X /* If it's a datagram, get ready for the message. */
- X if (p[s].type == SOCK_DGRAM)
- X hang_a_read (s);
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X
- X return 0;
- X}
- X
- X/* Connect routine. */
- XVMSconnect (s, name, namelen)
- X int s;
- X union socket_addr *name;
- X int namelen;
- X{
- X int pr, fl, st;
- X char *inet_ntoa ();
- X static struct
- X {
- X int len;
- X char name[128];
- X } gethostbuf;
- X extern int connect_ast ();
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X /* For datagrams we need to remember who the name was so we can send all
- X messages to that address without having to specify it all the time. */
- X if (p[s].connected)
- X {
- X if (p[s].connected == 1)
- X errno = EISCONN;
- X else
- X {
- X errno = ECONNREFUSED;
- X p[s].connected = 0;
- X }
- X return -1;
- X }
- X
- X if (p[s].connect_pending)
- X {
- X errno = EALREADY;
- X return -1;
- X }
- X
- X p[s].passive = 0;
- X p[s].tolen = namelen;
- X bcopy (name, &(p[s].to), namelen);
- X
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X {
- X
- X /* Get the info about the remote host and open up a connection. */
- X st = sys$qiow (0, p[s].channel, GTHST, p[s].iosb, 0, 0, &gethostbuf,
- X 132, 2, name->in.sin_addr.s_addr, 0, 0);
- X if (QIO_FAILED)
- X {
- X strcpy (gethostbuf.name, inet_ntoa (name->in.sin_addr.s_addr));
- X gethostbuf.len = strlen (gethostbuf.name);
- X }
- X gethostbuf.name[gethostbuf.len] = 0;
- X
- X /* TCP */
- X pr = 0;
- X /* Active */
- X fl = 1;
- X
- X /* Nothing else for datagrams. */
- X if (p[s].type == SOCK_DGRAM)
- X return (0);
- X st = sys$qio (s, p[s].channel, TCP$OPEN, p[s].iosb, connect_ast,
- X &p[s], &(gethostbuf.name), ntohs (name->in.sin_port),
- X ntohs (p[s].name.in.sin_port), fl, pr, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X else if (tcp_make == UCX)
- X {
- X /* Both UDP and TCP can use a connect - IO$_ACCESS */
- X p[s].rhost.length = namelen;
- X p[s].rhost.code = 0;
- X p[s].rhost.dataptr = (char *) name;
- X
- X st = sys$qio (s, p[s].channel, IO$_ACCESS, p[s].iosb, connect_ast,
- X &p[s], 0, 0, &p[s].rhost, 0, 0, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X else
- X {
- X /* TWG */
- X if (p[s].type == SOCK_DGRAM)
- X return (0);
- X st = sys$qio (s, p[s].channel, IO$_CONNECT, p[s].iosb, connect_ast,
- X &p[s], name, namelen, 0, 0, 0, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X
- X if (p[s].non_blocking)
- X {
- X if (p[s].connected)
- X {
- X if (p[s].connected == 1)
- X return 0;
- X else
- X {
- X p[s].connected = 0;
- X errno = ECONNREFUSED;
- X return -1;
- X }
- X }
- X else
- X {
- X p[s].connect_pending = 1;
- X errno = EINPROGRESS;
- X return -1;
- X }
- X }
- X else
- X {
- X /* wait for the connection to occur */
- X if (p[s].connected)
- X {
- X if (p[s].connected == 1)
- X return 0;
- X else
- X {
- X p[s].connected = 0;
- X errno = ECONNREFUSED;
- X return -1;
- X }
- X }
- X
- X /* Timed out? */
- X if (wait_efn (s) == -1)
- X return -1;
- X
- X if (p[s].connected != SS$_NORMAL)
- X {
- X errno = ECONNREFUSED;
- X return -1;
- X }
- X
- X return 0;
- X }
- X}
- X
- X/* Listen routine. */
- XVMSlisten (s, backlog)
- X int s;
- X int backlog;
- X{
- X int st;
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X p[s].passive = 1;
- X p[s].backlog = backlog;
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X {
- X /* For the CMU sockets we can't do the open call in listen;
- X we have to do it in hang_an_accept, because when we close
- X off the connection we have to be ready to accept another
- X one. accept() also calls hang_an_accept on the old
- X descriptor. */
- X
- X /* Nothing */
- X }
- X else if (tcp_make == UCX)
- X {
- X
- X /* Doc Verbage sez backlog is descriptor of byte. Doc examples
- X and common sense say backlog is value. Value doesn't work,
- X so let's try descriptor of byte after all. */
- X struct descriptor bl;
- X unsigned char ucx_backlog;
- X
- X ucx_backlog = (unsigned char) backlog;
- X bl.size = sizeof (ucx_backlog);
- X bl.ptr = (char *) &ucx_backlog;
- X
- X st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
- X 0, 0, 0, &bl, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X }
- X else
- X {
- X /* TWG */
- X st = sys$qiow (0, p[s].channel, IO$_LISTEN, p[s].iosb, 0, 0,
- X backlog, 0, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X
- X p[s].status = LISTENING;
- X hang_an_accept (s);
- X return 0;
- X}
- X
- X/* Accept routine. */
- Xint
- XVMSaccept (s, addr, addrlen)
- X int s;
- X union socket_addr *addr;
- X int *addrlen;
- X{
- X int news, st;
- X struct descriptor inetdesc;
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X if (p[s].non_blocking && !p[s].accept_pending)
- X {
- X errno = EWOULDBLOCK;
- X return -1;
- X }
- X
- X /* hang_an_accept set up an incoming connection request so we have first
- X to hang around until one appears or we time out. */
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X {
- X char infobuff[1024];
- X
- X /* Timed out? */
- X if (wait_efn (s) == -1)
- X return -1;
- X
- X /* Ok, get a new descriptor ... */
- X news = dup (0);
- X if (news > 31)
- X {
- X errno = EMFILE;
- X close (news);
- X return -1;
- X }
- X
- X /* ... and copy all of our data across. */
- X bcopy (&p[s], &p[news], sizeof (p[0]));
- X
- X /* But not this field, of course! */
- X p[news].s = news;
- X
- X sys$qiow (0, p[news].channel, TCP$INFO, p[news].iosb,
- X 0, 0, &infobuff, 1024, 0, 0, 0, 0);
- X
- X /* Copy across the connection info if necessary. */
- X if (addr != 0)
- X {
- X *addrlen = sizeof (struct sockaddr_in);
- X bcopy (infobuff + 132, &(addr->in.sin_port), 2);
- X addr->in.sin_port = htons (addr->in.sin_port);
- X addr->in.sin_family = AF_INET;
- X bcopy (infobuff + 272, &(addr->in.sin_addr), 4);
- X p[news].fromlen = *addrlen;
- X bcopy (addr, &(p[news].from), *addrlen);
- X }
- X p[news].status = PASSIVE_CONNECTION;
- X
- X /* Get a new file ptr for the socket. */
- X p[news].fptr = fdopen (news, "r");
- X
- X /* Reset this field. */
- X p[news].accept_pending = 0;
- X
- X /* Allocate a buffer. */
- X p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
- X p[news].fd_leftover = 0;
- X
- X /* Be prepared to get msgs. */
- X hang_a_read (news);
- X
- X /* Now fix up our previous socket so it's again listening
- X for connections. */
- X inetdesc.size = 3;
- X inetdesc.ptr = "IP:";
- X if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
- X return -1;
- X p[s].status = LISTENING;
- X hang_an_accept (s);
- X
- X /* Return the new socket descriptor. */
- X return news;
- X }
- X else if (tcp_make == UCX)
- X {
- X /* UCX does the actual accept from hang_an_accept. The accept info
- X is put into the data structure for the "listening" socket.
- X These just need to be copied into a newly allocated socket for
- X the connect and the listening socket re-started. */
- X
- X /* Wait for event flag from accept being received inside
- X of hang_an_accept(). */
- X
- X if (wait_efn (s) == -1)
- X /* Timed out. */
- X return -1;
- X
- X /* Ok, get a new descriptor ... */
- X news = dup (0);
- X if (news > 31)
- X {
- X errno = EMFILE;
- X close (news);
- X return -1;
- X }
- X /* ... and copy all of our data across. */
- X bcopy (&p[s], &p[news], sizeof (p[0]));
- X p[news].s = news; /* but not this field */
- X p[news].channel = p[s].ucx_accept_chan;
- X
- X /* Initialize the remote host address item_list_3 struct. */
- X p[news].rhost.length = sizeof (struct sockaddr_in);
- X p[news].rhost.code = 0;
- X p[news].rhost.dataptr = (char *) &p[news].from;
- X p[news].rhost.retlenptr = &p[news].fromdummy;
- X
- X if (addr != 0)
- X {
- X /* Return the caller's info, if requested. */
- X *addrlen = p[news].fromdummy;
- X bcopy (&p[news].from, addr, p[news].fromdummy);
- X }
- X
- X /* Finish fleshing out the new structure. */
- X p[news].status = PASSIVE_CONNECTION;
- X
- X /* Get a new file pointer for the socket. */
- X p[news].fptr = fdopen (news, "r");
- X
- X /* Reset this field. */
- X p[news].accept_pending = 0;
- X
- X /* Allocate a buffer. */
- X p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
- X p[news].fd_leftover = 0;
- X
- X /* Get it started reading. */
- X hang_a_read (news);
- X
- X p[s].status = LISTENING;
- X hang_an_accept (s);
- X
- X return news;
- X }
- X else
- X {
- X /* TWG */
- X struct descriptor inetdesc;
- X int size;
- X
- X /* Time out? */
- X if (wait_efn (s) == -1)
- X return -1;
- X
- X /* Ok, get a new descriptor ... */
- X news = dup (0);
- X if (news > 31)
- X {
- X errno = EMFILE;
- X close (news);
- X return -1;
- X }
- X
- X /* Assign a new channel. */
- X inetdesc.size = 7;
- X inetdesc.ptr = "_INET0:";
- X st = sys$assign (&inetdesc, &p[news].channel, 0, 0);
- X if (QIO_ST_FAILED)
- X {
- X p[s].accept_pending = 0;
- X sys$clref (s);
- X return -1;
- X }
- X
- X /* From info needs an int length field! */
- X size = sizeof (p[s].from) + 4;
- X st = sys$qiow (0, p[news].channel, IO$_ACCEPT, p[news].iosb, 0, 0,
- X &p[s].fromdummy, size, p[s].channel, 0, 0, 0);
- X
- X if (QIO_ST_FAILED || p[news].iosb[0] != SS$_NORMAL)
- X {
- X p[s].accept_pending = 0;
- X sys$clref (s);
- X return -1;
- X }
- X
- X if (addr != 0)
- X {
- X /* Return the caller's info if requested. */
- X *addrlen = p[s].fromdummy;
- X bcopy (&p[s].from, addr, *addrlen);
- X }
- X
- X /* Fix up our new data structure. */
- X p[news].status = PASSIVE_CONNECTION;
- X p[news].domain = AF_INET;
- X p[news].passive = 1;
- X p[news].fptr = fdopen (news, "r");
- X /* Allocate a buffer. */
- X p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
- X
- X /* Be prepared to accept msgs. */
- X hang_a_read (news);
- X
- X /* Get the old descriptor back onto accepting. */
- X hang_an_accept (s);
- X return news;
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X}
- X
- X/* Recv routine. */
- Xint
- XVMSrecv (s, buf, len, flags)
- X int s;
- X char *buf;
- X int len, flags;
- X{
- X return recvfrom (s, buf, len, flags, 0, 0);
- X}
- X
- X/* Revfrom routine. */
- Xint
- XVMSrecvfrom (s, buf, len, flags, from, fromlen)
- X int s;
- X char *buf;
- X int len, flags;
- X union socket_addr *from;
- X int *fromlen;
- X{
- X int number;
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X if (p[s].domain != AF_INET && p[s].domain != AF_X25)
- X return -1;
- X
- X /* If we're not onto datagrams, then it's possible that a previous
- X call to recvfrom didn't read all the data, and left some behind.
- X So first of all, look in our data buffer for any leftovers that
- X will satisfy this read. */
- X
- X /* We couldn't satisfy the request from previous calls so we must now
- X wait for a message to come through. */
- X if (wait_efn (s) == -1)
- X /* Timed out. */
- X return -1;
- X
- X if (p[s].closed_by_remote == 1)
- X {
- X /* This could have happened! */
- X errno = ECONNRESET;
- X return -1;
- X }
- X
- X if (from != NULL)
- X {
- X if (tcp_make == CMU)
- X {
- X if (p[s].type == SOCK_DGRAM)
- X {
- X /* Not documented but we get the from data from the beginning of
- X the data buffer. */
- X *fromlen = sizeof (p[s].from.in);
- X from->in.sin_family = AF_INET;
- X bcopy (&p[s].fd_buff[8], &(from->in.sin_port), 2);
- X from->in.sin_port = htons (from->in.sin_port);
- X bcopy (&p[s].fd_buff[0], &(from->in.sin_addr), 4);
- X
- X /* Remove the address data from front of data buffer. */
- X bcopy (p[s].fd_buff + 12, p[s].fd_buff, p[s].fd_buff_size);
- X }
- X else
- X {
- X *fromlen = p[s].fromlen;
- X bcopy (&p[s].from, from, p[s].fromlen);
- X }
- X }
- X else if (tcp_make == UCX)
- X {
- X *fromlen = p[s].fromdummy;
- X bcopy (&p[s].from, from, p[s].fromdummy);
- X }
- X else
- X {
- X *fromlen = p[s].fromlen;
- X bcopy (&p[s].from, from, p[s].fromlen);
- X }
- X }
- X
- X /* We may've received too much. */
- X number = p[s].fd_buff_size;
- X if (number <= len)
- X {
- X /* If we haven't give back all the data available. */
- X bcopy (p[s].fd_buff, buf, number);
- X p[s].fd_leftover = 0;
- X hang_a_read (s);
- X return (number);
- X }
- X else
- X {
- X /* If we have too much data then split it up. */
- X p[s].fd_leftover = p[s].fd_buff;
- X bcopy (p[s].fd_leftover, buf, len);
- X /* And change the pointers. */
- X p[s].fd_leftover += len;
- X p[s].fd_buff_size -= len;
- X return (len);
- X }
- X}
- X
- X/* Send routine. */
- Xint
- XVMSsend (s, msg, len, flags)
- X int s;
- X char *msg;
- X int len, flags;
- X{
- X return sendto (s, msg, len, flags, 0, 0);
- X}
- X
- X/* Sendto routine. */
- Xint
- XVMSsendto (s, msg, len, flags, to, tolen)
- X int s;
- X unsigned char *msg;
- X int len, flags;
- X union socket_addr *to;
- X int tolen;
- X{
- X int i, j, st, size;
- X unsigned char udpbuf[BUF_SIZE + 12];
- X char infobuff[1024], lhost[32];
- X unsigned short int temp;
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X /* First remember who we sent it to and set the value of size. */
- X if (to != 0)
- X {
- X p[s].tolen = tolen;
- X bcopy (to, &(p[s].to), tolen);
- X size = tolen;
- X }
- X else
- X size = 0;
- X
- X if (p[s].domain == AF_INET)
- X {
- X /* We might never have started a read for udp (socket/sendto) so
- X put one here. */
- X if (p[s].type == SOCK_DGRAM)
- X hang_a_read (s);
- X
- X if (tcp_make == CMU)
- X {
- X if (p[s].type == SOCK_DGRAM)
- X {
- X /* We might never have opened up a udp connection yet,
- X so check. */
- X if (p[s].cmu_open != 1)
- X {
- X st = sys$qiow (0, p[s].channel, TCP$OPEN, p[s].iosb, 0, 0,
- X 0, 0, 0, 0, 1, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X
- X p[s].cmu_open = 1;
- X sys$qiow (0, p[s].channel, TCP$INFO, p[s].iosb,
- X 0, 0, &infobuff, 1024, 0, 0, 0, 0);
- X bcopy (infobuff + 264, &(p[s].name.in.sin_port), 2);
- X p[s].name.in.sin_port = htons (p[s].name.in.sin_port);
- X bcopy (infobuff + 136, lhost, infobuff[1]);
- X lhost[infobuff[1]] = '\0';
- X sys$qiow (0, p[s].channel, GTHST, p[s].iosb,
- X 0, 0, &infobuff, 1024, 1, lhost, 0, 0);
- X bcopy (infobuff + 4, &(p[s].name.in.sin_addr), 4);
- X }
- X
- X /* This isn't well documented. To send to a UDP socket, we
- X need to put the address info at the beginning of the
- X buffer. */
- X bcopy (msg, udpbuf + 12, len);
- X bcopy (&p[s].to.in.sin_addr, udpbuf + 4, 4);
- X temp = ntohs (p[s].to.in.sin_port);
- X bcopy (&temp, udpbuf + 10, 2);
- X bcopy (&p[s].name.in.sin_addr, udpbuf, 4);
- X temp = ntohs (p[s].name.in.sin_port);
- X bcopy (&temp, udpbuf + 8, 2);
- X temp = len + 12;
- X st = sys$qiow (0, p[s].channel, TCP$SEND, p[s].iosb, 0, 0,
- X udpbuf, temp, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X }
- X else
- X {
- X /* TCP (! UDP) */
- X st = sys$qiow (0, p[s].channel, TCP$SEND, p[s].iosb, 0, 0,
- X msg, len, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X }
- X return len;
- X }
- X else if (tcp_make == UCX)
- X {
- X struct itemlist rhost;
- X rhost.length = sizeof (struct sockaddr_in);
- X rhost.code = 0;
- X rhost.dataptr = (char *) &p[s].to;
- X
- X st = sys$qiow (0, p[s].channel, IO$_WRITEVBLK, p[s].iosb, 0, 0,
- X msg, len, &rhost, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X return len;
- X }
- X else
- X {
- X /* TWG */
- X st = sys$qiow (0, p[s].channel, IO$_WRITEVBLK, p[s].iosb,
- X 0, 0, msg, len, 0, &p[s].to, size, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X return len;
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X}
- X
- X/* Getsockname routine. */
- Xint
- XVMSgetsockname (s, name, namelen)
- X int s;
- X union socket_addr *name;
- X int *namelen;
- X{
- X int st;
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X {
- X /* For CMU we just return values held in our data structure. */
- X *namelen = p[s].namelen;
- X bcopy (&(p[s].name), name, *namelen);
- X return (0);
- X }
- X else if (tcp_make == UCX)
- X {
- X /* An item_list_3 descriptor. */
- X struct itemlist lhost;
- X
- X lhost.length = *namelen;
- X lhost.code = 0;
- X lhost.dataptr = (char *) name;
- X
- X /* Fill in namelen with actual ret len value. */
- X lhost.retlenptr = (short int *) namelen;
- X
- X st = sys$qiow (0, p[s].channel, IO$_SENSEMODE, p[s].iosb, 0, 0,
- X 0, 0, &lhost, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X return 0;
- X }
- X else
- X {
- X /* TWG gives us the information. */
- X st = sys$qiow (0, p[s].channel, IO$_GETSOCKNAME, p[s].iosb,
- X 0, 0, name, namelen, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X return 0;
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X}
- X
- X/* Select routine. */
- Xint
- XVMSselect (nfds, readfds, writefds, exceptfds, timeout)
- X int nfds;
- X fd_set *readfds, *writefds, *exceptfds;
- X struct timeval *timeout;
- X{
- X int timer, fd, alarm_set, total, end;
- X long mask, cluster;
- X struct descriptor termdesc;
- X static fd_set new_readfds, new_writefds, new_exceptfds;
- X
- X FD_ZERO (&new_readfds);
- X FD_ZERO (&new_writefds);
- X FD_ZERO (&new_exceptfds);
- X total = 0;
- X
- X /* Assign a terminal channel if we haven't already. */
- X if (terminal.chan == -1)
- X {
- X termdesc.size = 10;
- X termdesc.ptr = "SYS$INPUT:";
- X sys$assign (&termdesc, &terminal.chan, 0, 0);
- X }
- X alarm_set = 0;
- X if (timeout != NULL)
- X {
- X /* If a timeout is given then set the alarm. */
- X end = timeout->tv_sec;
- X if (timer != 0)
- X {
- X /* We need to reset the alarm if it didn't fire, but we set it. */
- X alarm_set = 1;
- X si_alarm (end);
- X }
- X }
- X else
- X end = 1;
- X
- X do
- X {
- X if (exceptfds)
- X {
- X /* Nothing */ ;
- X }
- X
- X if (writefds)
- X {
- X for (fd = 0; fd < nfds; fd++)
- X if (FD_ISSET (fd, writefds))
- X {
- X if (p[fd].connect_pending)
- X /* Nothing */ ;
- X else if ((p[fd].status == ACTIVE_CONNECTION)
- X || (p[fd].status == PASSIVE_CONNECTION))
- X {
- X FD_SET (fd, &new_writefds);
- X total++;
- X }
- X }
- X }
- X
- X if (readfds)
- X {
- X /* True if data pending or an accept. */
- X for (fd = 3; fd < nfds; fd++)
- X if (FD_ISSET (fd, readfds) &&
- X ((p[fd].fd_buff_size != -1) || (p[fd].accept_pending == 1)))
- X {
- X FD_SET (fd, &new_readfds);
- X total++;
- X }
- X }
- X
- X if (total || (end == 0))
- X break;
- X
- X /* Otherwise, wait on an event flag. It's possible that the wait can
- X be stopped by a spurious event flag being set -- i.e. one that's
- X got a status not normal. So we've got to be prepared to loop
- X around the wait until a valid reason happens. */
- X
- X /* Set up the wait mask. */
- X cluster = 0;
- X mask = 0;
- X for (fd = 3; fd < nfds; fd++)
- X {
- X sys$clref (fd);
- X if (readfds)
- X if FD_ISSET
- X (fd, readfds) mask |= (1 << fd);
- X if (writefds)
- X if FD_ISSET
- X (fd, writefds) mask |= (1 << fd);
- X if (exceptfds)
- X if FD_ISSET
- X (fd, exceptfds) mask |= (1 << fd);
- X }
- X
- X mask |= (1 << TIMER_EFN);
- X
- X /* Clear it off just in case. */
- X sys$clref (TIMER_EFN);
- X
- X /* Wait around. */
- X sys$wflor (cluster, mask);
- X
- X mask = 0;
- X if (read_efn (TIMER_EFN))
- X {
- X errno = EINTR;
- X break;
- X }
- X } while (1);
- X /*NOTREACHED*/
- X
- X /* Unset the alarm if we set it. */
- X if (alarm_set == 1)
- X alarm (0);
- X
- X if (readfds)
- X *readfds = new_readfds;
- X
- X if (writefds)
- X *writefds = new_writefds;
- X
- X if (exceptfds)
- X *exceptfds = new_exceptfds;
- X
- X return total;
- X}
- X
- X/* Shutdown routine. */
- XVMSshutdown (s, how)
- X int s, how;
- X{
- X int st;
- X int ucx_how;
- X
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X {
- X /* For CMU we just close off. */
- X si_close (s);
- X return 0;
- X }
- X else if (tcp_make == UCX)
- X {
- X st = sys$qiow (0, p[s].channel, IO$_DEACCESS | IO$M_SHUTDOWN,
- X p[s].iosb, 0, 0, 0, 0, 0, how, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X return 0;
- X }
- X else
- X {
- X /* TWG lets us do it. */
- X st = sys$qiow (0, p[s].channel, IO$_SHUTDOWN, p[s].iosb, 0, 0, how,
- X 0, 0, 0, 0, 0);
- X if (QIO_FAILED)
- X return -1;
- X
- X return 0;
- X }
- X }
- X else /* it wasn't a socket */
- X return -1;
- X}
- X
- X/* */
- X
- X/* The following routines are used by the above socket calls. */
- X
- X/* hang_a_read sets up a read to be finished at some later time. */
- Xhang_a_read (s)
- X int s;
- X{
- X extern int read_ast ();
- X int size, st;
- X
- X /* Don't bother if we already did it. */
- X if (p[s].read_outstanding == 1)
- X return;
- X
- X /* Have a read outstanding. */
- X p[s].read_outstanding = 1;
- X size = sizeof (p[s].from) + 4;
- X sys$clref (s);
- X
- X /* Clear off the event flag just in case, and reset the buf size. */
- X p[s].fd_buff_size = -1;
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X {
- X st = sys$qio (s, p[s].channel, TCP$RECEIVE, p[s].iosb, read_ast,
- X &p[s], p[s].fd_buff, BUF_SIZE, 0, 0, 0, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X else if (tcp_make == UCX)
- X {
- X
- X p[s].rhost.length = sizeof (struct sockaddr_in);
- X p[s].rhost.code = 0;
- X p[s].rhost.dataptr = (char *) &p[s].from;
- X p[s].rhost.retlenptr = &p[s].fromdummy;
- X
- X st = sys$qio (s, p[s].channel, IO$_READVBLK, p[s].iosb, read_ast,
- X &p[s], p[s].fd_buff, BUF_SIZE, &p[s].rhost, 0, 0, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X else
- X {
- X /* TWG */
- X st = sys$qio (s, p[s].channel, IO$_READVBLK, p[s].iosb, read_ast,
- X &p[s], p[s].fd_buff, BUF_SIZE, 0, &p[s].fromlen,
- X size, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X}
- X
- X/* hang_an_accept waits for a connection request to come in. */
- Xhang_an_accept (s)
- X int s;
- X{
- X extern int accept_ast ();
- X int st;
- X
- X /* Clear the event flag just in case. */
- X sys$clref (s);
- X
- X /* Reset our flag & buf size. */
- X p[s].accept_pending = 0;
- X p[s].fd_buff_size = -1;
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X {
- X st = sys$qio (s, p[s].channel, TCP$OPEN, p[s].iosb, accept_ast,
- X &p[s], 0, 0, ntohs (p[s].name.in.sin_port), 0, 0, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X else if (tcp_make == UCX)
- X {
- X struct descriptor inetdesc;
- X
- X /* Assign channel for actual connection off listener. */
- X inetdesc.size = 3;
- X inetdesc.ptr = "BG:";
- X if (sys$assign (&inetdesc, &p[s].ucx_accept_chan, 0,
- X 0) != SS$_NORMAL)
- X return -1;
- X
- X /* UCX's accept returns remote host info and the channel for a new
- X socket to perform reads/writes on, so a sys$assign isn't
- X really necessary. */
- X p[s].rhost.length = sizeof (struct sockaddr_in);
- X p[s].rhost.dataptr = (char *) &p[s].from;
- X p[s].fromdummy = 0;
- X p[s].rhost.retlenptr = &p[s].fromdummy;
- X
- X st = sys$qio (s, p[s].channel, IO$_ACCESS | IO$M_ACCEPT, p[s].iosb,
- X accept_ast, &p[s], 0, 0, &p[s].rhost,
- X &p[s].ucx_accept_chan, 0, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X else
- X {
- X st = sys$qio (s, p[s].channel, IO$_ACCEPT_WAIT, p[s].iosb,
- X accept_ast, &p[s], 0, 0, 0, 0, 0, 0);
- X if (QIO_ST_FAILED)
- X return -1;
- X }
- X }
- X else
- X /* We don't handle any other domain yet. */
- X return -1;
- X}
- X
- X/* wait_efn just sets up a wait on either an event or the timer. */
- Xwait_efn (s)
- X int s;
- X{
- X long mask, cluster;
- X
- X cluster = 0;
- X sys$clref (TIMER_EFN);
- X mask = (1 << s) | (1 << TIMER_EFN);
- X sys$wflor (cluster, mask);
- X
- X if (read_efn (TIMER_EFN))
- X {
- X errno = EINTR;
- X return -1;
- X }
- X
- X return 0;
- X}
- X
- X/* read_ast is called by the system whenever a read is done. */
- Xread_ast (p)
- X struct fd_entry *p;
- X{
- X int i, j;
- X unsigned char *v, *w;
- X
- X /* Reset the outstanding flag. */
- X p->read_outstanding = 0;
- X if (p->iosb[0] == SS$_NORMAL)
- X {
- X /* Check no errors. */
- X p->fd_buff_size = p->iosb[1];
- X if (tcp_make == CMU)
- X {
- X /* fiddle for DGRMs */
- X if (p->type == SOCK_DGRAM)
- X p->fd_buff_size -= 12;
- X }
- X if (p->sig_req == 1)
- X gsignal (SIGIO);
- X }
- X else if (p->iosb[0] == SS$_CLEARED)
- X p->closed_by_remote = 1;
- X else if (tcp_make == UCX)
- X {
- X if (p->iosb[0] == SS$_LINKDISCON)
- X p->closed_by_remote = 1;
- X }
- X}
- X
- X/* accept_ast is called whenever an incoming call is detected. */
- Xaccept_ast (p)
- X struct fd_entry *p;
- X{
- X if (p->iosb[0] == SS$_NORMAL)
- X p->accept_pending = 1;
- X else
- X /* If it failed set up another listen. */
- X listen (p->s, p[p->s].backlog);
- X}
- X
- X/* connect_ast is called whenever an async connect is made. */
- Xconnect_ast (p)
- X struct fd_entry *p;
- X{
- X p->connect_pending = 0;
- X if ((p->connected = p->iosb[0]) == SS$_NORMAL)
- X {
- X /* We made the connection. */
- X p->status = ACTIVE_CONNECTION;
- X
- X /* Be prepared to accept a msg. */
- X hang_a_read (p->s);
- X }
- X}
- X
- X/* */
- X/* These routines handle stream I/O. */
- X
- X/* si_close -- must close off any connection in progress. */
- Xsi_close (s)
- X int s;
- X{
- X if (!tcp_make)
- X set_tcp_make ();
- X
- X if ((s < 0) || (s > 31))
- X return -1;
- X
- X if (p[s].channel != 0)
- X {
- X /* Was it one of our descriptors? */
- X if (p[s].domain == AF_INET)
- X {
- X if (tcp_make == CMU)
- X sys$qiow (0, p[s].channel, TCP$CLOSE, p[s].iosb,
- X 0, 0, 0, 0, 0, 0, 0, 0);
- X if (p[s].status != HANDED_OFF)
- X sys$dassgn (p[s].channel);
- X close (s);
- X free (p[s].fd_buff);
- X p_initialise (s);
- X }
- X return 0;
- X }
- X else
- X {
- X /* Re-initialise data structure just in case. */
- X p[s].fd_buff_size = -1;
- X p[s].accept_pending = 0;
- X p[s].status = INITIALISED;
- X return close (s);
- X }
- X}
- X
- X/* si_alarm -- insert a call to our own alarm function. */
- Xsi_alarm (i)
- X int i;
- X{
- X extern int pre_alarm ();
- X
- X /* Make the call to pre_alarm instead of what the user wants;
- X pre_alarm will call his routine when it finishes. */
- X /* VAX needs this call each time! */
- X signal (SIGALRM, pre_alarm);
- X alarm (i);
- X}
- X
- X/* pre_alarm -- gets called first on an alarm signal. */
- Xpre_alarm ()
- X{
- X /* Come here first so we can set our timer event flag. */
- X sys$setef (TIMER_EFN);
- X (*alarm_function) ();
- X}
- X
- X/* p_initialise - initialise our data array. */
- Xp_initialise (s)
- X int s;
- X{
- X int j;
- X for (j = 0; j < 4; j++)
- X p[s].iosb[j] = 0;
- X p[s].channel = 0;
- X p[s].fd_buff_size = -1;
- X p[s].accept_pending = 0;
- X p[s].connect_pending = 0;
- X p[s].connected = 0;
- X p[s].fd_buff = NULL;
- X p[s].fd_leftover = NULL;
- X p[s].fptr = NULL;
- X p[s].s = s;
- X p[s].name.in.sin_port = 0;
- X p[s].masklen = 4;
- X for (j = 0; j < 16; j++)
- X p[s].mask[j] = 0xff;
- X p[s].need_header = 0;
- X p[s].status = INITIALISED;
- X p[s].read_outstanding = 0;
- X p[s].cmu_open = 0;
- X p[s].x25_listener = 0;
- X p[s].mother = s;
- X p[s].child = 0;
- X p[s].no_more_accepts = 0;
- X p[s].closed_by_remote = 0;
- X p[s].non_blocking = 0;
- X p[s].sig_req = 0;
- X sys$clref (s);
- X}
- X
- X/* read_efn -- see whether an event flag is set. */
- Xread_efn (i)
- X int i;
- X{
- X int j;
- X sys$readef (i, &j);
- X j &= (1 << i);
- X
- X return j;
- X}
- X
- Xstatic
- Xset_tcp_make ()
- X{
- X struct descriptor inetdesc;
- X int channel;
- X /* first try CMU */
- X inetdesc.size = 3;
- X inetdesc.ptr = "IP:";
- X if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
- X {
- X sys$dassgn (channel);
- X tcp_make = CMU;
- X return;
- X }
- X
- X /* next try TWG */
- X inetdesc.size = 7;
- X inetdesc.ptr = "_INET0:";
- X if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
- X {
- X sys$dassgn (channel);
- X tcp_make = WG;
- X return;
- X }
- X
- X /* next try UCX */
- X inetdesc.size = 4;
- X inetdesc.ptr = "BG0:";
- X if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
- X {
- X sys$dassgn (channel);
- X tcp_make = UCX;
- X return;
- X }
- X
- X /* nothing there oh dear!*/
- X tcp_make = NONE;
- X return;
- X}
- X
- Xstatic char *
- Xgetdevicename (channel)
- X unsigned short int channel;
- X{
- X int st;
- X struct
- X {
- X struct itemlist id;
- X int eol;
- X } itmlst;
- X static char name[64];
- X short int lgth;
- X
- X name[0] = '\0';
- X itmlst.id.code = DVI$_DEVNAM;
- X itmlst.id.length = 64;
- X itmlst.id.dataptr = name;
- X itmlst.id.retlenptr = &lgth;
- X itmlst.eol = 0;
- X st = sys$getdvi (0, channel, 0, &itmlst, 0, 0, 0, 0);
- X if (QIO_ST_FAILED)
- X fprintf (stderr, "error getting device name %d\n", st);
- X
- X return (name);
- X}
- END_OF_FILE
- if test 32780 -ne `wc -c <'vms_support.c'`; then
- echo shar: \"'vms_support.c'\" unpacked with wrong size!
- fi
- # end of 'vms_support.c'
- fi
- echo shar: End of archive 1 \(of 7\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 7 archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-