You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1344 lines
29 KiB
1344 lines
29 KiB
/* $TOG: Xtrans.c /main/34 1998/02/06 15:55:15 kaleb $ */
|
|
/*
|
|
|
|
Copyright 1993, 1994, 1998 The Open Group
|
|
|
|
All Rights Reserved.
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
other dealings in this Software without prior written authorization
|
|
from The Open Group.
|
|
|
|
*/
|
|
/* $XFree86: xc/lib/xtrans/Xtrans.c,v 3.22 1999/12/27 00:39:28 robin Exp $ */
|
|
|
|
/* Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* 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 NCR not be used in advertising
|
|
* or publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. NCR makes no representations about the
|
|
* suitability of this software for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*
|
|
* NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
* NO EVENT SHALL NCR 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.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#ifdef _AIX
|
|
extern char *strpbrk(const char *, const char *);
|
|
extern char *strchr(const char *, int);
|
|
#endif
|
|
|
|
/*
|
|
* The transport table tqcontains a definition for every transport (protocol)
|
|
* family. All operations that can be made on the transport go through this
|
|
* table.
|
|
*
|
|
* Each transport is assigned a unique transport id.
|
|
*
|
|
* New transports can be added by adding an entry in this table.
|
|
* For compatibility, the transport ids should never be renumbered.
|
|
* Always add to the end of the list.
|
|
*/
|
|
|
|
#define TRANS_TLI_INET_INDEX 1
|
|
#define TRANS_TLI_TCP_INDEX 2
|
|
#define TRANS_TLI_TLI_INDEX 3
|
|
#define TRANS_SOCKET_UNIX_INDEX 4
|
|
#define TRANS_SOCKET_LOCAL_INDEX 5
|
|
#define TRANS_SOCKET_INET_INDEX 6
|
|
#define TRANS_SOCKET_TCP_INDEX 7
|
|
#define TRANS_DNET_INDEX 8
|
|
#define TRANS_LOCAL_LOCAL_INDEX 9
|
|
#define TRANS_LOCAL_PTS_INDEX 10
|
|
#define TRANS_LOCAL_NAMED_INDEX 11
|
|
#define TRANS_LOCAL_ISC_INDEX 12
|
|
#define TRANS_LOCAL_SCO_INDEX 13
|
|
#define TRANS_AMOEBA_INDEX 14
|
|
#define TRANS_MNX_INET_INDEX 15
|
|
#define TRANS_MNX_TCP_INDEX 16
|
|
|
|
|
|
static
|
|
Xtransport_table Xtransports[] = {
|
|
#if defined(STREAMSCONN)
|
|
{ &TRANS(TLITCPFuncs), TRANS_TLI_TCP_INDEX },
|
|
{ &TRANS(TLIINETFuncs), TRANS_TLI_INET_INDEX },
|
|
{ &TRANS(TLITLIFuncs), TRANS_TLI_TLI_INDEX },
|
|
#endif /* STREAMSCONN */
|
|
#if defined(TCPCONN)
|
|
{ &TRANS(SocketTCPFuncs), TRANS_SOCKET_TCP_INDEX },
|
|
{ &TRANS(SocketINETFuncs), TRANS_SOCKET_INET_INDEX },
|
|
#endif /* TCPCONN */
|
|
#if defined(DNETCONN)
|
|
{ &TRANS(DNETFuncs), TRANS_DNET_INDEX },
|
|
#endif /* DNETCONN */
|
|
#if defined(UNIXCONN)
|
|
#if !defined(LOCALCONN)
|
|
{ &TRANS(SocketLocalFuncs), TRANS_SOCKET_LOCAL_INDEX },
|
|
#endif /* !LOCALCONN */
|
|
{ &TRANS(SocketUNIXFuncs), TRANS_SOCKET_UNIX_INDEX },
|
|
#endif /* UNIXCONN */
|
|
#if defined(OS2PIPECONN)
|
|
{ &TRANS(OS2LocalFuncs), TRANS_LOCAL_LOCAL_INDEX },
|
|
#endif /* OS2PIPECONN */
|
|
#if defined(LOCALCONN)
|
|
{ &TRANS(LocalFuncs), TRANS_LOCAL_LOCAL_INDEX },
|
|
#ifndef sun
|
|
{ &TRANS(PTSFuncs), TRANS_LOCAL_PTS_INDEX },
|
|
#endif /* sun */
|
|
#ifdef SVR4
|
|
{ &TRANS(NAMEDFuncs), TRANS_LOCAL_NAMED_INDEX },
|
|
#endif
|
|
#ifndef sun
|
|
{ &TRANS(ISCFuncs), TRANS_LOCAL_ISC_INDEX },
|
|
{ &TRANS(SCOFuncs), TRANS_LOCAL_SCO_INDEX },
|
|
#endif /* sun */
|
|
#endif /* LOCALCONN */
|
|
#if defined(AMRPCCONN) || defined(AMTCPCONN)
|
|
{ &TRANS(AmConnFuncs), TRANS_AMOEBA_INDEX },
|
|
#endif /* AMRPCCONN || AMTCPCONN */
|
|
#if defined(MNX_TCPCONN)
|
|
{ &TRANS(MnxINETFuncs), TRANS_MNX_INET_INDEX },
|
|
{ &TRANS(MnxTCPFuncs), TRANS_MNX_TCP_INDEX },
|
|
#endif /* MNX_TCPCONN */
|
|
};
|
|
|
|
#define NUMTRANS (sizeof(Xtransports)/sizeof(Xtransport_table))
|
|
|
|
|
|
#ifdef _WIN32
|
|
#define ioctl ioctlsocket
|
|
#endif
|
|
|
|
|
|
/*
|
|
* These are a few utility function used by the public interface functions.
|
|
*/
|
|
|
|
void
|
|
TRANS(FreeConnInfo) (XtransConnInfo ciptr)
|
|
|
|
{
|
|
PRMSG (3,"FreeConnInfo(%x)\n", ciptr, 0, 0);
|
|
|
|
if (ciptr->addr)
|
|
xfree (ciptr->addr);
|
|
|
|
if (ciptr->peeraddr)
|
|
xfree (ciptr->peeraddr);
|
|
|
|
if (ciptr->port)
|
|
xfree (ciptr->port);
|
|
|
|
xfree ((char *) ciptr);
|
|
}
|
|
|
|
|
|
#define PROTOBUFSIZE 20
|
|
|
|
static Xtransport *
|
|
TRANS(SelectTransport) (char *protocol)
|
|
|
|
{
|
|
char protobuf[PROTOBUFSIZE];
|
|
int i;
|
|
|
|
PRMSG (3,"SelectTransport(%s)\n", protocol, 0, 0);
|
|
|
|
/*
|
|
* Force Protocol to be lowercase as a way of doing
|
|
* a case insensitive match.
|
|
*/
|
|
|
|
strncpy (protobuf, protocol, PROTOBUFSIZE - 1);
|
|
protobuf[PROTOBUFSIZE-1] = '\0';
|
|
|
|
for (i = 0; i < PROTOBUFSIZE && protobuf[i] != '\0'; i++)
|
|
if (isupper (protobuf[i]))
|
|
protobuf[i] = tolower (protobuf[i]);
|
|
|
|
/* Look at all of the configured protocols */
|
|
|
|
for (i = 0; i < (int) NUMTRANS; i++)
|
|
{
|
|
if (!strcmp (protobuf, Xtransports[i].transport->TransName))
|
|
return Xtransports[i].transport;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef TEST_t
|
|
static
|
|
#endif /* TEST_t */
|
|
int
|
|
TRANS(ParseAddress) (char *address, char **protocol, char **host, char **port)
|
|
|
|
{
|
|
/*
|
|
* For the font library, the address is a string formatted
|
|
* as "protocol/host:port[/catalog]". Note that the catalog
|
|
* is optional. At this time, the catalog info is ignored, but
|
|
* we have to parse it anyways.
|
|
*
|
|
* Other than fontlib, the address is a string formatted
|
|
* as "protocol/host:port".
|
|
*
|
|
* If the protocol part is missing, then assume INET.
|
|
* If the protocol part and host part are missing, then assume local.
|
|
*/
|
|
|
|
char *mybuf, *tmpptr;
|
|
char *_protocol, *_host, *_port;
|
|
char hostnamebuf[256];
|
|
|
|
PRMSG (3,"ParseAddress(%s)\n", address, 0, 0);
|
|
|
|
/* Copy the string so it can be changed */
|
|
|
|
tmpptr = mybuf = (char *) xalloc (strlen (address) + 1);
|
|
strcpy (mybuf, address);
|
|
|
|
/* Parse the string to get each component */
|
|
|
|
/* Get the protocol part */
|
|
|
|
_protocol = mybuf;
|
|
|
|
|
|
if ( ((mybuf = strchr (mybuf,'/')) == NULL) &&
|
|
((mybuf = strrchr (tmpptr,':')) == NULL) )
|
|
{
|
|
/* address is in a bad format */
|
|
*protocol = NULL;
|
|
*host = NULL;
|
|
*port = NULL;
|
|
xfree (tmpptr);
|
|
return 0;
|
|
}
|
|
|
|
if (*mybuf == ':')
|
|
{
|
|
/*
|
|
* If there is a hostname, then assume tcp, otherwise
|
|
* it must be local.
|
|
*/
|
|
if (mybuf == tmpptr)
|
|
{
|
|
/* There is neither a protocol or host specified */
|
|
_protocol = (char*)"local";
|
|
}
|
|
else
|
|
{
|
|
/* Ther is a hostname specified */
|
|
_protocol = (char*)"inet";
|
|
mybuf = tmpptr; /* reset to the begining of the host ptr */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* *mybuf == '/' */
|
|
|
|
*mybuf ++= '\0'; /* put a null at the end of the protocol */
|
|
|
|
if (strlen(_protocol) == 0)
|
|
{
|
|
/*
|
|
* If there is a hostname, then assume inet, otherwise
|
|
* it must be local.
|
|
*/
|
|
if (*mybuf != ':')
|
|
_protocol = (char*)"inet";
|
|
else
|
|
_protocol = (char*)"local";
|
|
}
|
|
}
|
|
|
|
/* Get the host part */
|
|
|
|
_host = mybuf;
|
|
|
|
if ((mybuf = strrchr (mybuf,':')) == NULL)
|
|
{
|
|
*protocol = NULL;
|
|
*host = NULL;
|
|
*port = NULL;
|
|
xfree (tmpptr);
|
|
return 0;
|
|
}
|
|
|
|
*mybuf ++= '\0';
|
|
|
|
if (strlen(_host) == 0)
|
|
{
|
|
TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
|
|
_host = hostnamebuf;
|
|
}
|
|
|
|
/* Get the port */
|
|
|
|
_port = mybuf;
|
|
|
|
#if defined(FONT_t) || defined(FS_t)
|
|
/*
|
|
* Is there an optional catalog list?
|
|
*/
|
|
|
|
if ((mybuf = strchr (mybuf,'/')) != NULL)
|
|
*mybuf ++= '\0';
|
|
|
|
/*
|
|
* The rest, if any, is the (currently unused) catalog list.
|
|
*
|
|
* _catalogue = mybuf;
|
|
*/
|
|
#endif
|
|
|
|
/*
|
|
* Now that we have all of the components, allocate new
|
|
* string space for them.
|
|
*/
|
|
|
|
if ((*protocol = (char *) xalloc(strlen (_protocol) + 1)) == NULL)
|
|
{
|
|
/* Malloc failed */
|
|
*port = NULL;
|
|
*host = NULL;
|
|
*protocol = NULL;
|
|
xfree (tmpptr);
|
|
return 0;
|
|
}
|
|
else
|
|
strcpy (*protocol, _protocol);
|
|
|
|
if ((*host = (char *) xalloc (strlen (_host) + 1)) == NULL)
|
|
{
|
|
/* Malloc failed */
|
|
*port = NULL;
|
|
*host = NULL;
|
|
xfree (*protocol);
|
|
*protocol = NULL;
|
|
xfree (tmpptr);
|
|
return 0;
|
|
}
|
|
else
|
|
strcpy (*host, _host);
|
|
|
|
if ((*port = (char *) xalloc (strlen (_port) + 1)) == NULL)
|
|
{
|
|
/* Malloc failed */
|
|
*port = NULL;
|
|
xfree (*host);
|
|
*host = NULL;
|
|
xfree (*protocol);
|
|
*protocol = NULL;
|
|
xfree (tmpptr);
|
|
return 0;
|
|
}
|
|
else
|
|
strcpy (*port, _port);
|
|
|
|
xfree (tmpptr);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* TRANS(Open) does all of the real work opening a connection. The only
|
|
* funny part about this is the type parameter which is used to decide which
|
|
* type of open to perform.
|
|
*/
|
|
|
|
static XtransConnInfo
|
|
TRANS(Open) (int type, char *address)
|
|
|
|
{
|
|
char *protocol = NULL, *host = NULL, *port = NULL;
|
|
XtransConnInfo ciptr = NULL;
|
|
Xtransport *thistrans;
|
|
|
|
PRMSG (2,"Open(%d,%s)\n", type, address, 0);
|
|
|
|
#if defined(_WIN32) && (defined(TCPCONN) || defined(DNETCONN))
|
|
if (TRANS(WSAStartup)())
|
|
{
|
|
PRMSG (1,"Open: WSAStartup failed\n", 0, 0, 0);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
/* Parse the Address */
|
|
|
|
if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
|
|
{
|
|
PRMSG (1,"Open: Unable to Parse address %s\n", address, 0, 0);
|
|
return NULL;
|
|
}
|
|
|
|
/* Determine the transport type */
|
|
|
|
if ((thistrans = TRANS(SelectTransport) (protocol)) == NULL)
|
|
{
|
|
PRMSG (1,"Open: Unable to tqfind transport for %s\n",
|
|
protocol, 0, 0);
|
|
|
|
xfree (protocol);
|
|
xfree (host);
|
|
xfree (port);
|
|
return NULL;
|
|
}
|
|
|
|
/* Open the transport */
|
|
|
|
switch (type)
|
|
{
|
|
case XTRANS_OPEN_COTS_CLIENT:
|
|
#ifdef TRANS_CLIENT
|
|
ciptr = thistrans->OpenCOTSClient(thistrans, protocol, host, port);
|
|
#endif /* TRANS_CLIENT */
|
|
break;
|
|
case XTRANS_OPEN_COTS_SERVER:
|
|
#ifdef TRANS_SERVER
|
|
ciptr = thistrans->OpenCOTSServer(thistrans, protocol, host, port);
|
|
#endif /* TRANS_SERVER */
|
|
break;
|
|
case XTRANS_OPEN_CLTS_CLIENT:
|
|
#ifdef TRANS_CLIENT
|
|
ciptr = thistrans->OpenCLTSClient(thistrans, protocol, host, port);
|
|
#endif /* TRANS_CLIENT */
|
|
break;
|
|
case XTRANS_OPEN_CLTS_SERVER:
|
|
#ifdef TRANS_SERVER
|
|
ciptr = thistrans->OpenCLTSServer(thistrans, protocol, host, port);
|
|
#endif /* TRANS_SERVER */
|
|
break;
|
|
default:
|
|
PRMSG (1,"Open: Unknown Open type %d\n", type, 0, 0);
|
|
}
|
|
|
|
if (ciptr == NULL)
|
|
{
|
|
if (!(thistrans->flags & TRANS_DISABLED))
|
|
{
|
|
PRMSG (1,"Open: transport open failed for %s/%s:%s\n",
|
|
protocol, host, port);
|
|
}
|
|
xfree (protocol);
|
|
xfree (host);
|
|
xfree (port);
|
|
return NULL;
|
|
}
|
|
|
|
ciptr->transptr = thistrans;
|
|
ciptr->port = port; /* We need this for TRANS(Reopen) */
|
|
|
|
xfree (protocol);
|
|
xfree (host);
|
|
|
|
return ciptr;
|
|
}
|
|
|
|
|
|
#ifdef TRANS_REOPEN
|
|
|
|
/*
|
|
* We might want to create an XtransConnInfo object based on a previously
|
|
* opened connection. For example, the font server may clone itself and
|
|
* pass file descriptors to the parent.
|
|
*/
|
|
|
|
static XtransConnInfo
|
|
TRANS(Reopen) (int type, int trans_id, int fd, char *port)
|
|
|
|
{
|
|
XtransConnInfo ciptr = NULL;
|
|
Xtransport *thistrans = NULL;
|
|
char *save_port;
|
|
int i;
|
|
|
|
PRMSG (2,"Reopen(%d,%d,%s)\n", trans_id, fd, port);
|
|
|
|
/* Determine the transport type */
|
|
|
|
for (i = 0; i < NUMTRANS; i++)
|
|
if (Xtransports[i].transport_id == trans_id)
|
|
{
|
|
thistrans = Xtransports[i].transport;
|
|
break;
|
|
}
|
|
|
|
if (thistrans == NULL)
|
|
{
|
|
PRMSG (1,"Reopen: Unable to tqfind transport id %d\n",
|
|
trans_id, 0, 0);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if ((save_port = (char *) xalloc (strlen (port) + 1)) == NULL)
|
|
{
|
|
PRMSG (1,"Reopen: Unable to malloc port string\n", 0, 0, 0);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
strcpy (save_port, port);
|
|
|
|
/* Get a new XtransConnInfo object */
|
|
|
|
switch (type)
|
|
{
|
|
case XTRANS_OPEN_COTS_SERVER:
|
|
ciptr = thistrans->ReopenCOTSServer(thistrans, fd, port);
|
|
break;
|
|
case XTRANS_OPEN_CLTS_SERVER:
|
|
ciptr = thistrans->ReopenCLTSServer(thistrans, fd, port);
|
|
break;
|
|
default:
|
|
PRMSG (1,"Reopen: Bad Open type %d\n", type, 0, 0);
|
|
}
|
|
|
|
if (ciptr == NULL)
|
|
{
|
|
PRMSG (1,"Reopen: transport open failed\n", 0, 0, 0);
|
|
return NULL;
|
|
}
|
|
|
|
ciptr->transptr = thistrans;
|
|
ciptr->port = save_port;
|
|
|
|
return ciptr;
|
|
}
|
|
|
|
#endif /* TRANS_REOPEN */
|
|
|
|
|
|
|
|
/*
|
|
* These are the public interfaces to this Transport interface.
|
|
* These are the only functions that should have knowledge of the transport
|
|
* table.
|
|
*/
|
|
|
|
#ifdef TRANS_CLIENT
|
|
|
|
XtransConnInfo
|
|
TRANS(OpenCOTSClient) (char *address)
|
|
|
|
{
|
|
PRMSG (2,"OpenCOTSClient(%s)\n", address, 0, 0);
|
|
return TRANS(Open) (XTRANS_OPEN_COTS_CLIENT, address);
|
|
}
|
|
|
|
#endif /* TRANS_CLIENT */
|
|
|
|
|
|
#ifdef TRANS_SERVER
|
|
|
|
XtransConnInfo
|
|
TRANS(OpenCOTSServer) (char *address)
|
|
|
|
{
|
|
PRMSG (2,"OpenCOTSServer(%s)\n", address, 0, 0);
|
|
return TRANS(Open) (XTRANS_OPEN_COTS_SERVER, address);
|
|
}
|
|
|
|
#endif /* TRANS_SERVER */
|
|
|
|
|
|
#ifdef TRANS_CLIENT
|
|
|
|
XtransConnInfo
|
|
TRANS(OpenCLTSClient) (char *address)
|
|
|
|
{
|
|
PRMSG (2,"OpenCLTSClient(%s)\n", address, 0, 0);
|
|
return TRANS(Open) (XTRANS_OPEN_CLTS_CLIENT, address);
|
|
}
|
|
|
|
#endif /* TRANS_CLIENT */
|
|
|
|
|
|
#ifdef TRANS_SERVER
|
|
|
|
XtransConnInfo
|
|
TRANS(OpenCLTSServer) (char *address)
|
|
|
|
{
|
|
PRMSG (2,"OpenCLTSServer(%s)\n", address, 0, 0);
|
|
return TRANS(Open) (XTRANS_OPEN_CLTS_SERVER, address);
|
|
}
|
|
|
|
#endif /* TRANS_SERVER */
|
|
|
|
|
|
#ifdef TRANS_REOPEN
|
|
|
|
XtransConnInfo
|
|
TRANS(ReopenCOTSServer) (int trans_id, int fd, char *port)
|
|
|
|
{
|
|
PRMSG (2,"ReopenCOTSServer(%d, %d, %s)\n", trans_id, fd, port);
|
|
return TRANS(Reopen) (XTRANS_OPEN_COTS_SERVER, trans_id, fd, port);
|
|
}
|
|
|
|
XtransConnInfo
|
|
TRANS(ReopenCLTSServer) (int trans_id, int fd, char *port)
|
|
|
|
{
|
|
PRMSG (2,"ReopenCLTSServer(%d, %d, %s)\n", trans_id, fd, port);
|
|
return TRANS(Reopen) (XTRANS_OPEN_CLTS_SERVER, trans_id, fd, port);
|
|
}
|
|
|
|
|
|
int
|
|
TRANS(GetReopenInfo) (XtransConnInfo ciptr,
|
|
int *trans_id, int *fd, char **port)
|
|
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUMTRANS; i++)
|
|
if (Xtransports[i].transport == ciptr->transptr)
|
|
{
|
|
*trans_id = Xtransports[i].transport_id;
|
|
*fd = ciptr->fd;
|
|
|
|
if ((*port = (char *) xalloc (strlen (ciptr->port) + 1)) == NULL)
|
|
return 0;
|
|
else
|
|
{
|
|
strcpy (*port, ciptr->port);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* TRANS_REOPEN */
|
|
|
|
|
|
int
|
|
TRANS(SetOption) (XtransConnInfo ciptr, int option, int arg)
|
|
|
|
{
|
|
int fd = ciptr->fd;
|
|
int ret = 0;
|
|
|
|
PRMSG (2,"SetOption(%d,%d,%d)\n", fd, option, arg);
|
|
|
|
/*
|
|
* For now, all transport type use the same stuff for setting options.
|
|
* As long as this is true, we can put the common code here. Once a more
|
|
* complicated transport such as shared memory or an OSI implementation
|
|
* that uses the session and application libraries is implemented, this
|
|
* code may have to move to a transport dependent function.
|
|
*
|
|
* ret = ciptr->transptr->SetOption (ciptr, option, arg);
|
|
*/
|
|
|
|
#ifdef MINIX
|
|
return ciptr->transptr->SetOption(ciptr, option, arg);
|
|
#else /* !MINIX */
|
|
|
|
switch (option)
|
|
{
|
|
case TRANS_NONBLOCKING:
|
|
switch (arg)
|
|
{
|
|
case 0:
|
|
/* Set to blocking mode */
|
|
break;
|
|
case 1: /* Set to non-blocking mode */
|
|
|
|
#if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux) && !defined(AIXV3) && !defined(uniosu) && !defined(__EMX__) && !defined(SCO)) && !defined(__QNX__)
|
|
ret = fcntl (fd, F_GETFL, 0);
|
|
if (ret != -1)
|
|
ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK);
|
|
#else
|
|
#ifdef FIOSNBIO
|
|
{
|
|
int arg;
|
|
arg = 1;
|
|
ret = ioctl (fd, FIOSNBIO, &arg);
|
|
}
|
|
#else
|
|
#if (defined(AIXV3) || defined(uniosu) || defined(_WIN32) || defined(__EMX__) || defined(__QNX__)) && defined(FIONBIO)
|
|
{
|
|
int arg;
|
|
arg = 1;
|
|
/* IBM TCP/IP understands this option too well: it causes TRANS(Read) to fail
|
|
* eventually with EWOULDBLOCK */
|
|
#ifndef __EMX__
|
|
ret = ioctl (fd, FIONBIO, &arg);
|
|
#else
|
|
/* ret = ioctl(fd, FIONBIO, &arg, sizeof(int));*/
|
|
#endif
|
|
}
|
|
#else
|
|
ret = fcntl (fd, F_GETFL, 0);
|
|
#ifdef FNDELAY
|
|
ret = fcntl (fd, F_SETFL, ret | FNDELAY);
|
|
#else
|
|
ret = fcntl (fd, F_SETFL, ret | O_NDELAY);
|
|
#endif
|
|
#endif /* AIXV3 || uniosu */
|
|
#endif /* FIOSNBIO */
|
|
#endif /* O_NONBLOCK */
|
|
break;
|
|
default:
|
|
/* Unknown option */
|
|
break;
|
|
}
|
|
break;
|
|
case TRANS_CLOSEONEXEC:
|
|
#ifdef F_SETFD
|
|
#ifdef FD_CLOEXEC
|
|
ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
|
|
#else
|
|
ret = fcntl (fd, F_SETFD, 1);
|
|
#endif /* FD_CLOEXEC */
|
|
#endif /* F_SETFD */
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
#endif /* MINIX */
|
|
}
|
|
|
|
#ifdef TRANS_SERVER
|
|
|
|
int
|
|
TRANS(CreateListener) (XtransConnInfo ciptr, char *port)
|
|
|
|
{
|
|
return ciptr->transptr->CreateListener (ciptr, port);
|
|
}
|
|
|
|
int
|
|
TRANS(NoListen) (char * protocol)
|
|
|
|
{
|
|
Xtransport *trans;
|
|
|
|
if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
|
|
{
|
|
PRMSG (1,"TRANS(TransNoListen): unable to tqfind transport: %s\n",
|
|
protocol, 0, 0);
|
|
|
|
return -1;
|
|
}
|
|
|
|
trans->flags |= TRANS_NOLISTEN;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TRANS(ResetListener) (XtransConnInfo ciptr)
|
|
|
|
{
|
|
if (ciptr->transptr->ResetListener)
|
|
return ciptr->transptr->ResetListener (ciptr);
|
|
else
|
|
return TRANS_RESET_NOOP;
|
|
}
|
|
|
|
|
|
XtransConnInfo
|
|
TRANS(Accept) (XtransConnInfo ciptr, int *status)
|
|
|
|
{
|
|
XtransConnInfo newciptr;
|
|
|
|
PRMSG (2,"Accept(%d)\n", ciptr->fd, 0, 0);
|
|
|
|
newciptr = ciptr->transptr->Accept (ciptr, status);
|
|
|
|
if (newciptr)
|
|
newciptr->transptr = ciptr->transptr;
|
|
|
|
return newciptr;
|
|
}
|
|
|
|
#endif /* TRANS_SERVER */
|
|
|
|
|
|
#ifdef TRANS_CLIENT
|
|
|
|
int
|
|
TRANS(Connect) (XtransConnInfo ciptr, char *address)
|
|
|
|
{
|
|
char *protocol;
|
|
char *host;
|
|
char *port;
|
|
int ret;
|
|
|
|
PRMSG (2,"Connect(%d,%s)\n", ciptr->fd, address, 0);
|
|
|
|
if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
|
|
{
|
|
PRMSG (1,"Connect: Unable to Parse address %s\n",
|
|
address, 0, 0);
|
|
return -1;
|
|
}
|
|
|
|
if (!port || !*port)
|
|
{
|
|
PRMSG (1,"Connect: Missing port specification in %s\n",
|
|
address, 0, 0);
|
|
if (protocol) xfree (protocol);
|
|
if (host) xfree (host);
|
|
return -1;
|
|
}
|
|
|
|
ret = ciptr->transptr->Connect (ciptr, host, port);
|
|
|
|
if (protocol) xfree (protocol);
|
|
if (host) xfree (host);
|
|
if (port) xfree (port);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* TRANS_CLIENT */
|
|
|
|
|
|
int
|
|
TRANS(BytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
|
|
|
|
{
|
|
return ciptr->transptr->BytesReadable (ciptr, pend);
|
|
}
|
|
|
|
int
|
|
TRANS(Read) (XtransConnInfo ciptr, char *buf, int size)
|
|
|
|
{
|
|
return ciptr->transptr->Read (ciptr, buf, size);
|
|
}
|
|
|
|
int
|
|
TRANS(Write) (XtransConnInfo ciptr, char *buf, int size)
|
|
|
|
{
|
|
return ciptr->transptr->Write (ciptr, buf, size);
|
|
}
|
|
|
|
int
|
|
TRANS(Readv) (XtransConnInfo ciptr, struct iovec *buf, int size)
|
|
|
|
{
|
|
return ciptr->transptr->Readv (ciptr, buf, size);
|
|
}
|
|
|
|
int
|
|
TRANS(Writev) (XtransConnInfo ciptr, struct iovec *buf, int size)
|
|
|
|
{
|
|
return ciptr->transptr->Writev (ciptr, buf, size);
|
|
}
|
|
|
|
int
|
|
TRANS(Disconnect) (XtransConnInfo ciptr)
|
|
|
|
{
|
|
return ciptr->transptr->Disconnect (ciptr);
|
|
}
|
|
|
|
int
|
|
TRANS(Close) (XtransConnInfo ciptr)
|
|
|
|
{
|
|
int ret;
|
|
|
|
PRMSG (2,"Close(%d)\n", ciptr->fd, 0, 0);
|
|
|
|
ret = ciptr->transptr->Close (ciptr);
|
|
|
|
TRANS(FreeConnInfo) (ciptr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
TRANS(CloseForCloning) (XtransConnInfo ciptr)
|
|
|
|
{
|
|
int ret;
|
|
|
|
PRMSG (2,"CloseForCloning(%d)\n", ciptr->fd, 0, 0);
|
|
|
|
ret = ciptr->transptr->CloseForCloning (ciptr);
|
|
|
|
TRANS(FreeConnInfo) (ciptr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
TRANS(IsLocal) (XtransConnInfo ciptr)
|
|
|
|
{
|
|
return (ciptr->family == AF_UNIX);
|
|
}
|
|
|
|
|
|
int
|
|
TRANS(GetMyAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
|
|
Xtransaddr **addrp)
|
|
|
|
{
|
|
PRMSG (2,"GetMyAddr(%d)\n", ciptr->fd, 0, 0);
|
|
|
|
*familyp = ciptr->family;
|
|
*addrlenp = ciptr->addrlen;
|
|
|
|
if ((*addrp = (Xtransaddr *) xalloc (ciptr->addrlen)) == NULL)
|
|
{
|
|
PRMSG (1,"GetMyAddr: malloc failed\n", 0, 0, 0);
|
|
return -1;
|
|
}
|
|
memcpy(*addrp, ciptr->addr, ciptr->addrlen);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TRANS(GetPeerAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
|
|
Xtransaddr **addrp)
|
|
|
|
{
|
|
PRMSG (2,"GetPeerAddr(%d)\n", ciptr->fd, 0, 0);
|
|
|
|
*familyp = ciptr->family;
|
|
*addrlenp = ciptr->peeraddrlen;
|
|
|
|
if ((*addrp = (Xtransaddr *) xalloc (ciptr->peeraddrlen)) == NULL)
|
|
{
|
|
PRMSG (1,"GetPeerAddr: malloc failed\n", 0, 0, 0);
|
|
return -1;
|
|
}
|
|
memcpy(*addrp, ciptr->peeraddr, ciptr->peeraddrlen);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
TRANS(GetConnectionNumber) (XtransConnInfo ciptr)
|
|
|
|
{
|
|
return ciptr->fd;
|
|
}
|
|
|
|
|
|
/*
|
|
* These functions are really utility functions, but they require knowledge
|
|
* of the internal data structures, so they have to be part of the Transport
|
|
* Independant API.
|
|
*/
|
|
|
|
#ifdef TRANS_SERVER
|
|
|
|
static int
|
|
complete_network_count (void)
|
|
|
|
{
|
|
int count = 0;
|
|
int found_local = 0;
|
|
int i;
|
|
|
|
/*
|
|
* For a complete network, we only need one LOCALCONN transport to work
|
|
*/
|
|
|
|
for (i = 0; i < (int) NUMTRANS; i++)
|
|
{
|
|
if (Xtransports[i].transport->flags & TRANS_ALIAS
|
|
|| Xtransports[i].transport->flags & TRANS_NOLISTEN)
|
|
continue;
|
|
|
|
if (Xtransports[i].transport->flags & TRANS_LOCAL)
|
|
found_local = 1;
|
|
else
|
|
count++;
|
|
}
|
|
|
|
return (count + found_local);
|
|
}
|
|
|
|
|
|
|
|
int
|
|
TRANS(MakeAllCOTSServerListeners) (char *port, int *partial, int *count_ret,
|
|
XtransConnInfo **ciptrs_ret)
|
|
|
|
{
|
|
char buffer[256]; /* ??? What size ?? */
|
|
XtransConnInfo ciptr, temp_ciptrs[NUMTRANS];
|
|
int status, i, j;
|
|
|
|
PRMSG (2,"MakeAllCOTSServerListeners(%s,%x)\n",
|
|
port ? port : "NULL", ciptrs_ret, 0);
|
|
|
|
*count_ret = 0;
|
|
|
|
for (i = 0; i < (int) NUMTRANS; i++)
|
|
{
|
|
Xtransport *trans = Xtransports[i].transport;
|
|
|
|
if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN)
|
|
continue;
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s/:%s", trans->TransName, port ? port : "");
|
|
|
|
PRMSG (5,"MakeAllCOTSServerListeners: opening %s\n",
|
|
buffer, 0, 0);
|
|
|
|
if ((ciptr = TRANS(OpenCOTSServer(buffer))) == NULL)
|
|
{
|
|
if (trans->flags & TRANS_DISABLED)
|
|
continue;
|
|
|
|
PRMSG (1,
|
|
"MakeAllCOTSServerListeners: failed to open listener for %s\n",
|
|
trans->TransName, 0, 0);
|
|
continue;
|
|
}
|
|
|
|
if ((status = TRANS(CreateListener (ciptr, port))) < 0)
|
|
{
|
|
if (status == TRANS_ADDR_IN_USE)
|
|
{
|
|
/*
|
|
* We failed to bind to the specified address because the
|
|
* address is in use. It must be that a server is already
|
|
* running at this address, and this function should fail.
|
|
*/
|
|
|
|
PRMSG (1,
|
|
"MakeAllCOTSServerListeners: server already running\n",
|
|
0, 0, 0);
|
|
|
|
for (j = 0; j < *count_ret; j++)
|
|
TRANS(Close) (temp_ciptrs[j]);
|
|
|
|
*count_ret = 0;
|
|
*ciptrs_ret = NULL;
|
|
*partial = 0;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
PRMSG (1,
|
|
"MakeAllCOTSServerListeners: failed to create listener for %s\n",
|
|
trans->TransName, 0, 0);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
PRMSG (5,
|
|
"MakeAllCOTSServerListeners: opened listener for %s, %d\n",
|
|
trans->TransName, ciptr->fd, 0);
|
|
|
|
temp_ciptrs[*count_ret] = ciptr;
|
|
(*count_ret)++;
|
|
}
|
|
|
|
*partial = (*count_ret < complete_network_count());
|
|
|
|
PRMSG (5,
|
|
"MakeAllCLTSServerListeners: partial=%d, actual=%d, complete=%d \n",
|
|
*partial, *count_ret, complete_network_count());
|
|
|
|
if (*count_ret > 0)
|
|
{
|
|
if ((*ciptrs_ret = (XtransConnInfo *) xalloc (
|
|
*count_ret * sizeof (XtransConnInfo))) == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < *count_ret; i++)
|
|
{
|
|
(*ciptrs_ret)[i] = temp_ciptrs[i];
|
|
}
|
|
}
|
|
else
|
|
*ciptrs_ret = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TRANS(MakeAllCLTSServerListeners) (char *port, int *partial, int *count_ret,
|
|
XtransConnInfo **ciptrs_ret)
|
|
|
|
{
|
|
char buffer[256]; /* ??? What size ?? */
|
|
XtransConnInfo ciptr, temp_ciptrs[NUMTRANS];
|
|
int status, i, j;
|
|
|
|
PRMSG (2,"MakeAllCLTSServerListeners(%s,%x)\n",
|
|
port ? port : "NULL", ciptrs_ret, 0);
|
|
|
|
*count_ret = 0;
|
|
|
|
for (i = 0; i < (int) NUMTRANS; i++)
|
|
{
|
|
Xtransport *trans = Xtransports[i].transport;
|
|
|
|
if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN)
|
|
continue;
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s/:%s", trans->TransName, port ? port : "");
|
|
|
|
PRMSG (5,"MakeAllCLTSServerListeners: opening %s\n",
|
|
buffer, 0, 0);
|
|
|
|
if ((ciptr = TRANS(OpenCLTSServer (buffer))) == NULL)
|
|
{
|
|
PRMSG (1,
|
|
"MakeAllCLTSServerListeners: failed to open listener for %s\n",
|
|
trans->TransName, 0, 0);
|
|
continue;
|
|
}
|
|
|
|
if ((status = TRANS(CreateListener (ciptr, port))) < 0)
|
|
{
|
|
if (status == TRANS_ADDR_IN_USE)
|
|
{
|
|
/*
|
|
* We failed to bind to the specified address because the
|
|
* address is in use. It must be that a server is already
|
|
* running at this address, and this function should fail.
|
|
*/
|
|
|
|
PRMSG (1,
|
|
"MakeAllCLTSServerListeners: server already running\n",
|
|
0, 0, 0);
|
|
|
|
for (j = 0; j < *count_ret; j++)
|
|
TRANS(Close) (temp_ciptrs[j]);
|
|
|
|
*count_ret = 0;
|
|
*ciptrs_ret = NULL;
|
|
*partial = 0;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
PRMSG (1,
|
|
"MakeAllCLTSServerListeners: failed to create listener for %s\n",
|
|
trans->TransName, 0, 0);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
PRMSG (5,
|
|
"MakeAllCLTSServerListeners: opened listener for %s, %d\n",
|
|
trans->TransName, ciptr->fd, 0);
|
|
temp_ciptrs[*count_ret] = ciptr;
|
|
(*count_ret)++;
|
|
}
|
|
|
|
*partial = (*count_ret < complete_network_count());
|
|
|
|
PRMSG (5,
|
|
"MakeAllCLTSServerListeners: partial=%d, actual=%d, complete=%d \n",
|
|
*partial, *count_ret, complete_network_count());
|
|
|
|
if (*count_ret > 0)
|
|
{
|
|
if ((*ciptrs_ret = (XtransConnInfo *) xalloc (
|
|
*count_ret * sizeof (XtransConnInfo))) == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < *count_ret; i++)
|
|
{
|
|
(*ciptrs_ret)[i] = temp_ciptrs[i];
|
|
}
|
|
}
|
|
else
|
|
*ciptrs_ret = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* TRANS_SERVER */
|
|
|
|
|
|
|
|
/*
|
|
* These routines are not part of the X Transport Interface, but they
|
|
* may be used by it.
|
|
*/
|
|
|
|
#ifdef CRAY
|
|
|
|
/*
|
|
* Cray UniCOS does not have readv and writev so we emulate
|
|
*/
|
|
|
|
static int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
|
|
|
|
{
|
|
struct msghdr hdr;
|
|
|
|
hdr.msg_iov = iov;
|
|
hdr.msg_iovlen = iovcnt;
|
|
hdr.msg_accrights = 0;
|
|
hdr.msg_accrightslen = 0;
|
|
hdr.msg_name = 0;
|
|
hdr.msg_namelen = 0;
|
|
|
|
return (recvmsg (ciptr->fd, &hdr, 0));
|
|
}
|
|
|
|
static int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
|
|
|
|
{
|
|
struct msghdr hdr;
|
|
|
|
hdr.msg_iov = iov;
|
|
hdr.msg_iovlen = iovcnt;
|
|
hdr.msg_accrights = 0;
|
|
hdr.msg_accrightslen = 0;
|
|
hdr.msg_name = 0;
|
|
hdr.msg_namelen = 0;
|
|
|
|
return (sendmsg (ciptr->fd, &hdr, 0));
|
|
}
|
|
|
|
#endif /* CRAY */
|
|
|
|
#if (defined(SYSV) && defined(i386) && !defined(SCO325)) || defined(_WIN32) || defined(__sxg__) || defined(__EMX__)
|
|
|
|
/*
|
|
* emulate readv
|
|
*/
|
|
|
|
static int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
|
|
|
|
{
|
|
int i, len, total;
|
|
char *base;
|
|
|
|
ESET(0);
|
|
for (i = 0, total = 0; i < iovcnt; i++, iov++) {
|
|
len = iov->iov_len;
|
|
base = iov->iov_base;
|
|
while (len > 0) {
|
|
register int nbytes;
|
|
nbytes = TRANS(Read) (ciptr, base, len);
|
|
if (nbytes < 0 && total == 0) return -1;
|
|
if (nbytes <= 0) return total;
|
|
ESET(0);
|
|
len -= nbytes;
|
|
total += nbytes;
|
|
base += nbytes;
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
#endif /* SYSV && i386 || _WIN32 || __sxg__ */
|
|
|
|
#if (defined(SYSV) && defined(i386) && !defined(SCO325)) || defined(_WIN32) || defined(__sxg__) || defined(__EMX__)
|
|
|
|
/*
|
|
* emulate writev
|
|
*/
|
|
|
|
static int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
|
|
|
|
{
|
|
int i, len, total;
|
|
char *base;
|
|
|
|
ESET(0);
|
|
for (i = 0, total = 0; i < iovcnt; i++, iov++) {
|
|
len = iov->iov_len;
|
|
base = iov->iov_base;
|
|
while (len > 0) {
|
|
register int nbytes;
|
|
nbytes = TRANS(Write) (ciptr, base, len);
|
|
if (nbytes < 0 && total == 0) return -1;
|
|
if (nbytes <= 0) return total;
|
|
ESET(0);
|
|
len -= nbytes;
|
|
total += nbytes;
|
|
base += nbytes;
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
#endif /* SYSV && i386 || _WIN32 || __sxg__ */
|
|
|
|
|
|
#if (defined(_POSIX_SOURCE) && !defined(AIXV3) && !defined(__QNX__)) || defined(hpux) || defined(USG) || defined(SVR4) || defined(SCO)
|
|
#ifndef NEED_UTSNAME
|
|
#define NEED_UTSNAME
|
|
#endif
|
|
#include <sys/utsname.h>
|
|
#endif
|
|
|
|
/*
|
|
* TRANS(GetHostname) - similar to gethostname but allows special processing.
|
|
*/
|
|
|
|
int TRANS(GetHostname) (char *buf, int maxlen)
|
|
|
|
{
|
|
int len;
|
|
|
|
#ifdef NEED_UTSNAME
|
|
struct utsname name;
|
|
|
|
uname (&name);
|
|
len = strlen (name.nodename);
|
|
if (len >= maxlen) len = maxlen - 1;
|
|
strncpy (buf, name.nodename, len);
|
|
buf[len] = '\0';
|
|
#else
|
|
buf[0] = '\0';
|
|
(void) gethostname (buf, maxlen);
|
|
buf [maxlen - 1] = '\0';
|
|
len = strlen(buf);
|
|
#endif /* NEED_UTSNAME */
|
|
return len;
|
|
}
|