/* $XFree86: xc/lib/xtrans/Xtransos2.c,v 3.5 1997/01/28 10:53:32 dawes Exp $ */

/*
 * (c) Copyright 1996 by Sebastien Marineau and Holger Veit
 *			<marineau@genie.uottawa.ca>
 *                      <Holger.Veit@gmd.de>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the 
 * Software is furnished to do so, subject to the following conditions:
 *
 * 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 
 * HOLGER VEIT  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 Sebastien Marineau or Holger Veit shall not be
 * used in advertising or otherwise to promote the sale, use or other dealings
 * in this Software without prior written authorization from Holger Veit or Sebastien Marineau.
 *
 */

/* Implementation of the OS/2 local pipe transport layer */

#define INCL_DOSNMPIPES
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_DOSFILEMGR
#undef BYTE
#undef BOOL
#include <os2.h>

#ifdef XSERV_t
extern HEV hPipeSem;
BOOL init_server_pipes();
#endif

/*************************************************************************
 * Independent Layer
 *************************************************************************/
#ifdef TRANS_CLIENT

static XtransConnInfo
TRANS(Os2OpenClient)(thistrans, protocol, host, port)
Xtransport *thistrans;
char *protocol;
char *host;
char *port;
{
	APIRET rc;
	HFILE hfd,hServer;
	ULONG action,byteWritten,State;
	char pipename[256],clientname[256];
        char server_string[256];
        struct sockaddr *addr_name;
        unsigned char pipe_len;
	XtransConnInfo ciptr;
        static int unique_id=0;
        int i,namelen,try;

	PRMSG(2,"Os2OpenClient(%s,%s,%s)\n",protocol,host,port);

	/* test, whether the host is really local, i.e. either
	 * "os2" or "local"
	 */
	if (strcmp(protocol,"os2") && strcmp(protocol,"local")) {
		PRMSG (1,
			"Os2OpenClient: Cannot connect to non-local host %s\n",
			host, 0, 0);
		return NULL;
	}

   /* make the pipename */

    if (port && *port ) {
	if( *port == '/' ) { /* A full pathname */
		(void) sprintf(pipename, "\\PIPE\\X\\%s,", port);
	    } else {
		(void) sprintf(pipename, "%s%s", "\\PIPE\\X\\xf86.", port);
	    }
    } else {
	(void) sprintf(pipename, "\\PIPE\\X\\xfree86"); }

    PRMSG(5, "Os2OpenClient: Creating pipe %s\n",pipename, 0,0 );

	/* make a connection entry */	
	if( (ciptr=(XtransConnInfo)xcalloc(1,sizeof(struct _XtransConnInfo))) == NULL ) {
		PRMSG(1,"Os2OpenClient: calloc(1,%d) failed\n",
			sizeof(struct _XtransConnInfo),0,0 );
		return NULL;
	}

	/* open the pipe. Try ten times before giving up at 500ms intervals*/
    try = 0;
    do {
	rc = DosOpen(pipename,&hServer, &action, 0,
		FILE_NORMAL, FILE_OPEN,
		OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
		(PEAOP2)NULL);
        if(rc == 0) break;
	if (try >=10) {
		PRMSG(1,"Os2OpenClient: Open server pipe %s failed, rc=%d\n",
			pipename,rc,0 );
		PRMSG(1,"\tProbable causes: either the XServer is not running, or has not started properly,\n",
			0,0,0 );
		PRMSG(1,"\tor the DISPLAY variable is set incorrectly.\n",
			0,0,0 );
		xfree(ciptr);
		return NULL;
	    }
       try ++;
       DosSleep(500);
       } while (rc != 0);

/* OK, now we are talking to the server. Generate a unique pipe name and pass it to
 * the server. Make the pipe and wait for server to connect */

   sprintf(clientname,"\\PIPE\\X\\%d.%d",getpid(),unique_id++);
 
   rc = DosCreateNPipe (clientname, &hfd,
                       NP_NOINHERIT | NP_ACCESS_DUPLEX,
                       1 | NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE,
                       16384, 16384, 0);
   if (rc != 0){
        PRMSG(1, "Os2OpenClient: Unable to create pipe %s\n", pipename,0,0 );
	DosClose(hfd);
        pipe_len=0;
        DosWrite(hServer,&pipe_len,1,&byteWritten);
        DosClose(hServer);
        xfree(ciptr);
	return(NULL);
    }

 /* Connect to the pipe. */

  rc = DosConnectNPipe (hfd);
  if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED)
    {
        PRMSG(1, "Os2OpenClient: Unable to connect to pipe %s\n", pipename,0,0 );
        DosClose (hfd);
        DosClose(hServer);
        xfree(ciptr);
        return (NULL);
    }

