SMOLNET PORTAL home about changes
/********************************************************************
 * wilkinson
 * 3.19VMS
 * 1995/05/25 14:00
 * gopher_root1:[gopher.g2.vms2_13.object]Sockets.c,v
 * Exp
 *
 * Paul Lindner, University of Minnesota CIS.
 *
 * Copyright 1991, 1992 by the Regents of the University of Minnesota
 * see the file "Copyright" in the distribution for conditions of use.
 *********************************************************************
 * MODULE: Sockets.c
 * Socket functions
 *********************************************************************
 * Revision History:
 * Sockets.c,v
 * Revision 3.19VMS 1995/05/25 14:00    wilkinson
 * Consolodate VMS/Unix source code for server as well as client
 *
 * Revision 3.19  1994/07/31  05:09:47  lindner
 * Add option to log only IP
 *
 * Revision 3.18  1994/04/25  03:46:03  lindner
 * Fix for NETLIB and CMUIP
 *
 * Revision 3.17  1994/04/25  03:36:59  lindner
 * Modifications for Debug() and mismatched NULL arguments, added Debugmsg
 *
 * Revision 3.16  1994/04/08  20:05:53  lindner
 * gcc -Wall fixes
 *
 * Revision 3.15  1994/03/31  21:03:35  lindner
 * Use better, more descriptive return codes for socket routines
 *
 * Revision 3.14  1994/03/17  04:45:39  lindner
 * Add needed stdio.h
 *
 * Revision 3.13  1994/03/17  04:44:39  lindner
 * Add needed stdio.h
 *
 * Revision 3.12  1994/03/17  04:36:01  lindner
 * Move socket specific server code here, rearrange include files
 *
 * Revision 3.11  1994/03/08  15:56:20  lindner
 * gcc -Wall fixes
 *
 * Revision 3.10  1994/01/12  22:23:50  lindner
 * Fixes for Data General
 *
 * Revision 3.9  1993/12/27  16:16:03  lindner
 * Fix for sign on integer..
 *
 * Revision 3.8  1993/10/19  20:49:02  lindner
 * Fix for NETLIB
 *
 * Revision 3.7  1993/10/11  17:26:01  lindner
 * Fix for cmuip/netlib
 *
 * Revision 3.6  1993/09/21  01:51:34  lindner
 * Moved netnames fcn..
 *
 * Revision 3.5  1993/08/09  20:17:10  lindner
 * Fixes for CMULIB and NETLIB for VMS
 *
 * Revision 3.4  1993/08/05  03:23:37  lindner
 * Changes for CMUIP and NETLIB
 *
 * Revision 3.3  1993/07/29  20:01:02  lindner
 * Removed dead variables
 *
 * Revision 3.2  1993/07/27  05:30:27  lindner
 * Mondo Debug overhaul from Mitra
 *
 * Revision 3.1  1993/07/07  19:27:25  lindner
 * Socket functions
 *
 *
 *
 *********************************************************************/

/* Generic stuff */

#include "boolean.h"
#include "compatible.h"
#include "Debug.h"

#ifdef unix
#  include <sys/param.h>
#endif

#include "Sockets.h"
#include "Malloc.h"
#include <stdio.h>

#ifdef VMS_SERVER
#include <prvdef.h>
char * vms_errno_string();
#include <errno.h>
#include <ssdef.h>
#endif

/*
 * This turns the linger output off
 */

void
SOCKlinger(sockfd, onoff)
  int sockfd;
  boolean onoff;
{
#if defined(SO_LINGER) && !defined(NO_LINGER)
    struct linger linger;
     
    linger.l_onoff = onoff;
    linger.l_linger = 0;
    if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *)&linger,
		   sizeof (linger)) < 0)
#ifndef VMS_SERVER
	 perror("server: can't turn off linger sockopt"),exit(-1);
#else
	 LOGGopher(-99,"fatal: can't turn off linger sockopt, %s",
						vms_errno_string());
#endif
#endif
}



/*
 * This function returns a socket file descriptor bound to the given port
 */

