APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout) { apr_status_t rv = APR_SUCCESS; if (thepipe->pipe == 1) { thepipe->timeout = timeout; if (thepipe->timeout >= 0) { if (thepipe->blocking != BLK_OFF) { thepipe->blocking = BLK_OFF; return APR_FROM_OS_ERROR(DosSetNPHState(thepipe->filedes, NP_NOWAIT)); } } else if (thepipe->timeout == -1) { if (thepipe->blocking != BLK_ON) { thepipe->blocking = BLK_ON; return APR_FROM_OS_ERROR(DosSetNPHState(thepipe->filedes, NP_WAIT)); } } } else { rv = APR_EINVAL; } return rv; }
APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, apr_file_t **out, apr_pool_t *pool) { ULONG filedes[2]; ULONG rc, action; static int id = 0; char pipename[50]; sprintf(pipename, "/pipe/%d.%d", getpid(), id++); rc = DosCreateNPipe(pipename, filedes, NP_ACCESS_INBOUND, NP_NOWAIT|1, 4096, 4096, 0); if (rc) return APR_FROM_OS_ERROR(rc); rc = DosConnectNPipe(filedes[0]); if (rc && rc != ERROR_PIPE_NOT_CONNECTED) { DosClose(filedes[0]); return APR_FROM_OS_ERROR(rc); } rc = DosOpen (pipename, filedes+1, &action, 0, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL); if (rc) { DosClose(filedes[0]); return APR_FROM_OS_ERROR(rc); } (*in) = (apr_file_t *)apr_palloc(pool, sizeof(apr_file_t)); rc = DosCreateEventSem(NULL, &(*in)->pipeSem, DC_SEM_SHARED, FALSE); if (rc) { DosClose(filedes[0]); DosClose(filedes[1]); return APR_FROM_OS_ERROR(rc); } rc = DosSetNPipeSem(filedes[0], (HSEM)(*in)->pipeSem, 1); if (!rc) { rc = DosSetNPHState(filedes[0], NP_WAIT); } if (rc) { DosClose(filedes[0]); DosClose(filedes[1]); DosCloseEventSem((*in)->pipeSem); return APR_FROM_OS_ERROR(rc); } (*in)->pool = pool; (*in)->filedes = filedes[0]; (*in)->fname = apr_pstrdup(pool, pipename); (*in)->isopen = TRUE; (*in)->buffered = FALSE; (*in)->flags = APR_FOPEN_READ; (*in)->pipe = 1; (*in)->timeout = -1; (*in)->blocking = BLK_ON; (*in)->ungetchar = -1; apr_pool_cleanup_register(pool, *in, apr_file_cleanup, apr_pool_cleanup_null); (*out) = (apr_file_t *)apr_palloc(pool, sizeof(apr_file_t)); rc = DosCreateEventSem(NULL, &(*out)->pipeSem, DC_SEM_SHARED, FALSE); if (rc) { DosClose(filedes[0]); DosClose(filedes[1]); DosCloseEventSem((*in)->pipeSem); return APR_FROM_OS_ERROR(rc); } rc = DosSetNPipeSem(filedes[1], (HSEM)(*out)->pipeSem, 1); if (rc) { DosClose(filedes[0]); DosClose(filedes[1]); DosCloseEventSem((*in)->pipeSem); DosCloseEventSem((*out)->pipeSem); return APR_FROM_OS_ERROR(rc); } (*out)->pool = pool; (*out)->filedes = filedes[1]; (*out)->fname = apr_pstrdup(pool, pipename); (*out)->isopen = TRUE; (*out)->buffered = FALSE; (*out)->flags = APR_FOPEN_WRITE; (*out)->pipe = 1; (*out)->timeout = -1; (*out)->blocking = BLK_ON; (*out)->ungetchar = -1; apr_pool_cleanup_register(pool, *out, apr_file_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; }
static void ProcessConnection( void ) { char buff[MAX_TRANS]; ULONG bytes_read; unsigned long max; struct _AVAILDATA BytesAvail; ULONG PipeState; APIRET rc; RESULTCODES res; PID dummy; char *dir; for( ;; ) { DosRead( LnkHdl, buff, sizeof( buff ), &bytes_read ); if( bytes_read == 0 ) break; buff[bytes_read] = '\0'; switch( buff[0] ) { case LNK_CWD: rc = 0; dir = &buff[1]; if( isalpha( dir[0] ) && dir[1] == ':' ) { rc = DosSetDefaultDisk( toupper( dir[0] ) - ('A' - 1) ); dir += 2; } if( rc == 0 && dir[0] != '\0' ) { rc = DosSetCurrentDir( dir ); } SendStatus( rc ); break; case LNK_RUN: DosSetNPHState( RedirHdl, NP_NOWAIT | NP_READMODE_BYTE ); DosConnectNPipe( RedirHdl ); DosSetNPHState( RedirHdl, NP_WAIT | NP_READMODE_BYTE ); RunCmd( &buff[1] ); break; case LNK_QUERY: max = *(unsigned long *)&buff[1]; if( max > sizeof( buff ) ) max = sizeof( buff ); --max; rc = DosPeekNPipe(RedirHdl, buff, 0, &bytes_read, &BytesAvail, &PipeState ); if( rc == 0 && BytesAvail.cbpipe != 0 ) { DosRead( RedirHdl, &buff[1], max, &bytes_read ); buff[0] = LNK_OUTPUT; DosWrite( LnkHdl, buff, bytes_read + 1, &bytes_read ); } else { rc = DosWaitChild( DCWA_PROCESS, DCWW_NOWAIT, &res, &dummy, ProcId ); if( rc != ERROR_CHILD_NOT_COMPLETE ) { DosDisConnectNPipe( RedirHdl ); SendStatus( res.codeResult ); ProcId = 0; } else { /* let someone else run */ DosSleep( 1 ); buff[0] = LNK_NOP; DosWrite( LnkHdl, buff, 1, &bytes_read ); } } break; case LNK_CANCEL: DosSendSignalException( ProcId, XCPT_SIGNAL_INTR ); break; case LNK_ABORT: DosKillProcess( DKP_PROCESSTREE, ProcId ); break; case LNK_DONE: return; case LNK_SHUTDOWN: exit( 0 ); break; } } }
static int CreatePipeChild(PID& pid, HPIPE& hfPipe, char *Command) { static int PCount = 0; char szPipe[32]; char FailBuf[256]; char *Args; int arglen = 0; char *Prog; RESULTCODES rc_code; ULONG ulAction; // ULONG ulNew; HPIPE hfChildPipe; HFILE hfNewStdOut = (HFILE)-1, hfNewStdErr = (HFILE)-1; HFILE hfStdOut = 1, hfStdErr = 2; int rc; sprintf(szPipe, "\\PIPE\\eFTE%d\\CHILD%d", getpid(), PCount); PCount++; rc = DosCreateNPipe(szPipe, &hfPipe, NP_NOINHERIT | NP_ACCESS_INBOUND, NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE | 1, 0, 4096, 0); if (rc != 0) return -1; rc = DosConnectNPipe(hfPipe); if ((rc != 0) && (rc != ERROR_PIPE_NOT_CONNECTED)) { DosClose(hfPipe); return -1; } rc = DosSetNPHState(hfPipe, NP_WAIT | NP_READMODE_BYTE); if (rc != 0) { DosClose(hfPipe); return -1; } rc = DosOpen(szPipe, &hfChildPipe, &ulAction, 0, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL); if (rc != 0) { DosClose(hfPipe); return -1; } // Duplicate handles DosDupHandle(hfStdOut, &hfNewStdOut); DosDupHandle(hfStdErr, &hfNewStdErr); // Close existing handles for current process DosClose(hfStdOut); DosClose(hfStdErr); // Redirect existing handles to new file DosDupHandle(hfChildPipe, &hfStdOut); DosDupHandle(hfChildPipe, &hfStdErr); // Let started program inherit handles from parent Prog = getenv("COMSPEC"); Args = (char *)malloc(strlen(Prog) + 1 + 3 + strlen(Command) + 1 + 1); if (Args == NULL) { DosClose(hfPipe); return -1; } strcpy(Args, Prog); arglen = strlen(Args) + 1; strcpy(Args + arglen, "/c "); arglen += 3; strcpy(Args + arglen, Command); arglen += strlen(Command) + 1; Args[arglen] = '\0'; rc = DosExecPgm(FailBuf, sizeof(FailBuf), EXEC_ASYNCRESULT, // | EXEC_BACKGROUND, Args, 0, &rc_code, Prog); free(Args); // Get back original handles DosDupHandle(hfNewStdOut, &hfStdOut); DosDupHandle(hfNewStdErr, &hfStdErr); // Close the duplicated handles - no longer needed DosClose(hfNewStdOut); DosClose(hfNewStdErr); DosClose(hfChildPipe); // pipe one way, close out write end if (rc != 0) { DosClose(hfPipe); return -1; } pid = rc_code.codeTerminate; // get pid when successful return 0; }
static XtransConnInfo TRANS(Os2Accept)(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; }