home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
jËzyki_programowania
/
clisp
/
src
/
archive
/
clisp.src.lha
/
src
/
socket.d
< prev
next >
Wrap
Text File
|
1996-04-15
|
17KB
|
536 lines
# Setting up a connection to an X server
# Bruno Haible 19.6.1994
# Marcus Daniels 28.9.1995
# This code comes from the X11R5 distribution, file mit/X/XConnDis.c,
# with the following modifications:
# - no support for DNETCONN or STREAMSCONN,
# - display name has already been split into hostname and display number,
# - doesn't return full host&display name and auth info,
# - doesn't depend on the X include files.
# mit/X/XConnDis.c carries the following copyright notice:
/*
* $XConsortium: XConnDis.c,v 11.85 91/07/19 23:07:39 gildea Exp $
*
* Copyright 1989 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission. M.I.T. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*
* This file contains operating system dependencies.
*/
# These are the only things we need from lispbibl.c :
#include "config.h"
#define global
#define local static
#define var
# We assume that if we have gethostbyname(), we have a networking Unix.
# and have either UNIX domain connections or TCP/IP connections.
#ifdef HAVE_GETHOSTBYNAME
#ifdef HAVE_SYS_UN_H # have <sys/un.h> and Unix domain sockets?
#define UNIXCONN # use Unix domain sockets
#endif
#ifdef HAVE_NETINET_IN_H # have <netinet/in.h> ?
#define TCPCONN # use TCP/IP sockets
#endif
#ifdef TCPCONN
#define SOCKET_STREAMS
#endif
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> # declares fcntl(), close(), sleep()
#endif
#ifdef HAVE_MEMSET
#include <string.h>
extern void* memset (void* ptr, int c, size_t len); # siehe MEMORY(3)
#define bzero(ptr,len) memset(ptr,0,len)
#define bcopy(source,dest,len) memcpy(dest,source,len)
#else
extern void bzero (void* ptr, int len); # siehe BZERO(3)
extern void bcopy (void *source, void *dest, int len);
#endif
#include <errno.h>
extern int errno;
#ifndef ENOSYS
#define ENOSYS EINVAL
#endif
#include <fcntl.h> # declares fcntl() and defines F_SETFD
#ifdef FCNTL_DOTS
extern int fcntl (int fd, int cmd, ...);
#else
extern int fcntl (int fd, int cmd, int arg);
#endif
#ifndef FD_CLOEXEC
#define FD_CLOEXEC 1
#endif
extern int close (int fd);
#define CLOSE(fd) while ((close(fd) < 0) && (errno == EINTR)) ;
#ifdef __CYGWIN32__
struct servent *cygwin32_getservbyport(int port,const char *proto) { abort(); }
unsigned short ntohs(unsigned short netshort) { abort(); }
#endif
#if defined(UNIXCONN) || defined(TCPCONN)
# include <sys/types.h>
#include <sys/socket.h> # declares socket(), connect(), defines AF_UNIX, AF_INET
extern int socket (int domain, int type, int protocol);
extern int connect (int fd, CONNECT_CONST CONNECT_NAME_T name, int namelen);
# A wrapper around the connect() function.
global int nonintr_connect (int fd, struct sockaddr * name, int namelen);
global int nonintr_connect(fd,name,namelen)
var int fd;
var struct sockaddr * name;
var int namelen;
{ var int retval;
do { retval = connect(fd,name,namelen); }
while ((retval < 0) && (errno == EINTR));
return retval;
}
#define connect nonintr_connect
extern unsigned int sleep (unsigned int seconds);
#endif
#ifdef UNIXCONN
#include <stdio.h> # declares sprintf()
#include <string.h> # declares strcmp(), strlen()
#ifdef RETSTRLENTYPE /* unless strlen() is a macro */
extern RETSTRLENTYPE strlen (STRLEN_CONST char* s);
#endif
#include <sys/un.h> # defines struct sockaddr_un
# set X_UNIX_PATH and - on hpux only - OLD_UNIX_PATH
#ifndef X_UNIX_PATH
#ifndef hpux
#define X_UNIX_PATH "/tmp/.X11-unix/X"
#else
#define X_UNIX_PATH "/usr/spool/sockets/X11/"
#define OLD_UNIX_PATH "/tmp/.X11-unix/X"
#endif
#endif
#endif
#ifdef TCPCONN
#ifdef HAVE_GETHOSTNAME
extern int gethostname (char* name, GETHOSTNAME_SIZE_T namelen);
#endif
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
extern int uname (struct utsname * buf);
#endif
#ifdef HAVE_GETHOSTBYNAME
#include <sys/types.h>
#ifdef HAVE_NETDB_H
# include <sys/socket.h>
#include <netdb.h>
#else
#include <sun/netdb.h>
#endif
extern struct hostent * gethostbyname (GETHOSTBYNAME_CONST char* name);
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#include <netinet/in.h> # declares htons(), defines struct sockaddr_in
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h> # declares inet_addr()
#endif
extern RET_INET_ADDR_TYPE inet_addr (INET_ADDR_CONST char* host);
#ifdef HAVE_NETINET_TCP_H
#include <netinet/in_systm.h>
#if defined(__386BSD__) || defined(__NetBSD__)
#include <machine/endian.h> # needed for <netinet/tcp.h>
#endif
#include <netinet/tcp.h> # declares TCP_NODELAY
#endif
extern int setsockopt (/* int fd, int level, int optname, char* optval, int optlen */);
#define X_TCP_PORT 6000 # from <X11/Xproto.h>
#endif
# Attempts to connect to server, given host name and display number.
# Returns file descriptor (network socket). Returns -1 and sets errbo
# if connection fails.
# An empty hostname is interpreted as the most efficient local connection to
# a server on the same machine (usually a UNIX domain socket).
# hostname="unix" is interpreted as a UNIX domain connection.
global int connect_to_server (char* host, int display);
global int connect_to_server(host,display)
var char* host; # host of display
var int display; # display number (screen number always zero)
{ var int fd; # file descriptor to return
var int retries = 3; # number of retries on ECONNREFUSED
var int conntype; # type of desired connection
#define conn_none 0
#define conn_unix 1
#define conn_tcp 2
#ifdef TCPCONN
conntype = conn_tcp;
#else
conntype = conn_none;
#endif
#ifdef UNIXCONN
if (host[0] == '\0')
{
#ifndef apollo # Unix domain sockets are *really* bad on apollos
conntype = conn_unix;
#endif
}
else if (strcmp(host,"unix")==0)
{ conntype = conn_unix; }
#endif
# Make the connection. Do retries in case server host has hit its
# backlog (which, unfortunately, isn't distinguishable from there not
# being a server listening at all, which is why we have to not retry
# too many times).
#ifdef UNIXCONN
if (conntype == conn_unix)
{
var struct sockaddr_un unaddr; # UNIX socket data block
var struct sockaddr * addr; # generic socket pointer
var int addrlen; # length of addr
#ifdef hpux /* this is disgusting */
var struct sockaddr_un ounaddr; # UNIX socket data block
var struct sockaddr * oaddr; # generic socket pointer
var int oaddrlen; # length of addr
#endif
unaddr.sun_family = AF_UNIX;
sprintf (unaddr.sun_path, "%s%d", X_UNIX_PATH, display);
addr = (struct sockaddr *) &unaddr;
#ifdef HAVE_SOCKADDR_UN_LEN /* this is AIX */
unaddr.sun_len = strlen(unaddr.sun_path); addrlen = sizeof(unaddr);
#else
addrlen = strlen(unaddr.sun_path) + sizeof(unaddr.sun_family);
#endif
#ifdef hpux /* this is disgusting */
ounaddr.sun_family = AF_UNIX;
sprintf (ounaddr.sun_path, "%s%d", OLD_UNIX_PATH, display);
oaddr = (struct sockaddr *) &ounaddr;
#ifdef HAVE_SOCKADDR_UN_LEN /* this is AIX */
ounaddr.sun_len = strlen(ounaddr.sun_path); oaddrlen = sizeof(ounaddr);
#else
oaddrlen = strlen(ounaddr.sun_path) + sizeof(ounaddr.sun_family);
#endif
#endif
# Open the network connection.
do { if ((fd = socket((int) addr->sa_family, SOCK_STREAM, 0)) >= 0)
{ if (connect (fd, addr, addrlen) >= 0)
break;
else
{ int olderrno = errno; CLOSE(fd); errno = olderrno; }
}
#ifdef hpux /* this is disgusting */
if (errno == ENOENT)
{ if ((fd = socket((int) oaddr->sa_family, SOCK_STREAM, 0)) >= 0)
{ if (connect (fd, oaddr, oaddrlen) >= 0)
break;
else
{ int olderrno = errno; CLOSE(fd); errno = olderrno; }
} }
#endif
if (!((errno == ENOENT) && (retries > 0)))
{ return -1; }
sleep (1);
}
while (retries-- > 0);
}
else
#endif
#ifdef TCPCONN
if (conntype == conn_tcp)
{
#if defined(HAVE_GETHOSTNAME)
var char hostname[MAXHOSTNAMELEN+1];
#elif defined(HAVE_SYS_UTSNAME_H)
var struct utsname utsname;
#endif
var unsigned long hostinetaddr; # result of inet_addr of arpa addr
var struct sockaddr_in inaddr; # IP socket
var struct sockaddr * addr; # generic socket pointer
var int addrlen; # length of addr
if (host[0] == '\0')
{ # get host name
#if defined(HAVE_GETHOSTNAME)
if (gethostname(&!hostname,MAXHOSTNAMELEN) < 0) { return -1; }
hostname[MAXHOSTNAMELEN] = '\0';
host = &!hostname;
#elif defined(HAVE_SYS_UTSNAME_H)
if (uname(&utsname) < 0) { return -1; }
host = &!utsname.nodename;
#else
??
#endif
}
# if numeric host name then try to parse it as such; do the number
# first because some systems return garbage instead of INVALID_INETADDR
#define INVALID_INETADDR ((unsigned long) -1)
if ((host[0] >= '0') && (host[0] <= '9'))
{ hostinetaddr = inet_addr(host) INET_ADDR_SUFFIX ; }
else
{ hostinetaddr = INVALID_INETADDR; }
# try numeric
if (hostinetaddr == INVALID_INETADDR)
{ var struct hostent * host_ptr; # entry in hosts table
if ((host_ptr = gethostbyname(host)) == NULL)
{ errno = EINVAL; return -1; } # No such host!
# Check the address type for an internet host.
if (host_ptr->h_addrtype != AF_INET)
{ errno = EPROTOTYPE; return -1; } # Not an Internet host!
# Set up the socket data.
inaddr.sin_family = host_ptr->h_addrtype;
inaddr.sin_addr = *(struct in_addr *)host_ptr->h_addr;
}
else
{ inaddr.sin_family = AF_INET;
inaddr.sin_addr.s_addr = hostinetaddr;
}
inaddr.sin_port = X_TCP_PORT + display;
inaddr.sin_port = htons(inaddr.sin_port);
addr = (struct sockaddr *) &inaddr;
addrlen = sizeof(struct sockaddr_in);
# Open the network connection.
do { if ((fd = socket ((int) addr->sa_family, SOCK_STREAM, 0)) < 0)
{ return -1; }
#ifdef TCP_NODELAY
# turn off TCP coalescence
{ int tmp = 1;
setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(int));
}
#endif
# Connect to the socket.
# If there is no X server or if the backlog has been reached,
# then ECONNREFUSED will be returned.
if (connect (fd, addr, addrlen) >= 0)
break;
{ int olderrno = errno; CLOSE(fd); errno = olderrno; }
if (!(
#ifdef ECONNREFUSED
(errno == ECONNREFUSED) &&
#endif
(retries > 0)))
{ return -1; }
sleep (1);
}
while (retries-- > 0);
}
else
#endif
# (conntype == conn_none)
{ errno = ENOSYS; return -1; }
# Set close-on-exec so that we won't get confused if we fork().
fcntl(fd,F_SETFD,FD_CLOEXEC);
return fd;
}
#endif # HAVE_GETHOSTBYNAME
#if defined(SOCKET_STREAMS)
# Creation of sockets on the server side:
# int socket_handle = create_server_socket(port);
# creates a socket to which other processes can connect.
# int fd = accept_connection(socket_handle);
# waits for a connection to another process.
# This can (and should) be done multiple times for the same
# socket_handle.
global int create_server_socket (int port);
global int create_server_socket(port)
var int port;
{
var struct sockaddr_in sa ;
var int s;
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
bzero((char *) &sa, sizeof(sa)) ;
sa.sin_family = AF_INET ;
sa.sin_addr.s_addr = htonl(INADDR_ANY) ;
sa.sin_port = htons(port) ;
if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
return -1 ;
if (listen(s, 1) < 0)
return -1;
return s ;
}
global int accept_connection (int socket_handle);
global int accept_connection (socket_handle)
var int socket_handle;
{
var struct sockaddr_in sa;
var int active_socket;
var int alen;
alen = sizeof(sa);
return accept(socket_handle,(struct sockaddr *)&sa,&alen);
}
# Creation of sockets on the client side:
# int fd = create_client_socket(hostname,port);
# creates a connection to a server (which must be waiting
# on the specified host and port).
global int create_client_socket (char *hostname, int port);
global int create_client_socket(hostname,port)
var char *hostname;
var int port;
{
var struct sockaddr_in sa;
var struct hostent *hp;
var int a;
var int s;
var long addr;
bzero(&sa, sizeof(sa));
if ((addr = inet_addr(hostname)) != -1)
{
# is Internet addr in octet notation
bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; # set address
sa.sin_family = AF_INET;
}
else
{
if ((hp = gethostbyname(hostname)) == NULL)
return -2;
bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length);
sa.sin_family = hp->h_addrtype;
}
sa.sin_port = htons((u_short) port);
if ((s = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
return -1;
if (connect(s, (CONNECT_CONST CONNECT_NAME_T)&sa, sizeof(sa)) < 0)
{ close(s);
return -1;
}
return s;
}
# Auxiliary function:
# port = resolve_service("name_or_number",&name);
# parses the "name_or_number" and returns data about the
# specified TCP service: its name and its port number.
local int is_number (char *s);
local int is_number(s)
var char *s;
{
while (*s)
{
if (*s < '0' || *s > '9')
return 0 ;
s++ ;
}
return 1 ;
}
global int resolve_service (char *name_or_number, char **name);
global int resolve_service (name_or_number,name)
char *name_or_number ;
char **name ;
{
struct servent *servent ;
int port;
extern int atoi();
if (is_number(name_or_number))
{ port = atoi(name_or_number);
if (name != NULL)
{ servent = getservbyport(htons(port), "tcp");
if (servent != NULL)
*name = servent->s_name;
else
*name = NULL;
}
return port;
}
else
{
servent = getservbyname(name_or_number, "tcp");
if (servent == NULL)
return -1;
if (name != NULL)
*name = servent->s_name;
return ntohs(servent->s_port);
}
}
# Auxiliary function:
# socket_getpeername(fd)
# returns the name of the host to which IP socket fd is connected.
# Return value: A pointer to a statically allocated string!
global char *socket_getpeername (int socket_handle);
global char *socket_getpeername(socket_handle)
var int socket_handle;
{
var struct hostent *hostent;
var struct sockaddr_in addr_in;
var int len=sizeof(addr_in);
var long norder;
# Get host's IP address.
if (getpeername(socket_handle,&addr_in,&len) == -1) return NULL;
norder = htonl(addr_in.sin_addr.s_addr) ;
# Convert it to an ASCII host name.
hostent=gethostbyaddr(&norder,sizeof(norder),AF_INET);
if (hostent == NULL)
{
static char dotted[20] ;
sprintf(dotted, "%d.%d.%d.%d",
(norder >> 24) & 0xff,
(norder >> 16) & 0xff,
(norder >> 8) & 0xff,
norder & 0xff) ;
return dotted;
}
return hostent->h_name;
}
#endif # SOCKET_STREAMS