/* Now write name to server on hServer */
        server_string[0]=(char) strlen(clientname)+1;
        strcpy(&server_string[1],clientname);
        rc = DosWrite(hServer,server_string,(ULONG)server_string[0]+1,&byteWritten);
        if(rc != 0){  /* Could not write to server pipe? */
           PRMSG(1, "Os2OpenClient: Error writing to server pipe, handle=%d, rc=%d, w=%d\n",
                hServer,rc,byteWritten );
           DosClose(hServer);
           DosClose(hfd);
           xfree(ciptr);
           return(NULL);
           }

      PRMSG (5, "Os2OpenCLient: Wrote pipename %s to server; len %d written %d \n",
        &server_string[1],server_string[0]+1,byteWritten);


/* The server will respond by opening the pipe. Wait for that for 30 secs */

        i=0;
        DosSleep(50);  /* Give it time to catch up but minimize race condition*/
        rc = DosConnectNPipe(hfd);
        while((rc == ERROR_PIPE_NOT_CONNECTED)&&(i++<60)) {
                DosSleep(500);
                rc = DosConnectNPipe(hfd);
                }

        if(rc != 0){  /* Server has not responded! */
           PRMSG(1, "Os2OpenClient: Timeout on wait for server response, handle=%d, rc=%d\n",hServer,rc,0 );
           PRMSG(1, "\tProbable cause: the XServer has exited or crashed while the connection was being established\n",0,0,0 );
           PRMSG(1, "\tor the XServer is too busy to respond.\n",0,0,0 );
           DosClose(hServer);
           DosClose(hfd);
           xfree(ciptr);
           return(NULL);
           }

/* OK, the server has connected! Fill-in the info and return */

        DosClose(hServer);

/* Last check: make sure client is connected! */

        rc = DosQueryNPHState(hfd,&State);
        if(rc != 0){  /* Client is not connected! */
           PRMSG(1, "Os2OpenClient: Client pipe does not appear connected. rc=%d, h=%d\n",rc,hfd,0 );
           PRMSG(1, "\tProbable cause: the XServer has just exited.\n",0,0,0 );
           DosClose(hfd);
           xfree(ciptr);
           return(NULL);
           }

        namelen=sizeof(struct sockaddr);
        if ((ciptr->addr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2OpenClient: Can't allocate space for the addr\n",
	        0, 0, 0);
                DosClose(hfd);
                xfree(ciptr);
                return(NULL);
           }
        ciptr->addrlen = namelen;
        ((struct sockaddr *)ciptr->addr)->sa_family = AF_UNIX;
        strcpy(((struct sockaddr *)ciptr->addr)->sa_data, "local");

        if ((ciptr->peeraddr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2OpenCLient: Can't allocate space for the addr\n",
	        0, 0, 0);
                DosClose(hfd);
                xfree(ciptr->addr);
                xfree(ciptr);
                return(NULL);
           }
       ciptr->peeraddrlen = namelen;
       ((struct sockaddr *)ciptr->peeraddr)->sa_family = AF_UNIX;
       strcpy (((struct sockaddr *)ciptr->peeraddr)->sa_data,"local");

       PRMSG (5, "Os2OpenCLient: Filled in struct: len %d %d name %s\n",
                ciptr->addrlen,ciptr->peeraddrlen,((struct sockaddr *)ciptr->peeraddr)->sa_data);


        ciptr->index=hfd;
        ciptr->family=AF_UNIX;
        if((ciptr->fd=_imphandle(hfd))<0){
           PRMSG(1, "Os2OpenClient: Could not import the pipe handle into EMX\n",0,0,0 );
           PRMSG(1, "\tProbable cause: EMX has run out of free file handles.\n",0,0,0 );
           DosClose(hfd);
           xfree(ciptr->addr);
           xfree(ciptr->peeraddr);
           xfree(ciptr);
           return(NULL);
           }
    PRMSG(5, "Os2OpenClient: pipe handle %d EMX handle %d\n",ciptr->index,ciptr->fd,0 );
        fcntl(ciptr->fd,F_SETFL,O_NDELAY);
        fcntl(ciptr->fd,F_SETFD,FD_CLOEXEC);
	return ciptr;
}
#endif /* TRANS_CLIENT */

