#define STDOUT_FILENO 1
#endif
-static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
+static size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
{
-#ifdef PHP_WRITE_STDOUT
- long ret;
-#else
- size_t ret;
-#endif
#if PHP_FASTCGI
if (!FCGX_IsCGI()) {
return ret;
}
#endif
+
#ifdef PHP_WRITE_STDOUT
- ret = write(STDOUT_FILENO, str, str_length);
- if (ret <= 0) return 0;
- return ret;
+ {
+ long ret;
+
+ ret = write(STDOUT_FILENO, str, str_length);
+ if (ret <= 0) return 0;
+ return ret;
+ }
#else
- ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
- return ret;
+ {
+ size_t ret;
+
+ ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
+ return ret;
+ }
#endif
}
static int isFastCGI = -1;
static char *webServerAddressList = NULL;
static FCGX_Request the_request;
-void _FCGX_FreeStream(FCGX_Stream **streamPtr, int freeData);
void FCGX_ShutdownPending(void)
{
*/
int FCGX_GetChar(FCGX_Stream *stream)
{
- if(stream->rdNext != stream->stop)
- return *stream->rdNext++;
- if(stream->isClosed || !stream->isReader)
+ if (stream->isClosed || ! stream->isReader)
return EOF;
+
+ if (stream->rdNext != stream->stop)
+ return *stream->rdNext++;
+
stream->fillBuffProc(stream);
+ if (stream->isClosed)
+ return EOF;
+
stream->stopUnget = stream->rdNext;
- if(stream->rdNext != stream->stop)
+ if (stream->rdNext != stream->stop)
return *stream->rdNext++;
+
ASSERT(stream->isClosed); /* bug in fillBufProc if not */
return EOF;
}
{
int m, bytesMoved;
- if(n <= 0) {
+ if (stream->isClosed || ! stream->isReader || n <= 0) {
return 0;
}
/*
if(bytesMoved == n)
return bytesMoved;
str += m;
- }
+ }
if(stream->isClosed || !stream->isReader)
return bytesMoved;
stream->fillBuffProc(stream);
+ if (stream->isClosed)
+ return bytesMoved;
+
stream->stopUnget = stream->rdNext;
}
}
*/
if(stream->FCGI_errno == 0) {
stream->FCGI_errno = FCGI_errno;
- stream->isClosed = TRUE;
}
+
+ stream->isClosed = TRUE;
}
/*
*/
}
+/*
+ * A vector of pointers representing the parameters received
+ * by a FastCGI application server, with the vector's length
+ * and last valid element so adding new parameters is efficient.
+ */
+typedef struct Params {
+ FCGX_ParamArray vec; /* vector of strings */
+ int length; /* number of string vec can hold */
+ char **cur; /* current item in vec; *cur == NULL */
+} Params;
+typedef Params *ParamsPtr;
/*
*----------------------------------------------------------------------
*----------------------------------------------------------------------
*/
void FCGX_FreeStream(FCGX_Stream **streamPtr)
-{
- _FCGX_FreeStream(streamPtr, TRUE);
-}
-
-void _FCGX_FreeStream(FCGX_Stream **streamPtr, int freeData)
{
FCGX_Stream *stream = *streamPtr;
FCGX_Stream_Data *data;
return;
}
data = (FCGX_Stream_Data *)stream->data;
- if (freeData && data->reqDataPtr) free(data->reqDataPtr);
data->reqDataPtr = NULL;
free(data->mBuff);
free(data);
if (request == NULL)
return;
- _FCGX_FreeStream(&request->in, FALSE);
- _FCGX_FreeStream(&request->out, FALSE);
- _FCGX_FreeStream(&request->err, FALSE);
+ FCGX_FreeStream(&request->in);
+ FCGX_FreeStream(&request->out);
+ FCGX_FreeStream(&request->err);
FreeParams(&request->paramsPtr);
- request->envp = NULL;
if (close) {
- OS_IpcClose(request->ipcFd);
+ OS_IpcClose(request->ipcFd, ! request->detached);
request->ipcFd = -1;
+ request->detached = 0;
}
}
int FCGX_OpenSocket(const char *path, int backlog)
{
- int rc = OS_CreateLocalIpcFd(path, backlog, 1);
+ int rc = OS_CreateLocalIpcFd(path, backlog);
if (rc == FCGI_LISTENSOCK_FILENO && isFastCGI == 0) {
/* XXX probably need to call OS_LibInit() again for Win */
isFastCGI = 1;
data->reqDataPtr->appStatus = status;
}
+
+int
+FCGX_Attach(FCGX_Request * r)
+{
+ r->detached = FALSE;
+ return 0;
+}
+
+
+int
+FCGX_Detach(FCGX_Request * r)
+{
+ if (r->ipcFd <= 0)
+ {
+ return -1;
+ }
+
+ r->detached = TRUE;
+ return 0;
+}
-/* fcgi_config.h. Generated automatically by configure. */
-/* fcgi_config.h.in. Generated automatically from configure.in by autoheader. */
+/*
+ * Copied to fcgi_config.h when building on WinNT without cygwin,
+ * i.e. configure is not run. See fcgi_config.h.in for details.
+ */
-/* Define if you have the <arpa/inet.h> header file. */
-#define HAVE_ARPA_INET_H 1
-
-/* Define if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define if there's a fileno() prototype in stdio.h */
-#define HAVE_FILENO_PROTO 1
-
-/* Define if the fpos_t typedef is in stdio.h */
#define HAVE_FPOS 1
-
-/* Define if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define if you have the `dnet_stub' library (-ldnet_stub). */
-/* #undef HAVE_LIBDNET_STUB */
-
-/* Define if you have the `ieee' library (-lieee). */
-/* #undef HAVE_LIBIEEE */
-
-/* Define if you have the `nsl' library (-lnsl). */
-#define HAVE_LIBNSL 1
-
-/* Define if you have the pthread library */
-#define HAVE_LIBPTHREAD 1
-
-/* Define if you have the `resolv' library (-lresolv). */
-#define HAVE_LIBRESOLV 1
-
-/* Define if you have the `socket' library (-lsocket). */
-#define HAVE_LIBSOCKET 1
-
-/* Define if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
-
-/* Define if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define if you have the <netdb.h> header file. */
-/* #define HAVE_NETDB_H 1 */
-
-/* Define if you have the <netinet/in.h> header file. */
-#define HAVE_NETINET_IN_H 1
-
-/* Define if sockaddr_un in sys/un.h contains a sun_len component */
-/* #undef HAVE_SOCKADDR_UN_SUN_LEN */
-
-/* Define if the socklen_t typedef is in sys/socket.h */
-/* #undef HAVE_SOCKLEN */
-
-/* Define if you have the <stdint.h> header file. */
-/* #undef HAVE_STDINT_H */
-
-/* Define if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define if you have the `strerror' function. */
+#define HAVE_STREAMBUF_CHAR_TYPE 1
#define HAVE_STRERROR 1
-
-/* Define if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define if you have the <sys/param.h> header file. */
-/* #define HAVE_SYS_PARAM_H 1 */
-
-/* Define if you have the <sys/socket.h> header file. */
-/*#define HAVE_SYS_SOCKET_H 1*/
-
-/* Define if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define if you have the <sys/time.h> header file. */
-/*#define HAVE_SYS_TIME_H 1*/
-
-/* Define if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define if you have the <unistd.h> header file. */
-/*#define HAVE_UNISTD_H 1*/
-
-/* Define if va_arg(arg, long double) crashes the compiler */
-/* #undef HAVE_VA_ARG_LONG_DOUBLE_BUG */
-
-/* Name of package */
-#define PACKAGE "fcgi"
-
-/* Define if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define if cross-process locking is required by accept() */
-#define USE_LOCKING 1
-
-/* Version number of package */
-#define VERSION "2.2.2"
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef const */
-
-/* Define as `__inline' if that's what the C compiler calls it, or to nothing
- if it is not supported. */
-/* #undef inline */
-
-/* Define to `int' if <sys/types.h> does not define. */
-#define ssize_t int
\ No newline at end of file
+#undef HAVE_ARPA_INET_H
+#undef HAVE_DLFCN_H
+#undef HAVE_FILENO_PROTO
+#undef HAVE_INTTYPES_H
+#undef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF
+#undef HAVE_LIBNSL
+#undef HAVE_LIBSOCKET
+#undef HAVE_MEMORY_H
+#undef HAVE_NETDB_H
+#undef HAVE_NETINET_IN_H
+#undef HAVE_PTHREAD
+#undef HAVE_SOCKADDR_UN_SUN_LEN
+#undef HAVE_SOCKLEN
+#undef HAVE_STDINT_H
+#undef HAVE_STDLIB_H
+#undef HAVE_STRING_H
+#undef HAVE_STRINGS_H
+#undef HAVE_SYS_PARAM_H
+#undef HAVE_SYS_SOCKET_H
+#undef HAVE_SYS_STAT_H
+#undef HAVE_SYS_TIME_H
+#undef HAVE_SYS_TYPES_H
+#undef HAVE_UNISTD_H
+#undef HAVE_VA_ARG_LONG_DOUBLE_BUG
+#undef PTHREAD_CREATE_JOINABLE
+#undef STDC_HEADERS
+#undef USE_LOCKING
+#undef const
+#undef inline
+#undef ssize_t
#ifndef DLLAPI
#ifdef _WIN32
-#if defined(_LIB) || defined(FCGI_STATIC)
-#define DLLAPI
-#else
#define DLLAPI __declspec(dllimport)
-#endif
#else
#define DLLAPI
#endif
#ifndef DLLAPI
#ifdef _WIN32
-#if defined(_LIB) || defined(FCGI_STATIC)
-#define DLLAPI
-#else
#define DLLAPI __declspec(dllimport)
-#endif
#else
#define DLLAPI
#endif
*/
typedef char **FCGX_ParamArray;
-/*
- * A vector of pointers representing the parameters received
- * by a FastCGI application server, with the vector's length
- * and last valid element so adding new parameters is efficient.
- */
-
-typedef struct Params {
- FCGX_ParamArray vec; /* vector of strings */
- int length; /* number of string vec can hold */
- char **cur; /* current item in vec; *cur == NULL */
-} Params;
-typedef Params *ParamsPtr;
-
/*
* FCGX_Request Flags
*
FCGX_Stream *in;
FCGX_Stream *out;
FCGX_Stream *err;
- FCGX_ParamArray envp;
+ char **envp;
- /* Don't use anything below here */
+ /* Don't use anything below here */
- ParamsPtr paramsPtr;
+ struct Params *paramsPtr;
int ipcFd; /* < 0 means no connection */
int isBeginProcessed; /* FCGI_BEGIN_REQUEST seen */
int keepConnection; /* don't close ipcFd at end of request */
int appStatus;
int nWriters; /* number of open writers (0..2) */
- int flags;
- int listen_sock;
+ int flags;
+ int listen_sock;
+ int detached;
} FCGX_Request;
\f
*/
DLLAPI void FCGX_ShutdownPending(void);
+
+/*
+ * Attach/Detach an accepted request from its listen socket.
+ * XXX This is not fully implemented at this time (patch welcome).
+ */
+DLLAPI int FCGX_Attach(FCGX_Request * r);
+DLLAPI int FCGX_Detach(FCGX_Request * r);
+
+
#if defined (__cplusplus) || defined (c_plusplus)
} /* terminate extern "C" { */
#endif
#ifndef FCGIO_H
#define FCGIO_H
-#include <iostream.h>
+#include <iostream>
#include "fcgiapp.h"
#endif
#endif
+#if ! HAVE_STREAMBUF_CHAR_TYPE
+typedef char char_type;
+#endif
+
/*
* fcgi_streambuf
*/
-class fcgi_streambuf : public streambuf
+class DLLAPI fcgi_streambuf : public std::streambuf
{
public:
// assigned, I/O is a bit less effecient and output streams will
// have to be flushed (or the streambuf destroyed) before the next
// call to "accept".
- DLLAPI fcgi_streambuf(FCGX_Stream * fcgx, char * buf, int len);
+ fcgi_streambuf(FCGX_Stream * fcgx, char * buf, int len);
- DLLAPI fcgi_streambuf(char * buf, int len);
+ fcgi_streambuf(char_type * buf, std::streamsize len);
- DLLAPI fcgi_streambuf(FCGX_Stream * fcgx = NULL);
+ fcgi_streambuf(FCGX_Stream * fcgx = 0);
- DLLAPI ~fcgi_streambuf(void);
+ ~fcgi_streambuf(void);
- DLLAPI int attach(FCGX_Stream * fcgx);
+ int attach(FCGX_Stream * fcgx);
protected:
// Consume the put area (if buffered) and c (if c is not EOF).
- DLLAPI virtual int overflow(int);
+ virtual int overflow(int);
// Flush the put area (if buffered) and the FCGX buffer to the client.
- DLLAPI virtual int sync();
+ virtual int sync();
// Remove and return the current character.
- DLLAPI virtual int uflow();
+ virtual int uflow();
// Fill the get area (if buffered) and return the current character.
- DLLAPI virtual int underflow();
+ virtual int underflow();
// Use a buffer. The only reasons that a buffer would be useful is
// to support the use of the unget()/putback() or seek() methods. Using
// a buffer will result in less efficient I/O. Note: the underlying
// FastCGI library (FCGX) maintains its own input and output buffers.
- DLLAPI virtual streambuf * setbuf(char * buf, int len);
+ virtual std::streambuf * setbuf(char_type * buf, std::streamsize len);
- DLLAPI virtual int xsgetn(char * s, int n);
- DLLAPI virtual int xsputn(const char * s, int n);
+ virtual std::streamsize xsgetn(char_type * s, std::streamsize n);
+ virtual std::streamsize xsputn(const char_type * s, std::streamsize n);
private:
FCGX_Stream * fcgx;
// buf is just handy to have around
- char * buf;
+ char_type * buf;
// this isn't kept by the base class
- int bufsize;
+ std::streamsize bufsize;
- void init(FCGX_Stream * fcgx, char * buf, int bufsize);
+ void init(FCGX_Stream * fcgx, char_type * buf, std::streamsize bufsize);
void reset(void);
};
/*
* fcgi_istream - deprecated
*/
-class fcgi_istream : public istream
+class DLLAPI fcgi_istream : public std::istream
{
public:
// deprecated
- DLLAPI fcgi_istream(FCGX_Stream * fcgx = NULL);
+ fcgi_istream(FCGX_Stream * fcgx = 0);
// deprecated
- DLLAPI ~fcgi_istream(void) {}
+ ~fcgi_istream(void) {}
// deprecated
- DLLAPI virtual void attach(FCGX_Stream * fcgx);
+ virtual void attach(FCGX_Stream * fcgx);
private:
/*
* fcgi_ostream - deprecated
*/
-class fcgi_ostream : public ostream
+class DLLAPI fcgi_ostream : public std::ostream
{
public:
// deprecated
- DLLAPI fcgi_ostream(FCGX_Stream * fcgx = NULL);
+ fcgi_ostream(FCGX_Stream * fcgx = 0);
// deprecated
- DLLAPI ~fcgi_ostream(void) {}
+ ~fcgi_ostream(void) {}
// deprecated
- DLLAPI virtual void attach(FCGX_Stream *fcgx);
+ virtual void attach(FCGX_Stream *fcgx);
private:
#include <sys/time.h>
#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
#if defined (c_plusplus) || defined (__cplusplus)
extern "C" {
#endif
#ifndef DLLAPI
#ifdef _WIN32
-#if defined(_LIB) || defined(FCGI_STATIC)
-#define DLLAPI
-#else
#define DLLAPI __declspec(dllimport)
-#endif
#else
#define DLLAPI
#endif
# endif /* __STDC__ */
#define _CLIENTDATA
#endif
-#define MUTEX_VARNAME "_FCGI_MUTEX_"
-#define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_"
typedef void (*OS_AsyncProc) (ClientData clientData, int len);
DLLAPI int OS_LibInit(int stdioFds[3]);
DLLAPI void OS_LibShutdown(void);
-DLLAPI int OS_CreateLocalIpcFd(const char *bindPath, int backlog, int bCreateMutex);
+DLLAPI int OS_CreateLocalIpcFd(const char *bindPath, int backlog);
DLLAPI int OS_FcgiConnect(char *bindPath);
DLLAPI int OS_Read(int fd, char * buf, size_t len);
DLLAPI int OS_Write(int fd, char * buf, size_t len);
#ifdef _WIN32
-DLLAPI int OS_SpawnChild(char *execPath, int listenFd, PROCESS_INFORMATION *pInfo, char *env);
+DLLAPI int OS_SpawnChild(char *execPath, int listenFd, PROCESS_INFORMATION *, char *);
#else
-DLLAPI int OS_SpawnChild(char *execPath, int listenfd);
+DLLAPI int OS_SpawnChild(char *execPath, int listenFd);
#endif
DLLAPI int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
- ClientData clientData);
+ ClientData clientData);
DLLAPI int OS_AsyncRead(int fd, int offset, void *buf, int len,
- OS_AsyncProc procPtr, ClientData clientData);
+ OS_AsyncProc procPtr, ClientData clientData);
DLLAPI int OS_AsyncWrite(int fd, int offset, void *buf, int len,
- OS_AsyncProc procPtr, ClientData clientData);
-DLLAPI int OS_Close(int fd);
+ OS_AsyncProc procPtr, ClientData clientData);
+DLLAPI int OS_Close(int fd, int shutdown);
DLLAPI int OS_CloseRead(int fd);
DLLAPI int OS_DoIo(struct timeval *tmo);
DLLAPI int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs);
-DLLAPI int OS_IpcClose(int ipcFd);
+DLLAPI int OS_IpcClose(int ipcFd, int shutdown);
DLLAPI int OS_IsFcgi(int sock);
DLLAPI void OS_SetFlags(int fd, int flags);
*
*----------------------------------------------------------------------
*/
-int OS_CreateLocalIpcFd(const char *bindPath, int backlog, int bCreateMutex)
+int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
{
int listenSock, servLen;
- union SockAddrUnion sa;
+ union SockAddrUnion sa;
int tcp = FALSE;
unsigned long tcp_ia = 0;
char *tp;
if(fd > maxFd)
maxFd = fd;
- if(index >= asyncIoTableSize) {
+ while (index >= asyncIoTableSize) {
GrowAsyncTable();
}
if(fd > maxFd)
maxFd = fd;
- if(index >= asyncIoTableSize) {
+ while (index >= asyncIoTableSize) {
GrowAsyncTable();
}
*
*--------------------------------------------------------------
*/
-int OS_Close(int fd)
+int OS_Close(int fd, int shutdown_ok)
{
if (fd == -1)
return 0;
maxFd--;
}
}
+
+ /*
+ * shutdown() the send side and then read() from client until EOF
+ * or a timeout expires. This is done to minimize the potential
+ * that a TCP RST will be sent by our TCP stack in response to
+ * receipt of additional data from the client. The RST would
+ * cause the client to discard potentially useful response data.
+ */
+
+ if (shutdown_ok)
+ {
+ if (shutdown(fd, 1) == 0)
+ {
+ struct timeval tv;
+ fd_set rfds;
+ int rv;
+ char trash[1024];
+
+ FD_ZERO(&rfds);
+
+ do
+ {
+ FD_SET(fd, &rfds);
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ rv = select(fd + 1, &rfds, NULL, NULL, &tv);
+ }
+ while (rv > 0 && read(fd, trash, sizeof(trash)) > 0);
+ }
+ }
+
return close(fd);
}
*
*----------------------------------------------------------------------
*/
-int OS_IpcClose(int ipcFd)
+int OS_IpcClose(int ipcFd, int shutdown)
{
- return OS_Close(ipcFd);
+ return OS_Close(ipcFd, shutdown);
}
/*
#include <assert.h>
#include <stdio.h>
#include <sys/timeb.h>
+#include <process.h>
#define DLLAPI __declspec(dllexport)
*/
#define ACCEPT_TIMEOUT 1000
+#define MUTEX_VARNAME "_FCGI_MUTEX_"
+#define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_"
#define LOCALHOST "localhost"
static HANDLE hIoCompPort = INVALID_HANDLE_VALUE;
static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE};
+// This is a nail for listening to more than one port..
static HANDLE acceptMutex = INVALID_HANDLE_VALUE;
static BOOLEAN shutdownPending = FALSE;
// XXX This should be a DESCRIPTOR
static HANDLE hListen = INVALID_HANDLE_VALUE;
-static OVERLAPPED listenOverlapped;
static BOOLEAN libInitialized = FALSE;
/*
*
*--------------------------------------------------------------
*/
-static void StdinThread(LPDWORD startup){
-
+static void StdinThread(void * startup)
+{
int doIo = TRUE;
unsigned long fd;
unsigned long bytesRead;
shutdownPending = TRUE;
}
-/* XXX Need a shutdown now event */
-static DWORD WINAPI ShutdownRequestThread(LPVOID arg)
+static void ShutdownRequestThread(void * arg)
{
HANDLE shutdownEvent = (HANDLE) arg;
+
WaitForSingleObject(shutdownEvent, INFINITE);
+
shutdownPending = TRUE;
- // Before an accept() is entered the shutdownPending flag is checked.
- // If set, OS_Accept() will return -1. If not, it waits
- // on a connection request for one second, checks the flag, & repeats.
- // Only one process/thread is allowed to do this at time by
- // wrapping the accept() with mutex.
- return 0;
+
+ if (listenType == FD_PIPE_SYNC)
+ {
+ // Its a hassle to get ConnectNamedPipe to return early,
+ // so just wack the whole process - yes, this will toast
+ // any requests in progress, but at least its a clean
+ // shutdown (its better than TerminateProcess())
+ exit(0);
+ }
+
+ // FD_SOCKET_SYNC: When in Accept(), select() is used to poll
+ // the shutdownPending flag - yeah this isn't pretty either
+ // but its only one process doing it if an Accept mutex is used.
+ // This at least buys no toasted requests.
}
+/*
+ */
int OS_SetImpersonate(void)
{
char *os_name = NULL;
WSADATA wsaData;
int err;
int fakeFd;
- DWORD threadId;
char *cLenPtr = NULL;
char *val = NULL;
{
HANDLE shutdownEvent = (HANDLE) atoi(val);
- if (! CreateThread(NULL, 0, ShutdownRequestThread,
- shutdownEvent, 0, NULL))
+ if (_beginthread(ShutdownRequestThread, 0, shutdownEvent) == -1)
{
return -1;
}
}
- /*
- * If an accept mutex is in the env, save it and remove it.
- */
- val = getenv(MUTEX_VARNAME);
- if (val != NULL)
+ if (acceptMutex == INVALID_HANDLE_VALUE)
{
- acceptMutex = (HANDLE) atoi(val);
+ /* If an accept mutex is in the env, use it */
+ val = getenv(MUTEX_VARNAME);
+ if (val != NULL)
+ {
+ acceptMutex = (HANDLE) atoi(val);
+ }
}
-
/*
* Determine if this library is being used to listen for FastCGI
* connections. This is communicated by STDIN containing a
if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL))
{
listenType = FD_PIPE_SYNC;
- listenOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
else
{
DebugBreak();
exit(99);
*/
- return -1;
}
if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
*/
if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL &&
atoi(cLenPtr) > 0) {
- hStdinThread = CreateThread(NULL, 8192,
- (LPTHREAD_START_ROUTINE)&StdinThread,
- NULL, 0, &threadId);
- if (hStdinThread == NULL) {
+ hStdinThread = (HANDLE) _beginthread(StdinThread, 0, NULL);
+ if (hStdinThread == (HANDLE) -1) {
printf("<H2>OS_LibInit Failed to create STDIN thread! ERROR: %d</H2>\r\n\r\n",
GetLastError());
return -1;
if (acceptMutex != INVALID_HANDLE_VALUE)
{
ReleaseMutex(acceptMutex);
- CloseHandle(acceptMutex);
}
/* we only want to do this if we're not a web server */
if (bImpersonate) RevertToSelf();
}
- DeleteCriticalSection(&fdTableCritical);
WSACleanup();
}
{
case FD_FILE_SYNC:
case FD_FILE_ASYNC:
-
+
/* Free file path string */
ASSERT(fdTable[fd].path != NULL);
-
free(fdTable[fd].path);
fdTable[fd].path = NULL;
break;
- case FD_PIPE_ASYNC:
- break;
+
default:
break;
}
*
*----------------------------------------------------------------------
*/
-int OS_CreateLocalIpcFd(const char *bindPath, int backlog, int bCreateMutex)
+int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
{
int pseudoFd = -1;
short port = getPort(bindPath);
- HANDLE mutex = INVALID_HANDLE_VALUE;
- char mutexEnvString[100];
- if (bCreateMutex) {
- mutex = CreateMutex(NULL, FALSE, NULL);
- if (! SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE))
- {
- CloseHandle(mutex);
- return -3;
- }
- // This is a nail for listening to more than one port..
- // This should really be handled by the caller.
- _snprintf(mutexEnvString, sizeof(mutexEnvString)-1, MUTEX_VARNAME "=%d", (int) mutex);
- putenv(mutexEnvString);
- }
+ if (acceptMutex == INVALID_HANDLE_VALUE)
+ {
+ acceptMutex = CreateMutex(NULL, FALSE, NULL);
+ if (acceptMutex == NULL) return -2;
+ if (! SetHandleInformation(acceptMutex, HANDLE_FLAG_INHERIT, TRUE)) return -3;
+ }
// There's nothing to be gained (at the moment) by a shutdown Event
"You should either use \"localhost:<port>\" or "
" just use \":<port>.\"\n");
//exit(1);
- if (bCreateMutex) CloseHandle(mutexEnvString);
return -1;
}
listenSock = socket(AF_INET, SOCK_STREAM, 0);
if (listenSock == INVALID_SOCKET)
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
return -4;
}
if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen) )
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
return -12;
}
if (listen(listenSock, backlog))
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
return -5;
}
if (pseudoFd == -1)
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
closesocket(listenSock);
return -6;
}
if (! pipePath)
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
return -7;
}
}
hListenPipe = CreateNamedPipe(pipePath,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
PIPE_UNLIMITED_INSTANCES,
4096, 4096, 0, bImpersonate?&sa:NULL);
if (hListenPipe == INVALID_HANDLE_VALUE)
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
return -8;
}
if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE))
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
return -9;
}
if (pseudoFd == -1)
{
- if (bCreateMutex)CloseHandle(mutexEnvString);
CloseHandle(hListenPipe);
return -10;
}
else
{
fdTable[fd].Errno = GetLastError();
- ret = -1;
}
break;
StartupInfo.lpReserved2 = NULL;
StartupInfo.cbReserved2 = 0;
StartupInfo.lpDesktop = NULL;
- StartupInfo.wShowWindow = SW_HIDE;
/*
* FastCGI on NT will set the listener pipe HANDLE in the stdin of
* the new process. The fact that there is a stdin and NULL handles
* for stdout and stderr tells the FastCGI process that this is a
* FastCGI process and not a CGI process.
*/
- StartupInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ StartupInfo.dwFlags = STARTF_USESTDHANDLES;
/*
* XXX: Do I have to dup the handle before spawning the process or is
* it sufficient to use the handle as it's reference counted
*
*--------------------------------------------------------------
*/
-int OS_Close(int fd)
+int OS_Close(int fd, int shutdown_ok)
{
int ret = 0;
case FD_PIPE_ASYNC:
case FD_FILE_SYNC:
case FD_FILE_ASYNC:
- /*
- * CloseHandle returns: TRUE success, 0 failure
- */
- /*
- XXX don't close here, fcgi apps fail if we do so
- need to examine resource leaks if any might exist
- if (CloseHandle(fdTable[fd].fid.fileHandle) == FALSE)
- ret = -1;
- */
+
break;
+
case FD_SOCKET_SYNC:
- case FD_SOCKET_ASYNC:
- /*
- * Closing a socket that has an async read outstanding causes a
- * tcp reset and possible data loss. The shutdown call seems to
- * prevent this.
- */
+ case FD_SOCKET_ASYNC:
- /* shutdown(fdTable[fd].fid.sock, SD_BOTH); */
+ /*
+ * shutdown() the send side and then read() from client until EOF
+ * or a timeout expires. This is done to minimize the potential
+ * that a TCP RST will be sent by our TCP stack in response to
+ * receipt of additional data from the client. The RST would
+ * cause the client to discard potentially useful response data.
+ */
+ if (shutdown_ok)
{
- char buf[16];
- int r;
+ if (shutdown(fdTable[fd].fid.sock, SD_SEND) == 0)
+ {
+ struct timeval tv;
+ fd_set rfds;
+ int sock = fdTable[fd].fid.sock;
+ int rv;
+ char trash[1024];
- shutdown(fdTable[fd].fid.sock,SD_SEND);
+ FD_ZERO(&rfds);
+
+ do
+ {
+#pragma warning( disable : 4127 )
+ FD_SET((unsigned) sock, &rfds);
+#pragma warning( default : 4127 )
- do
- {
- r = recv(fdTable[fd].fid.sock,buf,16,0);
- } while (r > 0);
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ rv = select(sock + 1, &rfds, NULL, NULL, &tv);
+ }
+ while (rv > 0 && recv(sock, trash, sizeof(trash), 0) > 0);
+ }
}
- /*
- * closesocket returns: 0 success, SOCKET_ERROR failure
- */
- if (closesocket(fdTable[fd].fid.sock) == SOCKET_ERROR)
- ret = -1;
- break;
- default:
- return -1; /* fake failure */
+
+ closesocket(fdTable[fd].fid.sock);
+
+ break;
+
+ default:
+
+ ret = -1; /* fake failure */
}
Win32FreeDescriptor(fd);
}
#endif
-static printLastError(const char * text)
+static void printLastError(const char * text)
{
LPVOID buf;
{
int ipcFd = -1;
- if (! ConnectNamedPipe(hListen, &listenOverlapped))
+ if (! ConnectNamedPipe(hListen, NULL))
{
switch (GetLastError())
{
case ERROR_IO_PENDING:
- // Wait for a connection to complete.
-
- while (WaitForSingleObject(listenOverlapped.hEvent,
- ACCEPT_TIMEOUT) == WAIT_TIMEOUT)
- {
- if (shutdownPending)
- {
- OS_LibShutdown();
- return -1;
- }
- }
-
- break;
+ // The NamedPipe was opened with an Overlapped structure
+ // and there is a pending io operation. mod_fastcgi
+ // did this in 2.2.12 (fcgi_pm.c v1.52).
case ERROR_PIPE_LISTENING:
fd_set readfds;
FD_ZERO(&readfds);
+
+#pragma warning( disable : 4127 )
FD_SET((unsigned int) hListen, &readfds);
+#pragma warning( default : 4127 )
if (select(0, &readfds, NULL, NULL, &timeout) == 0)
{
if (acceptMutex != INVALID_HANDLE_VALUE)
{
DWORD ret;
+#if YOU_WANT_TO_MAKE_THE_PROCESS_HANG_AFTER_FIRST_REQUEST
while ((ret = WaitForSingleObject(acceptMutex, ACCEPT_TIMEOUT)) == WAIT_TIMEOUT)
{
if (shutdownPending) break;
}
if (ret == WAIT_FAILED) {
+#else
+ if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) {
+#endif
printLastError("WaitForSingleObject() failed");
return -1;
}
*
*----------------------------------------------------------------------
*/
-int OS_IpcClose(int ipcFd)
+int OS_IpcClose(int ipcFd, int shutdown)
{
- if (ipcFd == -1)
- return 0;
+ if (ipcFd == -1) return 0;
/*
* Catch it if fd is a bogus value
ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX));
ASSERT(fdTable[ipcFd].type != FD_UNUSED);
- switch(listenType) {
-
+ switch (listenType)
+ {
case FD_PIPE_SYNC:
- /*
- * Make sure that the client (ie. a Web Server in this case) has
- * read all data from the pipe before we disconnect.
- */
- if(!FlushFileBuffers(fdTable[ipcFd].fid.fileHandle))
- return -1;
- if(DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) {
- OS_Close(ipcFd);
- if (bImpersonate) RevertToSelf();
- return 0;
- } else {
- return -1;
- }
- break;
+ /*
+ * Make sure that the client (ie. a Web Server in this case) has
+ * read all data from the pipe before we disconnect.
+ */
+ if (! FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) return -1;
+ if (! DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) return -1;
+
+ if (bImpersonate) RevertToSelf();
+
+ /* fall through */
case FD_SOCKET_SYNC:
- OS_Close(ipcFd);
- return 0;
- break;
+
+ OS_Close(ipcFd, shutdown);
+ break;
case FD_UNUSED:
default:
- //exit(106);
- return -1;
- break;
+ return -1;
+ break;
}
- return -1;
+
+ return 0;
}
/*