home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / scm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  15.8 KB  |  600 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  */
  25. /*
  26.  * SUP Communication Module for 4.3 BSD
  27.  *
  28.  * SUP COMMUNICATION MODULE SPECIFICATIONS:
  29.  *
  30.  * IN THIS MODULE:
  31.  *
  32.  * CONNECTION ROUTINES
  33.  *
  34.  *   FOR SERVER
  35.  *    servicesetup (port)    establish TCP port connection
  36.  *      char *port;            name of service
  37.  *    service ()        accept TCP port connection
  38.  *    servicekill ()        close TCP port in use by another process
  39.  *    serviceprep ()        close temp ports used to make connection
  40.  *    serviceend ()        close TCP port
  41.  *
  42.  *   FOR CLIENT
  43.  *    request (port,hostname,retry) establish TCP port connection
  44.  *      char *port,*hostname;          name of service and host
  45.  *      int retry;              true if retries should be used
  46.  *    requestend ()        close TCP port
  47.  *
  48.  * HOST NAME CHECKING
  49.  *    p = remotehost ()    remote host name (if known)
  50.  *      char *p;
  51.  *    i = samehost ()        whether remote host is also this host
  52.  *      int i;
  53.  *    i = matchhost (name)    whether remote host is same as name
  54.  *      int i;
  55.  *      char *name;
  56.  *
  57.  * RETURN CODES
  58.  *    All procedures return values as indicated above.  Other routines
  59.  *    normally return SCMOK on success, SCMERR on error.
  60.  *
  61.  * COMMUNICATION PROTOCOL
  62.  *
  63.  *    Described in scmio.c.
  64.  *
  65.  **********************************************************************
  66.  * HISTORY
  67.  *  2-Oct-92  Mary Thompson (mrt) at Carnegie-Mellon University
  68.  *    Added conditional declarations of INADDR_NONE and INADDR_LOOPBACK
  69.  *    since Tahoe version of <netinet/in.h> does not define them.
  70.  *
  71.  * $Log: scm.c,v $
  72.  * Revision 1.1.1.1  1993/05/21  14:52:17  cgd
  73.  * initial import of CMU's SUP to NetBSD
  74.  *
  75.  * Revision 1.13  92/08/11  12:05:35  mrt
  76.  *     Added changes from stump:
  77.  *       Allow for multiple interfaces, and for numeric addresses.
  78.  *       Changed to use builtin port for the "supfiledbg"
  79.  *         service when getservbyname() cannot find it.
  80.  *       Added forward static declatations, delinted.
  81.  *       Updated variable argument usage.
  82.  *     [92/08/08            mrt]
  83.  * 
  84.  * Revision 1.12  92/02/08  19:01:11  mja
  85.  *     Add (struct sockaddr *) casts for HC 2.1.
  86.  *     [92/02/08  18:59:09  mja]
  87.  * 
  88.  * Revision 1.11  89/08/03  19:49:03  mja
  89.  *     Updated to use v*printf() in place of _doprnt().
  90.  *     [89/04/19            mja]
  91.  * 
  92.  * 11-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  93.  *    Moved sleep into computeBackoff, renamed to dobackoff.
  94.  *
  95.  * 10-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  96.  *    Added timeout to backoff.
  97.  *
  98.  * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  99.  *    Removed nameserver support.
  100.  *
  101.  * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  102.  *    Fixed to depend less upon having name of remote host.
  103.  *
  104.  * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon Universtiy
  105.  *    Extracted backoff/sleeptime computation from "request" and
  106.  *    created "computeBackoff" so that I could use it in sup.c when
  107.  *    trying to get to nameservers as a group.
  108.  *
  109.  * 21-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
  110.  *    Merged divergent CS and EE versions.
  111.  *
  112.  * 02-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  113.  *    Added some bullet-proofing code around hostname calls.
  114.  *
  115.  * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
  116.  *    Fixed for 4.3.
  117.  *
  118.  * 30-May-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  119.  *    Added code to use known values for well-known ports if they are
  120.  *    not found in the host table.
  121.  *
  122.  * 19-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  123.  *    Changed setsockopt SO_REUSEADDR to be non-fatal.  Added fourth
  124.  *    parameter as described in 4.3 manual entry.
  125.  *
  126.  * 15-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  127.  *    Added call of readflush() to requestend() routine.
  128.  *
  129.  * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  130.  *    Major rewrite for protocol version 4.  All read/write and crypt
  131.  *    routines are now in scmio.c.
  132.  *
  133.  * 14-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  134.  *    Added setsockopt SO_REUSEADDR call.
  135.  *
  136.  * 01-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  137.  *    Removed code to "gracefully" handle unexpected messages.  This
  138.  *    seems reasonable since it didn't work anyway, and should be
  139.  *    handled at a higher level anyway by adhering to protocol version
  140.  *    number conventions.
  141.  *
  142.  * 26-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  143.  *    Fixed scm.c to free space for remote host name when connection
  144.  *    is closed.
  145.  *
  146.  * 07-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  147.  *    Fixed 4.2 retry code to reload sin values before retry.
  148.  *
  149.  * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  150.  *    Added code to retry initial connection open request.
  151.  *
  152.  * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  153.  *    Merged 4.1 and 4.2 versions together.
  154.  *
  155.  * 21-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  156.  *    Add close() calls after pipe() call.
  157.  *
  158.  * 12-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  159.  *    Converted for 4.2 sockets; added serviceprep() routine.
  160.  *
  161.  * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  162.  *    Created for 4.2 BSD.
  163.  *
  164.  **********************************************************************
  165.  */
  166.  
  167. #include <libc.h>
  168. #include <errno.h>
  169. #include <sys/param.h>
  170. #include <sys/types.h>
  171. #include <sys/time.h>
  172. #include <sys/socket.h>
  173. #include <sys/ioctl.h>
  174. #include <netinet/in.h>
  175. #include <arpa/inet.h>
  176. #include <net/if.h>
  177. #include <netdb.h>
  178. #if __STDC__
  179. #include <stdarg.h>
  180. #else
  181. #include <varargs.h>
  182. #endif
  183. #ifdef _ABI_SOURCE
  184. #include <sys/utsname.h>
  185. #endif
  186. #include "sup.h"
  187.  
  188. #if __STDC__
  189. int scmerr (int, char *, ...);
  190. #endif
  191.  
  192. #ifndef INADDR_NONE
  193. #define    INADDR_NONE        0xffffffff        /* -1 return */
  194. #endif
  195. #ifndef INADDR_LOOPBACK
  196. #define    INADDR_LOOPBACK        (u_long)0x7f000001    /* 127.0.0.1 */
  197. #endif
  198.  
  199. extern int errno;
  200. static char *myhost ();
  201.  
  202. char scmversion[] = "4.3 BSD";
  203.  
  204. /*************************
  205.  ***    M A C R O S    ***
  206.  *************************/
  207.  
  208. /* networking parameters */
  209. #define NCONNECTS 5
  210.  
  211. /*********************************************
  212.  ***    G L O B A L   V A R I A B L E S    ***
  213.  *********************************************/
  214.  
  215. extern char program[];            /* name of program we are running */
  216. extern int progpid;            /* process id to display */
  217.  
  218. int netfile = -1;            /* network file descriptor */
  219.  
  220. static int sock = -1;            /* socket used to make connection */
  221. static struct in_addr remoteaddr;    /* remote host address */
  222. static char *remotename = NULL;        /* remote host name */
  223. static int swapmode;            /* byte-swapping needed on server? */
  224.  
  225. /***************************************************
  226.  ***    C O N N E C T I O N   R O U T I N E S    ***
  227.  ***    F O R   S E R V E R                      ***
  228.  ***************************************************/
  229.  
  230. servicesetup (server)        /* listen for clients */
  231. char *server;
  232. {
  233.     struct sockaddr_in sin;
  234.     struct servent *sp;
  235.     short port;
  236.     int one = 1;
  237.  
  238.     if (myhost () == NULL)
  239.         return (scmerr (-1,"Local hostname not known"));
  240.     if ((sp = getservbyname(server,"tcp")) == 0) {
  241.         if (strcmp(server, FILEPORT) == 0)
  242.             port = htons((u_short)FILEPORTNUM);
  243.         else if (strcmp(server, DEBUGFPORT) == 0)
  244.             port = htons((u_short)DEBUGFPORTNUM);
  245.         else
  246.             return (scmerr (-1,"Can't find %s server description",server));
  247.         (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
  248.                     server,port);
  249.     } else
  250.         port = sp->s_port;
  251.     endservent ();
  252.     sock = socket (AF_INET,SOCK_STREAM,0);
  253.     if (sock < 0)
  254.         return (scmerr (errno,"Can't create socket for connections"));
  255.     if (setsockopt (sock,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0)
  256.         (void) scmerr (errno,"Can't set SO_REUSEADDR socket option");
  257.     (void) bzero ((char *)&sin,sizeof(sin));
  258.     sin.sin_family = AF_INET;
  259.     sin.sin_port = port;
  260.     if (bind (sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
  261.         return (scmerr (errno,"Can't bind socket for connections"));
  262.     if (listen (sock,NCONNECTS) < 0)
  263.         return (scmerr (errno,"Can't listen on socket"));
  264.     return (SCMOK);
  265. }
  266.  
  267. service ()
  268. {
  269.     struct sockaddr_in from;
  270.     int x,len;
  271.  
  272.     remotename = NULL;
  273.     len = sizeof (from);
  274.     do {
  275.         netfile = accept (sock,(struct sockaddr *)&from,&len);
  276.     } while (netfile < 0 && errno == EINTR);
  277.     if (netfile < 0)
  278.         return (scmerr (errno,"Can't accept connections"));
  279.     remoteaddr = from.sin_addr;
  280.     if (read(netfile,(char *)&x,sizeof(int)) != sizeof(int))
  281.         return (scmerr (errno,"Can't transmit data on connection"));
  282.     if (x == 0x01020304)
  283.         swapmode = 0;
  284.     else if (x == 0x04030201)
  285.         swapmode = 1;
  286.     else
  287.         return (scmerr (-1,"Unexpected byteswap mode %x",x));
  288.     return (SCMOK);
  289. }
  290.  
  291. serviceprep ()        /* kill temp socket in daemon */
  292. {
  293.     if (sock >= 0) {
  294.         (void) close (sock);
  295.         sock = -1;
  296.     }
  297.     return (SCMOK);
  298. }
  299.  
  300. servicekill ()        /* kill net file in daemon's parent */
  301. {
  302.     if (netfile >= 0) {
  303.         (void) close (netfile);
  304.         netfile = -1;
  305.     }
  306.     if (remotename) {
  307.         free (remotename);
  308.         remotename = NULL;
  309.     }
  310.     return (SCMOK);
  311. }
  312.  
  313. serviceend ()        /* kill net file after use in daemon */
  314. {
  315.     if (netfile >= 0) {
  316.         (void) close (netfile);
  317.         netfile = -1;
  318.     }
  319.     if (remotename) {
  320.         free (remotename);
  321.         remotename = NULL;
  322.     }
  323.     return (SCMOK);
  324. }
  325.  
  326. /***************************************************
  327.  ***    C O N N E C T I O N   R O U T I N E S    ***
  328.  ***    F O R   C L I E N T                      ***
  329.  ***************************************************/
  330.  
  331. dobackoff (t,b)
  332. int *t,*b;
  333. {
  334.     struct timeval tt;
  335.     unsigned s;
  336.  
  337.     if (*t == 0)
  338.         return (0);
  339.     s = *b * 30;
  340.     if (gettimeofday (&tt,(struct timezone *)NULL) >= 0)
  341.         s += (tt.tv_usec >> 8) % s;
  342.     if (*b < 32) *b <<= 1;
  343.     if (*t != -1) {
  344.         if (s > *t)
  345.             s = *t;
  346.         *t -= s;
  347.     }
  348.     (void) scmerr (-1,"Will retry in %d seconds",s);
  349.     sleep (s);
  350.     return (1);
  351. }
  352.  
  353. request (server,hostname,retry)        /* connect to server */
  354. char *server;
  355. char *hostname;
  356. int *retry;
  357. {
  358.     int x, backoff;
  359.     struct hostent *h;
  360.     struct servent *sp;
  361.     struct sockaddr_in sin, tin;
  362.     short port;
  363.  
  364.     if ((sp = getservbyname(server,"tcp")) == 0) {
  365.         if (strcmp(server, FILEPORT) == 0)
  366.             port = htons((u_short)FILEPORTNUM);
  367.         else if (strcmp(server, DEBUGFPORT) == 0)
  368.             port = htons((u_short)DEBUGFPORTNUM);
  369.         else
  370.             return (scmerr (-1,"Can't find %s server description",
  371.                     server));
  372.         (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
  373.                     server,port);
  374.     } else
  375.         port = sp->s_port;
  376.     (void) bzero ((char *)&sin,sizeof(sin));
  377.     sin.sin_family = AF_INET;
  378.     sin.sin_addr.s_addr = inet_addr (hostname);
  379.     if (sin.sin_addr.s_addr == (u_long) INADDR_NONE) {
  380.         if ((h = gethostbyname (hostname)) == NULL)
  381.             return (scmerr (-1,"Can't find host entry for %s",
  382.                     hostname));
  383.         hostname = h->h_name;
  384.         (void) bcopy (h->h_addr,(char *)&sin.sin_addr,h->h_length);
  385.     }
  386.     sin.sin_port = port;
  387.     backoff = 1;
  388.     for (;;) {
  389.         netfile = socket (AF_INET,SOCK_STREAM,0);
  390.         if (netfile < 0)
  391.             return (scmerr (errno,"Can't create socket"));
  392.         tin = sin;
  393.         if (connect(netfile,(struct sockaddr *)&tin,sizeof(tin)) >= 0)
  394.             break;
  395.         (void) scmerr (errno,"Can't connect to server for %s",server);
  396.         (void) close(netfile);
  397.         if (!dobackoff (retry,&backoff))
  398.             return (SCMERR);
  399.     }
  400.     remoteaddr = sin.sin_addr;
  401.     remotename = salloc(hostname);
  402.     x = 0x01020304;
  403.     (void) write (netfile,(char *)&x,sizeof(int));
  404.     swapmode = 0;        /* swap only on server, not client */
  405.     return (SCMOK);
  406. }
  407.  
  408. requestend ()            /* end connection to server */
  409. {
  410.     (void) readflush ();
  411.     if (netfile >= 0) {
  412.         (void) close (netfile);
  413.         netfile = -1;
  414.     }
  415.     if (remotename) {
  416.         free (remotename);
  417.         remotename = NULL;
  418.     }
  419.     return (SCMOK);
  420. }
  421.  
  422. /*************************************************
  423.  ***    H O S T   N A M E   C H E C K I N G    ***
  424.  *************************************************/
  425.  
  426. static
  427. char *myhost ()        /* find my host name */
  428. {
  429.     struct hostent *h;
  430. #ifdef _ABI_SOURCE
  431.     static struct utsname name;
  432.  
  433.     if (*(name.nodename) == '\0') {
  434.         if (uname (&name) < 0)
  435.             return (NULL);
  436.         if ((h = gethostbyname (name.nodename)) == NULL)
  437.             return (NULL);
  438.         (void) strcpy (name.nodename,h->h_name);
  439.     }
  440.     return (name.nodename);
  441. #else
  442.     static char name[MAXHOSTNAMELEN];
  443.  
  444.     if (name[0] == '\0') {
  445.         if (gethostname (name,MAXHOSTNAMELEN) < 0)
  446.             return (NULL);
  447.         if ((h = gethostbyname (name)) == NULL)
  448.             return (NULL);
  449.         (void) strcpy (name,h->h_name);
  450.     }
  451.     return (name);
  452. #endif
  453. }
  454.  
  455. char *remotehost ()    /* remote host name (if known) */
  456. {
  457.     register struct hostent *h;
  458.  
  459.     if (remotename == NULL) {
  460.         h = gethostbyaddr ((char *)&remoteaddr,sizeof(remoteaddr),
  461.                     AF_INET);
  462.         remotename = salloc (h ? h->h_name : inet_ntoa(remoteaddr));
  463.         if (remotename == NULL)
  464.             return("UNKNOWN");
  465.     }
  466.     return (remotename);
  467. }
  468.  
  469. int thishost (host)
  470. register char *host;
  471. {
  472.     register struct hostent *h;
  473.     char *name;
  474.  
  475.     if ((name = myhost ()) == NULL)
  476.         logquit (1,"Can't find my host entry");
  477.     h = gethostbyname (host);
  478.     if (h == NULL) return (0);
  479.     return (strcasecmp (name,h->h_name) == 0);
  480. }
  481.  
  482. int samehost ()        /* is remote host same as local host? */
  483. {
  484.     static struct in_addr *intp;
  485.     static int nint = 0;
  486.     struct in_addr *ifp;
  487.     int n;
  488.  
  489.     if (nint <= 0) {
  490.         int s;
  491.         char buf[BUFSIZ];
  492.         struct ifconf ifc;
  493.         struct ifreq *ifr;
  494.         struct sockaddr_in sin;
  495.  
  496.         if ((s = socket (AF_INET,SOCK_DGRAM,0)) < 0)
  497.             logquit (1,"Can't create socket for SIOCGIFCONF");
  498.         ifc.ifc_len = sizeof(buf);
  499.         ifc.ifc_buf = buf;
  500.         if (ioctl (s,SIOCGIFCONF,(char *)&ifc) < 0)
  501.             logquit (1,"SIOCGIFCONF failed");
  502.         (void) close(s);
  503.         if ((nint = ifc.ifc_len/sizeof(struct ifreq)) <= 0)
  504.             return (0);
  505.         intp = (struct in_addr *)
  506.             malloc ((unsigned) nint*sizeof(struct in_addr));
  507.         if ((ifp = intp) == 0)
  508.             logquit (1,"no space for interfaces");
  509.         for (ifr = ifc.ifc_req, n = nint; n > 0; --n, ifr++) {
  510.             (void) bcopy ((char *)&ifr->ifr_addr,(char *)&sin,sizeof(sin));
  511.             *ifp++ = sin.sin_addr;
  512.         }
  513.     }
  514.     if (remoteaddr.s_addr == htonl(INADDR_LOOPBACK))
  515.         return (1);
  516.     for (ifp = intp, n = nint; n > 0; --n, ifp++)
  517.         if (remoteaddr.s_addr == ifp->s_addr)
  518.             return (1);
  519.     return (0);
  520. }
  521.  
  522. int matchhost (name)    /* is this name of remote host? */
  523. char *name;
  524. {
  525.     struct hostent *h;
  526.     struct in_addr addr;
  527.     char **ap;
  528.     if ((addr.s_addr = inet_addr(name)) != (u_long) INADDR_NONE)
  529.         return (addr.s_addr == remoteaddr.s_addr);
  530.     if ((h = gethostbyname (name)) == 0)
  531.         return (0);
  532.     if (h->h_addrtype != AF_INET || h->h_length != sizeof(struct in_addr))
  533.         return (0);
  534.     for (ap = h->h_addr_list; *ap; ap++)
  535.         if (bcmp ((char *)&remoteaddr,*ap,h->h_length) == 0)
  536.             return (1);
  537.     return (0);
  538. }
  539.  
  540. #if __STDC__
  541. int scmerr (int errno,char *fmt,...)
  542. #else
  543. /*VARARGS*//*ARGSUSED*/
  544. int scmerr (va_alist)
  545. va_dcl
  546. #endif
  547. {
  548. #if !__STDC__
  549.     int errno;
  550.     char *fmt;
  551. #endif
  552.     va_list ap;
  553.  
  554.     (void) fflush (stdout);
  555.     if (progpid > 0)
  556.         fprintf (stderr,"%s %d: ",program,progpid);
  557.     else
  558.         fprintf (stderr,"%s: ",program);
  559. #if __STDC__
  560.     va_start(ap,fmt);
  561. #else
  562.     va_start(ap);
  563.     errno = va_arg(ap,int);
  564.     fmt = va_arg(ap,char *);
  565. #endif
  566.     vfprintf(stderr, fmt, ap);
  567.     va_end(ap);
  568.     if (errno >= 0)
  569.         fprintf (stderr,": %s\n",errmsg(errno));
  570.     else
  571.         fprintf (stderr,"\n");
  572.     (void) fflush (stderr);
  573.     return (SCMERR);
  574. }
  575.  
  576. /*******************************************************
  577.  ***    I N T E G E R   B Y T E - S W A P P I N G    ***
  578.  *******************************************************/
  579.  
  580. union intchar {
  581.     int ui;
  582.     char uc[sizeof(int)];
  583. };
  584.  
  585. int byteswap (in)
  586. int in;
  587. {
  588.     union intchar x,y;
  589.     register int ix,iy;
  590.  
  591.     if (swapmode == 0)  return (in);
  592.     x.ui = in;
  593.     iy = sizeof(int);
  594.     for (ix=0; ix<sizeof(int); ix++) {
  595.         --iy;
  596.         y.uc[iy] = x.uc[ix];
  597.     }
  598.     return (y.ui);
  599. }
  600.