#ifdef TRANS_SERVER
static XtransConnInfo
TRANS(Os2OpenServer)(thistrans, protocol, host, port)
Xtransport *thistrans;
char *protocol;
char *host;
char *port;
{
   APIRET rc;
   HFILE hfd;
   ULONG action;
   char pipename[256];
   struct sockaddr *addr_name;
   XtransConnInfo ciptr;
   int namelen;

#ifdef XSERV_t
    if (! init_server_pipes()) return(NULL);
#endif

    PRMSG(2,"Os2OpenServer(%s,%s,%s)\n",protocol,host,port);

   if( (ciptr=(XtransConnInfo)xcalloc(1,sizeof(struct _XtransConnInfo))) == NULL )
    {
	PRMSG(1,"Os2OpenServer: xcalloc(1,%d) failed\n",
	      sizeof(struct _XtransConnInfo),0,0 );
	return NULL;
    }


    if (port && *port ) {
	if( *port == '/' ) { /* A full pathname */
		(void) sprintf(pipename, "\\PIPE\\X\\%s", port);
	    } else {
		(void) sprintf(pipename, "%s%s", "\\PIPE\\X\\xf86.", port);
	    }
    } else {
	(void) sprintf(pipename, "\\PIPE\\X\\xfree86");
    }

    PRMSG(5, "Os2OpenServer: Creating pipe %s\n",pipename, 0,0 );

   rc = DosCreateNPipe (pipename, &hfd,
                       NP_NOINHERIT | NP_ACCESS_INBOUND,
                       1 | NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE,
                       0, 8192, 0);
   if (rc != 0){
        PRMSG(1, "Os2OpenServer: Unable to create pipe %s, rc=%d\n", pipename,rc,0 );
        PRMSG(1, "\tProbable cause: there is already another XServer running on display :%s\n",port,0,0 );
	DosClose(hfd);
        xfree(ciptr);
	return(NULL);
    }

 /* Connect to the pipe. */

  rc = DosConnectNPipe (hfd);
  if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED)
    {
        PRMSG(1, "Os2OpenServer: Unable to connect to pipe %s\n", pipename,0,0 );
        DosClose (hfd);
        xfree(ciptr);
        return (NULL);
    }

/* Pipe is now connected and waiting for client connect */

/*** Put in info ***/

        namelen=sizeof(struct sockaddr);
        if ((ciptr->addr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2OpenServer: Can't allocate space for the addr\n",
	        0, 0, 0);
                DosClose(hfd);
                xfree(ciptr);
                return(NULL);
           }
        ciptr->addrlen = namelen;
        ((struct sockaddr *)ciptr->addr)->sa_family = AF_UNIX;
        strcpy (((struct sockaddr *)ciptr->addr)->sa_data, "local");

        if ((ciptr->peeraddr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2OpenServer: Can't allocate space for the addr\n",
	        0, 0, 0);
                DosClose(hfd);
                xfree(ciptr->addr);
                xfree(ciptr);
                return(NULL);
           }

       ciptr->peeraddrlen = namelen;
       ((struct sockaddr *)ciptr->peeraddr)->sa_family = AF_UNIX;
       strcpy(((struct sockaddr *)ciptr->peeraddr)->sa_data,"local");
     
      PRMSG (5, "Os2OpenServer: Filled in struct: len %d %d name %s\n",
                ciptr->addrlen,ciptr->peeraddrlen,((struct sockaddr *)ciptr->peeraddr)->sa_data);

    ciptr->index=hfd; /* Save this for later use in this unused member of struct */
    ciptr->flags=1;     /* Listener */
    ciptr->family=AF_UNIX;

    if((ciptr->fd=_imphandle(hfd))<0){
       DosClose(hfd);
       xfree(ciptr->addr);
       xfree(ciptr->peeraddr);
       xfree(ciptr);
       return(NULL);
       }
    PRMSG(5, "Os2OpenServer: Pipe handle %d EMX handle %d",ciptr->index,ciptr->fd,0 );