#if !defined(CMUIP) && !defined(NETLIB)
int
SOCKbind_to_port(port) 
  int port;
{
    struct sockaddr_in serv_addr;
    int reuseaddr = 1;
    int sockfd;
#ifdef VMS_SERVER
    union prvdef prvadr;
    unsigned long int ON = -1;

    if (port<1024) {
	bzero((char *) &prvadr, sizeof(prvadr));
	prvadr.prv$v_sysprv = 1;
	if (SS$_NORMAL != (vaxc$errno = SYS$SETPRV (ON, &prvadr, 0, 0))) {
	      LOGGopher(-1,"Can't insure  SYSPRV for bind to port %d, %s", 
				port, STRerror(vaxc$errno));
	}
    }
#endif
    
    
    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
#ifndef VMS_SERVER
	 perror("server: can't open stream socket"), exit(-1);
#else
	 LOGGopher(-99,"fatal: can't open stream socket, %s",
						vms_errno_string());
#endif
    
    /** Bind our local address so that the client can send to us **/
    
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family 		= AF_INET;
    serv_addr.sin_addr.s_addr 	= htonl(INADDR_ANY);
    serv_addr.sin_port		= htons(port);
    
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr,
		   sizeof(reuseaddr)) < 0)
#ifndef VMS_SERVER
	  perror("server: can't set REUSEADDR!"),exit(-1);
#else
	  LOGGopher(-99,"fatal: can't set socket REUSEADDR, %s",
					vms_errno_string());
#endif
    
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0)
#ifndef VMS_SERVER
	 perror("server: can't bind local address"),exit(-1);
#else
	 LOGGopher(-99, "fatal: can't bind local address, %s",
				vms_errno_string());
#endif
    
    SOCKlinger(sockfd, FALSE);
#ifdef VMS_SERVER
    bzero((char *) &prvadr, sizeof(prvadr));
    prvadr.prv$v_sysprv = 1;
    if (SS$_NORMAL != (vaxc$errno = SYS$SETPRV (DEBUG, &prvadr, 0, 0))) {
	  LOGGopher(-1,"Can't discard PRIVS, %s", STRerror(vaxc$errno));
    }
#endif
    return(sockfd);
}



/*
 * This routine finds out the hostname of the server machine.
 * It uses a couple of methods to find the fully qualified 
 * Domain name
 *
 * If gdchost is non NULL then use that paramater instead of 
 * the code in here.
 */

char *
SOCKgetDNSname(backupdomain, gdchost)
  char *backupdomain;
  char *gdchost;
{
     static char DNSname[MAXHOSTNAMELEN];
     struct hostent *hp;

     if (*gdchost != '\0')
	  return(gdchost);

     DNSname[0] = '\0';
     /* Work out our fully-qualified name, for later use */
     
     if (gethostname(DNSname, MAXHOSTNAMELEN) != 0) {
#ifndef VMS_SERVER
	  fprintf(stderr, "Cannot determine the name of this host\n");
	  exit(-1);
#else
	  LOGGopher(-99,"fatal: Cannot determine the name of this host");
#endif
     }

     /* Now, use gethostbyname to (hopefully) do a nameserver lookup */
     hp = gethostbyname( DNSname);

     /*
      ** If we got something, and the name is longer than hostname, then
      ** assume that it must the the fully-qualified hostname
      */
     if ( hp!=NULL && strlen(hp->h_name) > strlen(DNSname) ) 
	  strncpy( DNSname, hp->h_name, MAXHOSTNAMELEN );
     else
	  strcat(DNSname, backupdomain);

     return(DNSname);
}


/*
 * Tries to figure out what the currently connected port is.
 * 
 * If it's a socket then it will return the port of the socket, 
 * if it isn't a socket then it returns -1.
 */

int 
SOCKgetPort(fd)
  int fd;
{
     struct sockaddr_in serv_addr;

     int length = sizeof(serv_addr);
     
     /** Try to figure out the port we're running on. **/
     
     if (getsockname(fd, (struct sockaddr *) &serv_addr,&length) == 0)
	  return(ntohs(serv_addr.sin_port));
     else
	  return(-1);

}

#endif /* not CMUIP nor NETLIB */



/* SOCKconnect performs a connection to socket 'service' on host
 * 'host'.  Host can be a hostname or ip-address.  If 'host' is null, the
 * local host is assumed.   The parameter full_hostname will, on return,
 * contain the expanded hostname (if possible).  Note that full_hostname is a
 * pointer to a char *, and is allocated by connect_to_gopher()
 *
 * Errors: ErrSocket* defined in Sockets.h
 *
 */