#ifdef XSERV_t
/* Attach the pipe sem to the pipe. Use handle index as key */
    rc = DosSetNPipeSem(ciptr->fd, (HSEM)hPipeSem, ciptr->fd);
    if (rc){
        PRMSG(1, "Os2OpenCOTSServer: Could not attach sem %d to pipe %d, rc=%d\n",
                 hPipeSem,ciptr->fd,rc);
        DosClose(ciptr->fd);
        xfree(ciptr->addr);
        xfree(ciptr->peeraddr);
        xfree(ciptr);
         return(NULL);
        }
#endif

    fcntl(ciptr->fd,F_SETFL,O_NDELAY);
    fcntl(ciptr->fd,F_SETFD,FD_CLOEXEC);
    return(ciptr);
}
#endif /* TRANS_SERVER */

#ifdef TRANS_CLIENT
static XtransConnInfo
TRANS(Os2OpenCLTSClient)(thistrans, protocol, host, port)
Xtransport *thistrans;
char *protocol;
char *host;
char *port;
{
	PRMSG(2,"Os2OpenCLTSClient(%s,%s,%s)\n",protocol,host,port);
	return TRANS(Os2OpenClient)(thistrans, protocol, host, port);
}
#endif /* TRANS_CLIENT */

#ifdef TRANS_CLIENT
static XtransConnInfo
TRANS(Os2OpenCOTSClient)(thistrans, protocol, host, port)
Xtransport *thistrans;
char *protocol;
char *host;
char *port;
{
	PRMSG(2,"Os2OpenCOTSClient(%s,%s,%s)\n",protocol,host,port);
	return TRANS(Os2OpenClient)(thistrans, protocol, host, port);
}
#endif /* TRANS_CLIENT */


#ifdef TRANS_SERVER
static XtransConnInfo
TRANS(Os2OpenCLTSServer)(thistrans, protocol, host, port)
Xtransport *thistrans;
char *protocol;
char *host;
char *port;
{
	PRMSG(2,"Os2OpenCLTSServer(%s,%s,%s)\n",protocol,host,port);
	return TRANS(Os2OpenServer)(thistrans, protocol, host, port);
}
#endif /* TRANS_SERVER */


#ifdef TRANS_SERVER
static XtransConnInfo
TRANS(Os2OpenCOTSServer)(thistrans, protocol, host, port)
Xtransport *thistrans;
char *protocol;
char *host;
char *port;
{
	PRMSG(2,"Os2OpenCOTSServer(%s,%s,%s)\n",protocol,host,port);
	return TRANS(Os2OpenServer)(thistrans, protocol, host, port);
}
#endif /* TRANS_SERVER */


#ifdef TRANS_REOPEN
static XtransConnInfo
TRANS(Os2ReopenCOTSServer)(thistrans, fd, port)
Xtransport *thistrans;
int  	   fd;
char	   *port;
{

    XtransConnInfo ciptr;
    char addr_name[256];
    int namelen;
    
    PRMSG(2,"Os2ReopenCOTSServer(%d,%s)\n", fd, port, 0);
    
    if( (ciptr=(XtransConnInfo)xcalloc(1,sizeof(struct _XtransConnInfo))) == NULL )
    {
	PRMSG(1,"Os2ReopenCOTSServer: xcalloc(1,%d) failed\n",
	      sizeof(struct _XtransConnInfo),0,0 );
	return NULL;
    }
    
        strcpy(addr_name,"local");
        namelen=sizeof(addr_name);
        if ((ciptr->addr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2ReopenCOTSServer: Can't allocate space for the addr\n",
	        0, 0, 0);
                xfree(ciptr);
                return(NULL);
           }

        ciptr->addrlen = namelen;
        memcpy (ciptr->addr, addr_name, ciptr->addrlen);
        if ((ciptr->peeraddr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2ReopenCOTSServer: Can't allocate space for the addr\n",
	        0, 0, 0);
                xfree(ciptr);
                return(NULL);
           }

       ciptr->peeraddrlen = namelen;
       memcpy (ciptr->peeraddr,addr_name, ciptr->addrlen);

    ciptr->fd = fd;
    ciptr->family=AF_UNIX;
    ciptr->flags=1;
    PRMSG(1,"Os2ReopenCOTSServer: Filled-in info for handle %d on port %s.\n", fd, port, 0);

    return(ciptr);
}

static XtransConnInfo
TRANS(Os2ReopenCLTSServer)(thistrans, fd, port)
Xtransport *thistrans;
int  	   fd;
char	   *port;
{
    PRMSG(2,"Os2ReopenCLTSServer(%d,%s)\n", fd, port, 0);
    return TRANS(Os2ReopenCOTSServer)(thistrans, fd, port);
}
#endif

static
TRANS(Os2SetOption)(ciptr, option, arg)
XtransConnInfo ciptr;
int option;
int arg;
{
    PRMSG(2,"Os2SetOption(%d,%d,%d)\n",ciptr->fd,option,arg);
    return -1;
}

#ifdef TRANS_SERVER

static
TRANS(Os2CreateListener)(ciptr, port)
XtransConnInfo ciptr;
char *port;
{
	PRMSG(2,"Os2CreateListener(%x->%d,%s)\n",ciptr,ciptr->fd,port);
	return 0;
}

static XtransConnInfo
TRANS(Os2Accept)(ciptr, status)
XtransConnInfo ciptr;
int	       *status;
{
    XtransConnInfo	newciptr;
    HFILE hClient;
    unsigned char length;
    ULONG action;
    char clientname[256];
    struct sockaddr *addr_name;
    int in,namelen;
    APIRET rc;


    PRMSG(2,"Os2Accept(%x->%d)\n", ciptr, ciptr->fd,0);
    if( (newciptr=(XtransConnInfo)xcalloc(1,sizeof(struct _XtransConnInfo)))==NULL )
    {
	PRMSG(1,"Os2Accept: xcalloc(1,%d) failed\n",
	      sizeof(struct _XtransConnInfo),0,0 );
	*status = TRANS_ACCEPT_BAD_MALLOC;
	return NULL;
    }

/* Read in length of client pipe name. If fails, then reset server pipe */
    if((in=read(ciptr->fd,&length,1))<=0){
        PRMSG(2,"Os2Accept: Error reading incoming connection, in=%d, error=%d\n",
	      in,errno,0 );
	*status = TRANS_ACCEPT_MISC_ERROR;
        xfree(newciptr);
        rc = DosDisConnectNPipe(ciptr->fd);
        rc = DosConnectNPipe (ciptr->fd);
        if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED)
        {
                PRMSG(1, "Os2Accept: Unable to reconnect server pipe %d\n", ciptr->fd,0,0 );
                }
	return NULL;
        }
	PRMSG(5, "Os2Accept: Bytes to read for name: %d\n",length,0,0 );


/* Check length for valid length ?? */

/* Now read in length bytes from pipe for client pipe name */
    if((in=read(ciptr->fd,clientname,length))<=0){
        PRMSG(2,"Os2Accept: Error reading incoming connection, in=%d, error=%d\n",
	      in,errno,0 );
	*status = TRANS_ACCEPT_MISC_ERROR;
        xfree(newciptr);
        rc = DosDisConnectNPipe(ciptr->fd);
        rc = DosConnectNPipe (ciptr->fd);
        if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED)
        {
                PRMSG(1, "Os2Accept: Unable to reconnect server pipe %d\n", ciptr->fd,0,0 );
                }
	return NULL;
        }
    clientname[length]='\0';
    PRMSG(5, "Os2Accept: Server name %s length %d\n",clientname,length,0 );