int
SOCKconnect(hostname, port)
  char *hostname;
  int port;
{
#if !defined(CMUIP) && !defined(NETLIB)
     struct sockaddr_in Server;
     struct hostent *HostPtr;
     int sockfd = 0;
     unsigned int ERRinet = -1;

#ifdef _CRAY
     ERRinet = 0xFFFFFFFF;  /* -1 doesn't sign extend on 64 bit machines */
#endif

     /*** Find the hostname address ***/
     
     if (hostname == NULL || *hostname == '\0')
	  return(ErrSocketNullHost);

#ifdef DGUX
     Server.sin_addr = inet_addr(hostname);
     if (Server.sin_addr.s_addr == ERRinet)
#else
     if ((Server.sin_addr.s_addr = inet_addr(hostname)) == ERRinet)
#endif
     {
	  if ((HostPtr = gethostbyname(hostname)) != NULL) {
	       bzero((char *) &Server, sizeof(Server));
	       bcopy(HostPtr->h_addr, (char *) &Server.sin_addr, HostPtr->h_length);
	       Server.sin_family = HostPtr->h_addrtype;
	  } else
	       return (ErrSocketGetHost);
     } else
	  Server.sin_family = AF_INET;

     Server.sin_port = (unsigned short) htons(port);

     /*** Open the socket ***/

     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	  return (ErrSocketCall);

#ifndef UCX
     setsockopt(sockfd, SOL_SOCKET, ~SO_LINGER, 0, 0);
#endif

     setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0);
     setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, 0, 0);

     /*** Connect ***/

     if (connect(sockfd, (struct sockaddr *) &Server, sizeof(Server)) < 0) {
	  closenet(sockfd);
	  return (ErrSocketConnect);
     }

     return(sockfd);

#else /* !NETLIB && !CMUIP */
#ifdef NETLIB
     int status;
     static int iSock = 0;
     struct {
          long len;
          char *adr;
     } host_desc;

#define NET_K_TCP 1
     status = NET_ASSIGN (&iSock);
     if ((status & 1) == 0)
          return (ErrSocketCall);
     status = NET_BIND (&iSock, NET_K_TCP);
     if ((status & 1) == 0)
          return (ErrSocketCall);
     host_desc.adr = hostname;
     host_desc.len = strlen (host_desc.adr);
     status = TCP_CONNECT (&iSock, &host_desc, port);
     if ((status & 1) == 0) {
          NET_DEASSIGN (&iSock);
          if (status == SS$_REJECT || status == SS$_TIMEOUT) {
	       if (status == SS$_REJECT)
		    errno = ECONNREFUSED;
	       else
		    errno = ETIMEDOUT;
	       
	       return (ErrSocketConnect);
	  }
	  if (status == SS$_ENDOFFILE)
	       return (ErrSocketGetHost);
          return (ErrSocketGetService);
     }
     return (iSock);
#else /* ifdef NETLIB:  assume CMUIP */
     short channel;
     int status;
     struct {
          short status;
          short size;
          long xxx;
     } cmu_iosb;
     static struct {long l; char *a;} ip_dev = {12, "INET$DEVICE:"};
     globalvalue NET$_CREF;           /* Connection refused */
     globalvalue NET$_FTO;            /* Function timedout */
     globalvalue NET$_DSNAMERR;       /* Domain server name error */
     status = SYS$ASSIGN (&ip_dev, &channel, 0, 0);
     if ((status & 1) == 0)
          return (ErrSocketCall);
     status = SYS$QIOW (0, channel, IO$_CREATE, &cmu_iosb, 0, 0,
          hostname, port, 0, 1, 0, 0);
     if ((status & 1) == 0 || (cmu_iosb.status & 1) == 0) {
          SYS$DASSGN (channel);
          if (cmu_iosb.status == SS$_ABORT || cmu_iosb.xxx == NET$_FTO) {
               if (cmu_iosb.xxx == NET$_CREF)
		    errno = ECONNREFUSED;
	       else
		    errno = ETIMEDOUT;

	       return(ErrSocketConnect);
	  }
	  if (cmu_iosb.xxx == NET$_DSNAMERR)
	       return (ErrSocketGetHost);
     }
     return (channel);