/* Now we have the client pipe name. Open it with DosOpen  */

     rc = DosOpen(clientname,&hClient, &action, 0,
	   FILE_NORMAL, FILE_OPEN,
	   OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE,
	   (PEAOP2)NULL);

     PRMSG(5, "Os2Accept: Open pipe %s, handle = %d, rc=%d\n",clientname,hClient,rc );

       if (rc) {
	    PRMSG(1,"Os2Accept: Open pipe %s to client failed, rc=%d\n",
	    clientname,rc,0 );
            PRMSG(1, "\tProbable cause: the client has exited or timed-out.\n",0,0,0 );
            xfree(newciptr);
            rc = DosDisConnectNPipe(ciptr->fd);
            rc = DosConnectNPipe (ciptr->fd);
            if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED)
               {
                   PRMSG(1, "Os2Accept: Unable to reconnect server pipe %d\n", ciptr->fd,0,0 );
                   }
     	    return NULL;
            }

        rc = DosSetNPHState (hClient, NP_NOWAIT | NP_READMODE_BYTE);
        if (rc != 0)
        {
            PRMSG(1,"Os2Accept: Could not set pipe %s to non-blocking mode, rc=%d\n",
	    hClient,rc,0 );
            xfree(newciptr);
            rc = DosDisConnectNPipe(ciptr->fd);
            rc = DosConnectNPipe (ciptr->fd);
            if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED)
               {
                   PRMSG(1, "Os2Accept: Unable to reconnect server pipe %d\n", ciptr->fd,0,0 );
                   }
     	    return NULL;
            }

/* OK, we seem to be well connected to client. Now disconnect server pipe and put again in listen */

         rc = DosDisConnectNPipe(ciptr->fd);
         rc = DosConnectNPipe (ciptr->fd);
	PRMSG(5, "Os2Accept: Reconnecting server pipe %d, rc = %d\n",ciptr->fd,rc,0 );

         if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED)
         {
              PRMSG(1, "Os2Accept: Unable to reconnect server pipe %d\n", ciptr->fd,0,0 );
              }  /* Consider this non-fatal for present connection */
 
/* And finally fill-in info in newciptr */

        namelen=sizeof(struct sockaddr);
        if ((newciptr->addr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2Accept: Can't allocate space for the addr\n",
	        0, 0, 0);
                DosClose(hClient);
                xfree(newciptr);
                return(NULL);
           }

        newciptr->addrlen = namelen;
        ((struct sockaddr *)newciptr->addr)->sa_family = AF_UNIX;
        strcpy (((struct sockaddr *)newciptr->addr)->sa_data, "local");

        if ((newciptr->peeraddr = (char *) xalloc (namelen)) == NULL)
          {
                PRMSG (1, "Os2Accept: Can't allocate space for the addr\n",
	        0, 0, 0);
                DosClose(hClient);
                xfree(ciptr->addr);
                xfree(newciptr);
                return(NULL);
           }

       newciptr->peeraddrlen = namelen;
       ((struct sockaddr *)newciptr->peeraddr)->sa_family = AF_UNIX;
       strcpy (((struct sockaddr *)newciptr->peeraddr)->sa_data, "local");

      PRMSG (5, "Os2Accept: Filled in struct: len %d %d name %s\n",
                newciptr->addrlen,newciptr->peeraddrlen,newciptr->peeraddr);


        newciptr->index=hClient;
        newciptr->family=AF_UNIX;
        if((newciptr->fd=_imphandle(hClient))<0){
           PRMSG(1,"Os2Accept: Could not import pipe %d into EMX, errno=%d\n",
           hClient,errno,0 );
           PRMSG(1, "\tProbable cause: EMX has run out of file handles.\n",0,0,0 );
           DosClose(hClient);
           xfree(newciptr->addr);
           xfree(newciptr->peeraddr);
           xfree(newciptr);
           return(NULL);
           }
    PRMSG(5, "Os2Accept: Pipe handle %d EMX handle %d",newciptr->index,newciptr->fd,0 );