#endif
#endif

}




/*
 *
 */

#if !defined(CMUIP) && !defined(NETLIB)         /* temp - MLH */ 
int
SOCKlisten(We)
  struct sockaddr_in *	We;
{
     int             sockfd = 0;
     struct hostent *HostPtr;
     int             len = sizeof(struct sockaddr);
     char            name[100];


     sockfd = SOCKbind_to_port(sockfd);
     if (listen(sockfd, 5) || getsockname(sockfd, (struct sockaddr *) We, &len)) {
          closenet(sockfd);
          return(ErrSocketGetHost);
     }
     
     gethostname(name, 100);
     if ((HostPtr = gethostbyname(name)))
          bcopy(HostPtr->h_addr, (char *) &We->sin_addr, HostPtr->h_length);
     return(sockfd);
}


/* SOCKaccept accepts a connection form some socket. *
 * Errors: ErrSocket* defined in Sockets.h
 */

int
SOCKaccept(s, we)
  int s;
  struct sockaddr_in we;
{
     int            sockfd    = 0;
     int            len       = sizeof(struct sockaddr);
     unsigned short tem;

     tem = ntohs(we.sin_port);

     Debugmsg("Here we go...\n");

     if ((sockfd = accept(s, (struct sockaddr *) &we, &len)) < 0) {
	  return ErrSocketConnect;
     }
     close(s); /* Der Mohr hat seine Schuldigkeit getan */

     return(sockfd);
}



/*
 * SOCKnetnames -- return the network, subnet, and host names of
 * our peer process for the Internet domain.
 *
 *      Parameters:     "sock" is our socket
 *                      "host_name"
 *                      is filled in by this routine with the
 *                      corresponding ASCII names of our peer.
 *       
 *                      if there doesn't exist a hostname in DNS etal,
 *                      the IP# will be inserted for the host_name
 *
 *                      "ipnum" is filled in with the ascii IP#
 */

void
SOCKnetnames(sockfd, host_name, ipnum)
  int  sockfd;
  char *host_name;
  char *ipnum;
{
     struct sockaddr_in      sa;
     int                     length;
     struct hostent          *hp;

     length = sizeof(sa);
     if (getpeername(sockfd, (struct sockaddr *)&sa, &length))
	  /** May fail if sockfd has been closed **/
#ifdef VMS_SERVER
     {
          LOGGopher(-2, "getpeername() failure: %s", vms_errno_string());
	  if (ipnum != NULL)
	    strcpy(ipnum,"Unknown");
	  if (host_name != NULL)
	    strcpy(host_name,"Unknown");
          return;
      }

#else
	  return;
#endif

     if (ipnum != NULL)
	  strcpy(ipnum, inet_ntoa(sa.sin_addr));

     if (host_name != NULL)
	  strcpy(host_name, inet_ntoa(sa.sin_addr));

#ifdef LOG_IP_ONLY
     hp = NULL;
#else
     hp = gethostbyaddr((char *) &sa.sin_addr,sizeof (sa.sin_addr), AF_INET);
#endif

     if (hp != NULL && host_name != NULL)
	  (void) strcpy(host_name, hp->h_name);

}

#endif  /** CMUIP etal **/

#if defined(VMS_SERVER) && defined(MULTINET)
/*
 * This turns the keepalive option on
 *	TGV recommended setting KEEPALIVE on the server, just in case
 *	    we somehow got a socket locked in a CLOSE_WAIT state (shouldn't
 *	    happen since we set REUSEADDR *before* we bind, but... it's
 *	    sure a lot better than rebooting your VAX/AXP node to get the
 *	    port back from a %MULTINET-F-EADDRINUSE error condition).
 */
void
SOCKkeepalive(sockfd, onoff)
  int sockfd;
  boolean onoff;
{
#if defined(SO_KEEPALIVE) && !defined(NO_KEEPALIVE)
    int keepalive = onoff;
    if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
		   sizeof (keepalive)) < 0)
	 LOGGopher(-1,"warning: can't turn %s keepalive sockopt, %s",
				onoff?"on":"off", vms_errno_string());
#endif
}
#endif
.
Response: text/plain
Original URLgopher://bitreich.org/0/gopher2007/2007-gopher-mirror/gop...
Content-Typetext/plain; charset=utf-8