#ifdef XSERV_t
/* Attach the pipe sem to the pipe. Use handle index as key */
    rc = DosSetNPipeSem(newciptr->fd, (HSEM)hPipeSem, newciptr->fd);
    if (rc){
        PRMSG(1, "Os2OpenCOTSServer: Could not attach sem %d to pipe %d, rc=%d\n",
                 hPipeSem,newciptr->fd,rc);
        DosClose(newciptr->fd);
        xfree(newciptr->addr);
        xfree(newciptr->peeraddr);
        xfree(newciptr);
         return(NULL);
        }
#endif

    fcntl(ciptr->fd,F_SETFL,O_NDELAY);
    fcntl(ciptr->fd,F_SETFD,FD_CLOEXEC);
    *status=0;
    return newciptr;
}

#endif /* TRANS_SERVER */

#ifdef TRANS_CLIENT

static
TRANS(Os2Connect)(ciptr, host, port)
XtransConnInfo ciptr;
char *host;
char *port;
{
    PRMSG(2,"Os2Connect(%x->%d,%s)\n", ciptr, ciptr->fd, port);
    return 0;
}

#endif /* TRANS_CLIENT */

static int
TRANS(Os2BytesReadable)(ciptr, pend )
XtransConnInfo ciptr;
BytesReadable_t *pend;
{
   ULONG rc, state, nread;
  AVAILDATA avail;
  char buffer;

  PRMSG(2,"Os2BytesReadable(%x->%d,%x)\n", ciptr, ciptr->fd, pend);

  rc = DosPeekNPipe (ciptr->fd, &buffer, 0, &nread, &avail, &state);
  if (rc != 0)
    {
      errno = EPIPE;
      *pend = 0;
      return -1;
    }
  if (state == NP_STATE_CLOSING)
     {
        errno = EPIPE;
        *pend = 0;
        return -1;
      }
  errno = 0;
  *pend = avail.cbpipe;
  return 0;
}

static int
TRANS(Os2Read)(ciptr, buf, size)
XtransConnInfo ciptr;
char *buf;
int size;
{
    int ret;
    APIRET rc;
    ULONG ulRead;
    PRMSG(2,"Os2Read(%d,%x,%d)\n", ciptr->fd, buf, size );
    errno = 0;
    rc = DosRead(ciptr->fd, buf, size, &ulRead);
    if (rc == 0){
        ret = ulRead;
        }
    else if ((rc == 232) || (rc == 231)){
        errno = EAGAIN;
        ret = -1;
        }
    else if (rc == 6){
        errno = EBADF;
        ret = -1;
        }
     else if ((rc == 109) || (rc == 230) || (rc == 233)){
        errno = EPIPE;
       ret = -1;
        }
    else {
           PRMSG(2,"Os2Read: Unknown return code from DosRead, fd %d rc=%d\n", ciptr->fd,rc,0 );
           errno = EINVAL;
           ret = -1;
           }
    return (ret);
}

static int
TRANS(Os2Write)(ciptr, buf, size)
XtransConnInfo ciptr;
char *buf;
int size;
{
    int ret;
    APIRET rc;
    ULONG nWritten;
    PRMSG(2,"Os2Write(%d,%x,%d)\n", ciptr->fd, buf, size );
    rc = DosWrite(ciptr->fd, buf, size, &nWritten);
    if (rc == 0){
         ret = nWritten;
         if(nWritten == 0) { 
                 errno=EAGAIN;
                 ret = -1;
                 }
         }
    else if ((rc == 39) || (rc == 112)){
        errno = EAGAIN;
        ret = -1;
        }
    else if ((rc == 109) || (rc == 230) || (rc == 233)){
        errno = EPIPE;
        ret = -1;
        }
    else if (rc == 6){
         errno=EBADF;
         ret = -1;
         }
    else {
        PRMSG(2,"(Os2Write)Unknown return code from DosWrite, fd %d rc=%d\n", ciptr->fd,rc,0 );
        errno = EINVAL;
        ret = -1;
        }
    return (ret);
}

static int
TRANS(Os2Readv)(ciptr, buf, size)
XtransConnInfo 	ciptr;
struct iovec 	*buf;
int 		size;
{
    int ret;
    PRMSG(2,"Os2Readv(%d,%x,%d)\n", ciptr->fd, buf, size );
    ret = READV(ciptr,buf,size);
    if ((ret <0) && (errno == EINVAL)) errno = EPIPE;
    return (ret);
}

static int
TRANS(Os2Writev)(ciptr, buf, size)
XtransConnInfo 	ciptr;
struct iovec 	*buf;
int 		size;
{
    int ret;
    PRMSG(2,"Os2Writev(%d,%x,%d)\n", ciptr->fd, buf, size );
    ret = WRITEV(ciptr,buf,size);
    if ((ret <0) && (errno == EINVAL)) errno = EPIPE;
    if ((ret <0) && (errno == ENOSPC)) errno = EAGAIN;
    return (ret);
}

static int
TRANS(Os2Disconnect)(ciptr)
XtransConnInfo ciptr;
{
    PRMSG(2,"Os2Disconnect(%x->%d)\n", ciptr, ciptr->fd, 0);
    return 0;
}

static int
TRANS(Os2Close)(ciptr)
XtransConnInfo ciptr;
{
    int ret;
    PRMSG(2,"Os2Close(%x->%d)\n", ciptr, ciptr->fd ,0);
    ret=close(ciptr->fd);
    return ret;
}

static int
TRANS(Os2CloseForCloning)(ciptr)
XtransConnInfo ciptr;
{
    int ret;

    PRMSG(2,"Os2CloseForCloning(%x->%d)\n", ciptr, ciptr->fd ,0);
    ret=close(ciptr->fd);
    return ret;
}


Xtransport	TRANS(OS2LocalFuncs) = {
	/* Local Interface */
	"local",
	TRANS_LOCAL,
#ifdef TRANS_CLIENT
	TRANS(Os2OpenCOTSClient),
#endif /* TRANS_CLIENT */
#ifdef TRANS_SERVER
	TRANS(Os2OpenCOTSServer),
#endif /* TRANS_SERVER */
#ifdef TRANS_CLIENT
	TRANS(Os2OpenCLTSClient),
#endif /* TRANS_CLIENT */
#ifdef TRANS_SERVER
	TRANS(Os2OpenCLTSServer),
#endif /* TRANS_SERVER */
#ifdef TRANS_REOPEN
	TRANS(Os2ReopenCOTSServer),
	TRANS(Os2ReopenCLTSServer),
#endif
	TRANS(Os2SetOption),
#ifdef TRANS_SERVER
	TRANS(Os2CreateListener),
	NULL,                  /* ResetListener */
	TRANS(Os2Accept),
#endif /* TRANS_SERVER */
#ifdef TRANS_CLIENT
	TRANS(Os2Connect),
#endif /* TRANS_CLIENT */
	TRANS(Os2BytesReadable),
	TRANS(Os2Read),
	TRANS(Os2Write),
	TRANS(Os2Readv),
	TRANS(Os2Writev),
	TRANS(Os2Disconnect),
	TRANS(Os2Close),
	TRANS(Os2CloseForCloning),
};

#ifdef XSERV_t
/* This function is used in the server to initialize the semaphore used with pipes */

BOOL init_server_pipes()
{
   static BOOL first_time=TRUE;
   ULONG rc;

   if(first_time){
        rc = DosCreateEventSem(NULL, &hPipeSem,DC_SEM_SHARED,FALSE);
        if (rc){
           PRMSG(1,"Os2OpenListener (init_server_pipes): Could not create pipe semaphore, rc=%d\n",
                rc,0,0);
           return(FALSE);
           }
     first_time=FALSE;
     }
return(TRUE);
}
#endif  /* XSERV_t */
