63#include <sys/resource.h>
64#include <sys/socket.h>
74#include <netinet/in.h>
75#include <netinet/tcp.h>
77#include <php_config.h>
85#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
86 || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
87#include <sys/sysctl.h>
92#define uint32 uint32_t
100 unsigned char in[64];
114#define LSAPI_ST_REQ_HEADER 1
115#define LSAPI_ST_REQ_BODY 2
116#define LSAPI_ST_RESP_HEADER 4
117#define LSAPI_ST_RESP_BODY 8
118#define LSAPI_ST_BACKGROUND 16
120#define LSAPI_RESP_BUF_SIZE 8192
121#define LSAPI_INIT_RESP_HEADER_LEN 4096
148static int g_inited = 0;
149static int g_running = 1;
151static int s_restored_ppid = 0;
153static int s_slow_req_msecs = 0;
154static int s_keep_listener = 1;
155static int s_dump_debug_info = 0;
156static int s_pid_dump_debug_info = 0;
157static int s_req_processed = 0;
158static int s_skip_write = 0;
159static int (*pthread_atfork_func)(
void (*prepare)(
void),
void (*parent)(
void),
162static int *s_busy_workers =
NULL;
163static int *s_accepting_workers =
NULL;
164static int *s_global_counter = &s_req_processed;
165static int s_max_busy_workers = -1;
166static char *s_stderr_log_path =
NULL;
167static int s_stderr_is_pipe = 0;
168static int s_ignore_pid = -1;
169static size_t s_total_pages = 1;
170static size_t s_min_avail_pages = 256 * 1024;
171static size_t *s_avail_pages = &s_total_pages;
174{ .m_fdListen = -1, .m_fd = -1 };
176static char s_secret[24];
181static int lsapi_reopen_stderr(
const char *
p);
185 "HTTP_ACCEPT",
"HTTP_ACCEPT_CHARSET",
186 "HTTP_ACCEPT_ENCODING",
187 "HTTP_ACCEPT_LANGUAGE",
"HTTP_AUTHORIZATION",
188 "HTTP_CONNECTION",
"CONTENT_TYPE",
189 "CONTENT_LENGTH",
"HTTP_COOKIE",
"HTTP_COOKIE2",
190 "HTTP_HOST",
"HTTP_PRAGMA",
191 "HTTP_REFERER",
"HTTP_USER_AGENT",
192 "HTTP_CACHE_CONTROL",
193 "HTTP_IF_MODIFIED_SINCE",
"HTTP_IF_MATCH",
194 "HTTP_IF_NONE_MATCH",
196 "HTTP_IF_UNMODIFIED_SINCE",
199 "HTTP_X_FORWARDED_FOR",
201 "HTTP_TRANSFER_ENCODING"
205{ 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18,
206 22, 13, 18, 13, 24, 15, 10, 20, 8, 22 };
211 "Accept",
"Accept-Charset",
213 "Accept-Language",
"Authorization",
214 "Connection",
"Content-Type",
215 "Content-Length",
"Cookie",
"Cookie2",
217 "Referer",
"User-Agent",
219 "If-Modified-Since",
"If-Match",
222 "If-Unmodified-Since",
231{ 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10,
232 13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17
236static const char *s_log_level_names[8] =
238 "",
"DEBUG",
"INFO",
"NOTICE",
"WARN",
"ERROR",
"CRIT",
"FATAL"
247 && !(s_stderr_is_pipe))
252 localtime_r(&
tv.tv_sec, &tm);
255 p +=
snprintf(
p, 1024,
"%04d-%02d-%02d %02d:%02d:%02d.%06d ",
256 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
257 tm.tm_hour, tm.tm_min, tm.tm_sec, (
int)
tv.tv_usec);
262 tm.tm_hour, tm.tm_min, tm.tm_sec);
269 p +=
snprintf(
p, 100,
"[%s] ", s_log_level_names[level]);
274 p +=
snprintf(
p, 100,
"[UID:%d][%d] ", getuid(), s_pid);
287#define DBGLOG_FLAG (LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_FLAG_DEBUG|LSAPI_LOG_PID)
288#define lsapi_dbg(...) LSAPI_Log(DBGLOG_FLAG, __VA_ARGS__)
292#define lsapi_dbg(...)
296#define lsapi_log(...) LSAPI_Log(LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_PID, __VA_ARGS__)
301 lsapi_log(
"%s, errno: %d (%s)\n", pMessage, err_no, strerror(err_no));
305static int lsapi_parent_dead(
void)
312 if (s_restored_ppid) {
313 if (kill(s_restored_ppid,0) == -1) {
314 if (
errno == EPERM) {
321 return(s_ppid != getppid());
325static void lsapi_sigpipe(
int sig )
330static void lsapi_siguser1(
int sig )
343 sigaction(signo,
NULL, &sa);
347 sigemptyset(&sa.sa_mask);
350 sigaction(signo, &sa,
NULL);
355static int s_enable_core_dump = 0;
356static void lsapi_enable_core_dump(
void)
358#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
359 || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
363#if !defined(__OpenBSD__)
365 if ( sysctlnametomib(
"kern.sugid_coredump", mib, &
len) == 0 )
367 len =
sizeof(s_enable_core_dump);
368 if (sysctl(mib, 2,
NULL, 0, &s_enable_core_dump,
len) == -1)
369 perror(
"sysctl: Failed to set 'kern.sugid_coredump', "
370 "core dump may not be available!");
376 mib[1] = KERN_NOSUIDCOREDUMP;
377 if (sysctl(mib, 2,
NULL, 0, &set,
len) == 0) {
378 s_enable_core_dump = 1;
386 if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1)
387 perror(
"prctl: Failed to set dumpable, "
388 "core dump may not be available!");
404static int lsapi_set_nblock(
int fd,
int nonblock )
406 int val = fcntl(
fd, F_GETFL, 0 );
425static int lsapi_close(
int fd )
431 if ((
ret == -1 )&&(
errno == EINTR )&&(g_running))
440 if (pReq->
m_fd == -1)
442 lsapi_close(pReq->
m_fd);
445 __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST);
452static inline ssize_t lsapi_read(
int fd,
void * pBuf,
size_t len )
457 ret = read(
fd, (
char *)pBuf,
len );
458 if ((
ret == -1 )&&(
errno == EINTR )&&(g_running))
488static int lsapi_writev(
int fd,
struct iovec ** pVec,
int count,
int totalLen )
497 while((
left > 0 )&&g_running )
499 ret = writev(
fd, *pVec,
n );
503 if ((
left <= 0)||( !g_running ))
504 return totalLen -
left;
507 if ( (*pVec)->iov_len <= (
unsigned int )
ret )
509 ret -= (*pVec)->iov_len;
514 (*pVec)->iov_base = (
char *)(*pVec)->iov_base +
ret;
515 (*pVec)->iov_len -=
ret;
520 else if (
ret == -1 )
524 if ( totalLen -
left > 0 )
525 return totalLen -
left;
529 else if (
errno != EINTR )
533 return totalLen -
left;
568 struct iovec *
p = (
struct iovec *)realloc(
569 pReq->
m_pIovec,
sizeof(
struct iovec) *
n );
596 ( pktType != pHeader->
m_type ))
613 int *curSize,
int newSize )
616 if ( *curSize >= newSize )
618 if ( newSize > 8192 )
634static inline int isPipe(
int fd )
638 if (( getpeername(
fd, (
struct sockaddr *)achPeer, &
len ) != 0 )&&
647 char **pBegin,
char * pEnd )
653 pEnvEnd = pEnvList +
count;
654 while( pEnvList != pEnvEnd )
656 if ( pEnd - *pBegin < 4 )
658 keyLen = *((
unsigned char *)((*pBegin)++));
659 keyLen = (
keyLen << 8) + *((
unsigned char *)((*pBegin)++));
660 valLen = *((
unsigned char *)((*pBegin)++));
661 valLen = (
valLen << 8) + *((
unsigned char *)((*pBegin)++));
667 pEnvList->
pKey = *pBegin;
669 pEnvList->
pValue = *pBegin;
676 if ( memcmp( *pBegin,
"\0\0\0\0", 4 ) != 0 )
683static inline void swapIntEndian(
int * pInteger )
685 char *
p = (
char *)pInteger;
700 swapIntEndian( &
p->m_httpHeaderLen );
701 swapIntEndian( &
p->m_reqBodyLen );
702 swapIntEndian( &
p->m_scriptFileOff );
703 swapIntEndian( &
p->m_scriptNameOff );
704 swapIntEndian( &
p->m_queryStringOff );
705 swapIntEndian( &
p->m_requestMethodOff );
706 swapIntEndian( &
p->m_cntUnknownHeaders );
707 swapIntEndian( &
p->m_cntEnv );
708 swapIntEndian( &
p->m_cntSpecialEnv );
734 swapIntEndian( &pCur->
nameOff );
735 swapIntEndian( &pCur->
nameLen );
777static uid_t s_uid = 0;
778static uid_t s_defaultUid;
779static gid_t s_defaultGid;
781#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
783#define LSAPI_LVE_DISABLED 0
784#define LSAPI_LVE_ENABLED 1
785#define LSAPI_CAGEFS_ENABLED 2
786#define LSAPI_CAGEFS_NO_SUEXEC 3
788static int s_enable_lve = LSAPI_LVE_DISABLED;
789static struct liblve * s_lve =
NULL;
791static void *s_liblve;
792static int (*fp_lve_is_available)(
void) =
NULL;
793static int (*fp_lve_instance_init)(
struct liblve *) =
NULL;
794static int (*fp_lve_destroy)(
struct liblve *) =
NULL;
795static int (*fp_lve_enter)(
struct liblve *, uint32_t, int32_t, int32_t, uint32_t *) =
NULL;
796static int (*fp_lve_leave)(
struct liblve *, uint32_t *) =
NULL;
797static int (*fp_lve_jail)(
struct passwd *,
char *) =
NULL;
798static int lsapi_load_lve_lib(
void)
800 s_liblve = DL_LOAD(
"liblve.so.0");
803 fp_lve_is_available = dlsym(s_liblve,
"lve_is_available");
804 if (dlerror() ==
NULL)
806 if ( !(*fp_lve_is_available)() )
811 if (setreuid( s_uid, uid )) {};
812 if ( !(*fp_lve_is_available)() )
814 if (setreuid( uid, s_uid )) {};
821 s_enable_lve = LSAPI_LVE_DISABLED;
823 return (s_liblve)? 0 : -1;
827static int init_lve_ex(
void)
832 fp_lve_instance_init = dlsym(s_liblve,
"lve_instance_init");
833 fp_lve_destroy = dlsym(s_liblve,
"lve_destroy");
834 fp_lve_enter = dlsym(s_liblve,
"lve_enter");
835 fp_lve_leave = dlsym(s_liblve,
"lve_leave");
836 if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED )
837 fp_lve_jail = dlsym(s_liblve,
"jail" );
841 rc = (*fp_lve_instance_init)(
NULL);
844 rc = (*fp_lve_instance_init)(s_lve);
847 perror(
"LSAPI: Unable to initialize LVE" );
860static int readSecret(
const char * pSecretFile )
863 int fd = open( pSecretFile, O_RDONLY , 0600 );
866 lsapi_log(
"LSAPI: failed to open secret file: %s!\n", pSecretFile );
871 lsapi_log(
"LSAPI: failed to check state of file: %s!\n", pSecretFile );
883 if ( st.st_mode & 0077 )
885 lsapi_log(
"LSAPI: file permission check failure: %s\n", pSecretFile );
889 if ( read(
fd, s_secret, 16 ) < 16 )
891 lsapi_log(
"LSAPI: failed to read secret from secret file: %s\n", pSecretFile );
902 if (( !s_uid )&&( s_secret[0] ))
909static int LSAPI_perror_r(
LSAPI_Request * pReq,
const char * pErr1,
const char *pErr2 )
912 int n =
snprintf(achError,
sizeof(achError),
"[UID:%d][%d] %s:%s: %s\n",
914 pErr1, (pErr2)?pErr2:
"", strerror(
errno));
915 if (
n > (
int)
sizeof(achError))
916 n =
sizeof(achError);
925#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
928 static const char * headers[] =
930 "Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0",
933 "Content-Type: text/html",
936 static const char achBody[] =
937 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
938 "<HTML><HEAD>\n<TITLE>508 Resource Limit Is Reached</TITLE>\n"
939 "</HEAD><BODY>\n" "<H1>Resource Limit Is Reached</H1>\n"
940 "The website is temporarily unable to service your request as it exceeded resource limit.\n"
941 "Please try again later.\n"
955 ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie);
959 LSAPI_perror_r(pReq,
"LSAPI: lve_enter() failure, reached resource limit.",
NULL );
960 lsapi_lve_error( pReq );
968static int lsapi_jailLVE(
LSAPI_Request * pReq, uid_t uid,
struct passwd * pw )
975 lsapi_log(
"LSAPI: LVE jail(%d) result: %d, error: %s !\n",
977 LSAPI_perror_r( pReq,
"LSAPI: jail() failure.",
NULL );
984static int lsapi_initLVE(
void)
987 if ( (pEnv =
getenv(
"LSAPI_LVE_ENABLE" ))!=
NULL )
989 s_enable_lve = atol( pEnv );
992 else if ( (pEnv =
getenv(
"LVE_ENABLE" ))!=
NULL )
994 s_enable_lve = atol( pEnv );
997 if ( s_enable_lve && !s_uid )
999 lsapi_load_lve_lib();
1002 return init_lve_ex();
1011static int setUID_LVE(
LSAPI_Request * pReq, uid_t uid, gid_t gid,
const char * pChroot)
1015 pw = getpwuid( uid );
1016#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
1019 if( lsapi_enterLVE( pReq, uid ) == -1 )
1021 if ( pw && fp_lve_jail)
1023 rv = lsapi_jailLVE( pReq, uid, pw );
1026 if ((
rv == 1 )&&(s_enable_lve == LSAPI_CAGEFS_NO_SUEXEC ))
1030 pw = getpwuid( uid );
1040#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
1041 || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
1042 if ( s_enable_core_dump )
1043 lsapi_enable_core_dump();
1049 LSAPI_perror_r(pReq,
"LSAPI: setgid()",
NULL);
1052 if ( pw && (pw->pw_gid == gid ))
1054 rv = initgroups( pw->pw_name, gid );
1057 LSAPI_perror_r(pReq,
"LSAPI: initgroups()",
NULL);
1063 rv = setgroups(1, &gid);
1066 LSAPI_perror_r(pReq,
"LSAPI: setgroups()",
NULL);
1074 LSAPI_perror_r(pReq,
"LSAPI: chroot()",
NULL);
1081 LSAPI_perror_r(pReq,
"LSAPI: setuid()",
NULL);
1084#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
1085 if ( s_enable_core_dump )
1086 lsapi_enable_core_dump();
1092 char * pAuth,
int len,
char * pUgid,
int ugidLen )
1095 unsigned char achMD5[16];
1098 memmove( achMD5, pAuth + 16, 16 );
1099 memmove( pAuth + 16, s_secret, 16 );
1104 if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 )
1112 int uid = s_defaultUid;
1113 int gid = s_defaultGid;
1114 const char *pStderrLog;
1115 const char *pChroot =
NULL;
1130 if (( *pEnv->
pKey ==
'\000' )&&
1131 (
strcmp( pEnv->
pKey+1,
"SUEXEC_AUTH" ) == 0 ))
1135 if (( *pEnv->
pKey ==
'\000' )&&
1136 (
strcmp( pEnv->
pKey+1,
"SUEXEC_UGID" ) == 0 ))
1139 uid = *(uint32_t *)pEnv->
pValue;
1140 gid = *(((uint32_t *)pEnv->
pValue) + 1 );
1145 lsapi_log(
"LSAPI: missing SUEXEC_UGID env, use default user!\n" );
1156 lsapi_log(
"LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" );
1174 if ( setUID_LVE( pReq, uid, gid, pChroot ) == -1 )
1189 lsapi_reopen_stderr(pStderrLog);
1205static int parseRequest(
LSAPI_Request * pReq,
int totalLen )
1207 int shouldFixEndian;
1209 char * pEnd = pReq->
m_pReqBuf + totalLen;
1212 if ( shouldFixEndian )
1228 &pBegin, pEnd ) == -1 )
1231 &pBegin, pEnd ) == -1 )
1242 lsapi_log(
"Bad request header - ERROR#1\n");
1260 if ( pBegin != pEnd )
1262 lsapi_log(
"Request header does match total size, total: %d, "
1263 "real: %ld\n", totalLen, pBegin - pReq->
m_pReqBuf );
1266 if ( shouldFixEndian )
1268 fixHeaderIndexEndian( pReq );
1271 if (validateHeaders(pReq) == -1)
1273 lsapi_log(
"Bad request header - ERROR#2\n");
1280 parseContentLenFromHeader(pReq);
1288static char s_accept_notify = 0;
1289static char s_schedule_notify = 0;
1290static char s_notify_scheduled = 0;
1291static char s_notified_pid = 0;
1307static inline int send_req_received_notification(
int fd )
1309 return send_notification_pkt(
fd, &s_ack);
1313static inline int send_conn_close_notification(
int fd )
1315 return send_notification_pkt(
fd, &s_conn_close_pkt);
1330static inline int lsapi_schedule_notify(
void)
1332 if ( !s_notify_scheduled )
1335 s_notify_scheduled = 1;
1341static inline int notify_req_received(
int fd )
1343 if ( s_schedule_notify )
1344 return lsapi_schedule_notify();
1345 return send_req_received_notification(
fd );
1350static inline int lsapi_notify_pid(
int fd )
1355 memmove( &achBuf[8],
"\0PID", 4 );
1356 *((
int *)&achBuf[12]) = getpid();
1358 if ( write(
fd, achBuf, 16 ) < 16 )
1371 if ( allocateBuf( pReq, 8192 ) == -1 )
1385 if ( packetLen < 0 )
1398 if ( allocateBuf( pReq, packetLen + 1024 ) == -1 )
1408 if ( parseRequest( pReq, packetLen ) < 0 )
1418 if ( lsapi_changeUGid( pReq ) )
1420 memset(s_secret, 0,
sizeof(s_secret));
1425 if ( !s_accept_notify && !s_notified_pid )
1426 return notify_req_received( pReq->
m_fd );
1441 lsapi_signal(
SIGPIPE, lsapi_sigpipe);
1442 lsapi_signal(
SIGUSR1, lsapi_siguser1);
1444#if defined(SIGXFSZ) && defined(SIG_IGN)
1454 void *pthread_lib = dlopen(
"libpthread.so", RTLD_LAZY);
1456 pthread_atfork_func = dlsym(pthread_lib,
"pthread_atfork");
1477 s_proc_group_timer_cb =
cb;
1487 if ( allocateIovec( pReq, 16 ) == -1 )
1501 newfd = open(
"/dev/null", O_RDWR );
1514 lsapi_set_nblock(
fd, 1 );
1545 if ( pReq->
m_fd == -1 )
1549 len =
sizeof( achPeer );
1551 (
struct sockaddr *)&achPeer, &
len );
1552 if ( pReq->
m_fd == -1 )
1561 if (s_worker_status)
1562 __atomic_store_n(&s_worker_status->m_state,
1565 __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST);
1566 lsapi_set_nblock( pReq->
m_fd , 0 );
1567 if (((
struct sockaddr *)&achPeer)->sa_family ==
AF_INET )
1570 (
char *)&nodelay,
sizeof(nodelay));
1574 if ( s_accept_notify )
1575 if ( notify_req_received( pReq->
m_fd ) == -1 )
1582 if ( !readReq( pReq ) )
1585 lsapi_close_connection(pReq);
1606 if ( pReq->
m_fd != -1 )
1617 pReq->
m_pIovecCur->iov_base = (
void *)finish_close;
1637 if ( pReq->
m_fd != -1 )
1651 pReq->
m_pIovecCur->iov_base = (
void *)finish_close;
1656 lsapi_close_connection(pReq);
1719 if (
len > bodyLeft )
1731 if (!pReq || (pReq->
m_fd ==-1) )
1735 if ( readBodyToReqBuf( pReq ) <= 0 )
1747 char * pBufEnd = pBuf + bufLen - 1;
1748 char * pBufCur = pBuf;
1751 if (!pReq || pReq->
m_fd == -1 || !pBuf || !getLF)
1754 while( (
left = pBufEnd - pBufCur ) > 0 )
1760 if ( (
len = readBodyToReqBuf( pReq )) <= 0 )
1769 p = memchr( pCur,
'\n',
len );
1786 return pBufCur - pBuf;
1795 if (!pReq || pReq->
m_fd == -1 || !pBuf || (ssize_t)bufLen < 0)
1802 if (
total < (ssize_t)bufLen )
1809 if (
len > (ssize_t)bufLen )
1819 len = lsapi_read( pReq->
m_fd, pBuf, bufLen );
1826 else if (
len <= 0 )
1853 if (pReq->
m_fd == -1)
1884 while( ( toWrite = pEnd -
p ) > 0 )
1886 packetLen = toWrite + bufLen;
1890 toWrite = packetLen - bufLen;
1929#if defined(__FreeBSD__ )
1930ssize_t gsendfile(
int fdOut,
int fdIn, off_t* off,
size_t size )
1934 ret = sendfile( fdIn, fdOut, *off,
size,
NULL, &written, 0 );
1944#if defined(__OpenBSD__) || defined(__NetBSD__)
1945ssize_t gsendfile(
int fdOut,
int fdIn, off_t* off,
size_t size )
1949 const size_t bufsiz = 16384;
1950 unsigned char in[bufsiz] = {0};
1952 if (lseek(fdIn, *off,
SEEK_SET) == -1) {
1957 size_t tor =
size >
sizeof(in) ?
sizeof(in) :
size;
1958 ssize_t c = read(fdIn, in, tor);
1963 ssize_t w = write(fdOut, in, c);
1979#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
1980ssize_t gsendfile(
int fdOut,
int fdIn, off_t* off,
size_t size )
1984 ret = sendfile( fdIn, fdOut, *off, &
len,
NULL, 0 );
1985 if ((
ret == 0 )&&(
len > 0 ))
1995#if defined(sun) || defined(__sun)
1996#include <sys/sendfile.h>
1997ssize_t gsendfile(
int fdOut,
int fdIn, off_t *off,
size_t size )
2000 sendfilevec_t vec[1];
2002 vec[
n].sfv_fd = fdIn;
2003 vec[
n].sfv_flag = 0;
2004 vec[
n].sfv_off = *off;
2005 vec[
n].sfv_len =
size;
2009 ssize_t
ret = sendfilev( fdOut, vec,
n, &written );
2019#if defined(linux) || defined(__linux) || defined(__linux__) || \
2020 defined(__gnu_linux__)
2021#include <sys/sendfile.h>
2022#define gsendfile sendfile
2027ssize_t gsendfile(
int fdOut,
int fdIn, off_t * off,
size_t size )
2029 return sendfile( fdOut, fdIn, off,
size,
NULL, 0 );
2037 if ( !pReq || (pReq->
m_fd == -1) || fdIn == -1 )
2054 return gsendfile( pReq->
m_fd, fdIn, off,
size );
2091 if ( pReq->
m_fd == -1 )
2115 lsapi_close_connection(pReq);
2133 struct iovec iov[2];
2139 return write( 2, pBuf,
len );
2148 while( ( packetLen = pEnd -
p ) > 0 )
2159 iov[0].iov_base = (
void *)&
header;
2162 iov[1].iov_base = (
void *)
p;
2163 iov[1].iov_len = packetLen;
2166 ret = lsapi_writev( pReq->
m_fd, &pIov,
2168 if (
ret < totalLen )
2170 lsapi_close_connection(pReq);
2207 while( pCur < pEnd )
2211 pKeyEnd = pKey + keyLen;
2214 while(( pKey < pKeyEnd )&&( *
p ))
2216 char ch = toupper( *pKey );
2217 if ((
ch != *
p )||(( *
p ==
'_' )&&(
ch !=
'-')))
2221 if (( pKey == pKeyEnd )&& (!*
p ))
2225 if ( *(pValue + pCur->
valueLen) !=
'\0')
2242 if ( !pReq || !
name )
2246 return GetHeaderVar( pReq,
name );
2248 while( pBegin < pEnd )
2296 *(pValue +
len ) = 0;
2316 while( pCur < pEnd )
2320 *(pKey + keyLen ) = 0;
2339 for( i = 0; i <
count; ++i )
2366 *(pValue +
len ) = 0;
2367 ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i],
2376 char achHeaderName[256];
2384 while( pCur < pEnd )
2390 pKeyEnd = pKey + keyLen;
2391 memcpy( achHeaderName,
"HTTP_", 5 );
2392 p = &achHeaderName[5];
2394 while( pKey < pKeyEnd )
2400 *
p++ = toupper(
ch );
2407 ret = (*fn)( achHeaderName, keyLen,
2425 while( pEnv < pEnd )
2483 + pReq->m_respHeader.
m_respInfo.m_cntHeaders *
sizeof( short );
2495 const char * pHeaderValue )
2497 int nameLen, valLen,
len;
2498 if ( !pReq || !pHeaderName || !pHeaderValue )
2504 nameLen =
strlen( pHeaderName );
2505 valLen =
strlen( pHeaderValue );
2508 while( nameLen > 0 )
2510 char ch = *(pHeaderName + nameLen - 1 );
2511 if ((
ch ==
'\n' )||(
ch ==
'\r' ))
2520 char ch = *(pHeaderValue + valLen - 1 );
2521 if ((
ch ==
'\n' )||(
ch ==
'\r' ))
2526 len = nameLen + valLen + 1;
2533 newlen -= newlen % 4096;
2534 if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
2560 char ch = *(pBuf +
len - 1 );
2561 if ((
ch ==
'\n' )||(
ch ==
'\r' ))
2571 newlen -= newlen % 4096;
2572 if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
2592 switch( pServerAddr->sa_family )
2598 addr_len =
sizeof(
struct sockaddr_in6 );
2601 addr_len =
sizeof(
struct sockaddr_un );
2602 unlink( ((
struct sockaddr_un *)pServerAddr)->sun_path );
2615 (
char *)( &flag ),
sizeof(flag)) == 0)
2617 ret = bind(
fd, pServerAddr, addr_len );
2620 ret = listen(
fd, backlog );
2638 struct addrinfo *
res, hints;
2645 while( isspace( *pBind ) )
2648 strncpy(achAddr, pBind, 255);
2655 memccpy(((
struct sockaddr_un *)pAddr)->sun_path,
p, 0,
2656 sizeof(((
struct sockaddr_un *)pAddr)->sun_path));
2669 strcpy( achAddr,
"::" );
2685 ((
struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY);
2688 ((
struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK );
2701 port = atoi( pEnd );
2702 if (( port <= 0 )||( port > 65535 ))
2707 memset(&hints, 0,
sizeof(hints));
2709 hints.ai_family = pAddr->sa_family;
2711 hints.ai_protocol = IPPROTO_TCP;
2713 if ( getaddrinfo(
p,
NULL, &hints, &
res) )
2722 if ( pAddr->sa_family ==
AF_INET )
2723 ((
struct sockaddr_in *)pAddr)->sin_port = htons( port );
2725 ((
struct sockaddr_in6 *)pAddr)->sin6_port = htons( port );
2733 char serverAddr[128];
2768 if ( g_prefork_server )
2770 if ( max_children <= 1 )
2772 if ( max_children >= 10000)
2773 max_children = 10000;
2775 if (s_max_busy_workers == 0)
2776 s_max_busy_workers = max_children / 2 + 1;
2779 if ( !g_prefork_server )
2788 setpgid( s_pid, s_pid );
2789#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
2790 s_total_pages = sysconf(_SC_PHYS_PAGES);
2792 g_prefork_server->m_iAvoidFork = avoidFork;
2793 g_prefork_server->m_iMaxChildren = max_children;
2795 g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ;
2796 g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3);
2797 if ( g_prefork_server->m_iMaxIdleChildren == 0 )
2798 g_prefork_server->m_iMaxIdleChildren = 1;
2799 g_prefork_server->m_iChildrenMaxIdleTime = 300;
2800 g_prefork_server->m_iMaxReqProcessTime = 3600;
2810 if( g_prefork_server )
2811 g_prefork_server->m_fd =
fd;
2815static int lsapi_accept(
int fdListen )
2822 len =
sizeof( achPeer );
2823 fd = accept( fdListen, (
struct sockaddr *)&achPeer, &
len );
2826 if (((
struct sockaddr *)&achPeer)->sa_family ==
AF_INET )
2829 (
char *)&nodelay,
sizeof(nodelay));
2841static unsigned int s_max_reqs = UINT_MAX;
2842static int s_max_idle_secs = 300;
2845static void lsapi_cleanup(
int signal)
2855 while( pStatus < pEnd )
2857 if ( pStatus->
m_pid == pid )
2861 memset(pStatus, 0,
sizeof( *pStatus ) );
2862 pStatus->
m_pid = -1;
2864 if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur )
2865 g_prefork_server->m_pChildrenStatusCur = pStatus + 1;
2879 g_prefork_server->m_iCurChildren = 0;
2882 while( pStatus < pEnd )
2888 __atomic_store_n(s_busy_workers, 0, __ATOMIC_SEQ_CST);
2889 if (s_accepting_workers)
2890 __atomic_store_n(s_accepting_workers, 0, __ATOMIC_SEQ_CST);
2895static void lsapi_sigchild(
int signal )
2901 if (g_prefork_server ==
NULL)
2910 if ( WIFSIGNALED(
status ))
2912 int sig_num = WTERMSIG(
status );
2915 const char * dump = WCOREDUMP(
status ) ?
"yes" :
"no";
2917 const char * dump =
"unknown";
2919 lsapi_log(
"Child process with pid: %d was killed by signal: "
2920 "%d, core dumped: %s\n", pid, sig_num, dump );
2922 if ( pid == s_pid_dump_debug_info )
2927 if ( pid == s_ignore_pid )
2933 child_status = find_child_status( pid );
2936 if (__atomic_compare_exchange_n(&child_status->
m_state,
2943 __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST);
2945 else if (__atomic_compare_exchange_n(&child_status->
m_state,
2951 if (s_accepting_workers)
2952 __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST);
2954 child_status->
m_pid = 0;
2955 --g_prefork_server->m_iCurChildren;
2958 while(( g_prefork_server->m_pChildrenStatusCur > g_prefork_server->m_pChildrenStatus )
2959 &&( g_prefork_server->m_pChildrenStatusCur[-1].m_pid == 0 ))
2960 --g_prefork_server->m_pChildrenStatusCur;
2965static int lsapi_init_children_status(
void)
2970 if (g_prefork_server->m_pChildrenStatus)
2972 max_children = g_prefork_server->m_iMaxChildren
2973 + g_prefork_server->m_iExtraChildren;
2976 size = (
size + 4095) / 4096 * 4096;
2978 MAP_ANON | MAP_SHARED, -1, 0 );
2981 perror(
"Anonymous mmap() failed" );
2988 s_busy_workers = (
int *)g_prefork_server->m_pChildrenStatusEnd;
2989 s_accepting_workers = s_busy_workers + 1;
2990 s_global_counter = s_accepting_workers + 1;
2991 s_avail_pages = (
size_t *)(s_global_counter + 1);
3001 if ( s_pid_dump_debug_info )
3003 if ( kill( s_pid_dump_debug_info, 0 ) == 0 )
3007 lsapi_log(
"Possible runaway process, UID: %d, PPID: %d, PID: %d, "
3008 "reqCount: %d, process time: %ld, checkpoint time: %ld, start "
3009 "time: %ld\n", getuid(), getppid(), pStatus->
m_pid,
3013 s_pid_dump_debug_info = fork();
3014 if (s_pid_dump_debug_info == 0)
3016 snprintf( achCmd, 1024,
"gdb --batch -ex \"attach %d\" -ex \"set height 0\" "
3017 "-ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2",
3019 if (
system( achCmd ) == -1 )
3020 perror(
"system()" );
3026static void lsapi_check_child_status(
long tmCur )
3034 while( pStatus < pEnd )
3037 if ( pStatus->
m_pid != 0 && pStatus->
m_pid != -1)
3042 if (g_prefork_server->m_iCurChildren - dying
3043 > g_prefork_server->m_iMaxChildren
3044 || idle > g_prefork_server->m_iMaxIdleChildren)
3051 if (s_max_idle_secs> 0
3064 g_prefork_server->m_iMaxReqProcessTime)
3066 if ((pStatus->
m_iKillSent % 5) == 0 && s_dump_debug_info)
3067 dump_debug_info( pStatus, tmCur );
3071 lsapi_log(
"Force killing runaway process PID: %d"
3072 " with SIGKILL\n", pStatus->
m_pid );
3077 lsapi_log(
"Killing runaway process PID: %d with "
3078 "SIGTERM\n", pStatus->
m_pid );
3084 if (( kill( pStatus->
m_pid, tobekilled ) == -1 ) &&
3099 if (
abs( g_prefork_server->m_iCurChildren -
count ) > 1 )
3101 lsapi_log(
"Children tracking is wrong: Cur Children: %d,"
3102 " count: %d, idle: %d, dying: %d\n",
3103 g_prefork_server->m_iCurChildren,
count, idle, dying );
3129{ s_skip_write = 1; }
3134#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
3136 return (*s_avail_pages > s_min_avail_pages
3137 || (*s_avail_pages * 10) / s_total_pages > 0);
3146 struct sigaction act, old_term, old_quit, old_int,
3147 old_usr1, old_child;
3152 time_t lastTime = 0;
3155 struct timeval timeout;
3160 lsapi_init_children_status();
3163 act.sa_handler = lsapi_sigchild;
3164 sigemptyset(&(act.sa_mask));
3165 if( sigaction(
SIGCHLD, &act, &old_child ) )
3167 perror(
"Can't set signal handler for SIGCHILD" );
3173 act.sa_handler = lsapi_cleanup;
3174 sigemptyset(&(act.sa_mask));
3175 if( sigaction(
SIGTERM, &act, &old_term ) ||
3176 sigaction(
SIGINT, &act, &old_int ) ||
3177 sigaction(
SIGUSR1, &act, &old_usr1 ) ||
3178 sigaction(
SIGQUIT, &act, &old_quit ))
3180 perror(
"Can't set signals" );
3186 if (s_proc_group_timer_cb !=
NULL) {
3187 s_proc_group_timer_cb(&s_ignore_pid);
3191 if (curTime != lastTime )
3194 if (lsapi_parent_dead())
3196 lsapi_check_child_status(curTime );
3210#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
3211 *s_avail_pages = sysconf(_SC_AVPHYS_PAGES);
3216 FD_ZERO( &readfds );
3217 FD_SET( pServer->
m_fd, &readfds );
3219 timeout.tv_usec = 0;
3224 if (s_accepting_workers)
3225 accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST);
3231 while(accepting-- > 0)
3236 else if (
ret == -1 )
3238 if (
errno == EINTR )
3251 lsapi_log(
"Reached max children process limit: %d, extra: %d,"
3252 " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n",
3255 s_busy_workers ? *s_busy_workers : -1 );
3260 pReq->
m_fd = lsapi_accept( pServer->
m_fd );
3261 if ( pReq->
m_fd != -1 )
3264 child_status = find_child_status( 0 );
3266 sigemptyset( &mask );
3269 if ( sigprocmask(
SIG_BLOCK, &mask, &orig_mask) < 0 )
3271 perror(
"sigprocmask(SIG_BLOCK) to block SIGCHLD" );
3280 perror(
"sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" );
3281 g_prefork_server =
NULL;
3284 s_req_processed = 0;
3285 s_proc_group_timer_cb =
NULL;
3286 s_worker_status = child_status;
3288 if (pthread_atfork_func)
3291 __atomic_store_n(&s_worker_status->m_state,
3294 __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST);
3295 lsapi_set_nblock( pReq->
m_fd, 0 );
3297 if (!s_keep_listener && s_busy_workers
3299 s_keep_listener = 1;
3307 sigaction(
SIGCHLD, &old_child, 0 );
3308 sigaction(
SIGTERM, &old_term, 0 );
3309 sigaction(
SIGQUIT, &old_quit, 0 );
3310 sigaction(
SIGINT, &old_int, 0 );
3311 sigaction(
SIGUSR1, &old_usr1, 0 );
3313 lsapi_notify_pid( pReq->
m_fd );
3319 else if ( pid == -1 )
3323 child_status->m_pid = 0;
3330 child_status->m_pid = pid;
3331 child_status->m_tmWaitBegin = curTime;
3332 child_status->m_tmStart = curTime;
3339 perror(
"sigprocmask( SIG_SETMASK ) to restore SIGMASK" );
3350 sigaction(
SIGUSR1, &old_usr1, 0 );
3358static struct sigaction old_term, old_quit, old_int,
3359 old_usr1, old_child;
3364 int max_children = g_prefork_server->m_iMaxChildren;
3370 g_prefork_server =
NULL;
3372 s_req_processed = 0;
3373 s_proc_group_timer_cb =
NULL;
3375 if (pthread_atfork_func)
3378 __atomic_store_n(&s_worker_status->m_state,
3381 __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST);
3382 lsapi_set_nblock( pReq->
m_fd, 0 );
3384 if (!s_keep_listener && s_busy_workers
3385 && *s_busy_workers > (max_children >> 1))
3386 s_keep_listener = 1;
3395 lsapi_notify_pid(pReq->
m_fd);
3405 ++g_prefork_server->m_iCurChildren;
3420 time_t lastTime = 0;
3423 struct timeval timeout;
3429 struct sigaction act;
3431 lsapi_init_children_status();
3434 act.sa_handler = lsapi_sigchild;
3435 sigemptyset(&(act.sa_mask));
3436 if (sigaction(
SIGCHLD, &act, &old_child))
3438 perror(
"Can't set signal handler for SIGCHILD" );
3444 act.sa_handler = lsapi_cleanup;
3445 sigemptyset(&(act.sa_mask));
3446 if (sigaction(
SIGTERM, &act, &old_term) ||
3447 sigaction(
SIGINT, &act, &old_int ) ||
3448 sigaction(
SIGUSR1, &act, &old_usr1) ||
3449 sigaction(
SIGQUIT, &act, &old_quit))
3451 perror(
"Can't set signals" );
3459 if (s_proc_group_timer_cb !=
NULL) {
3460 s_proc_group_timer_cb(&s_ignore_pid);
3464 if (curTime != lastTime)
3467 if (lsapi_parent_dead())
3469 lsapi_check_child_status(curTime);
3483#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
3484 *s_avail_pages = sysconf(_SC_AVPHYS_PAGES);
3490 FD_SET(pServer->
m_fd, &readfds);
3492 timeout.tv_usec = 0;
3497 if (s_accepting_workers)
3498 accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST);
3504 while(accepting-- > 0)
3524 lsapi_log(
"Reached max children process limit: %d, extra: %d,"
3525 " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n",
3528 s_busy_workers ? *s_busy_workers : -1);
3533 pReq->
m_fd = lsapi_accept(pServer->
m_fd);
3534 if (pReq->
m_fd != -1)
3552 sigaction(
SIGCHLD, &old_child, 0);
3553 sigaction(
SIGTERM, &old_term, 0);
3554 sigaction(
SIGQUIT, &old_quit, 0);
3555 sigaction(
SIGINT, &old_int, 0);
3556 sigaction(
SIGUSR1, &old_usr1, 0);
3568 struct timeval timeout;
3575 if ( g_prefork_server )
3577 if ( g_prefork_server->m_fd != -1 )
3578 if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 )
3581 else if (s_req_processed > 0 && s_max_busy_workers > 0 && s_busy_workers)
3583 ret = __atomic_load_n(s_busy_workers, __ATOMIC_SEQ_CST);
3584 if (
ret >= s_max_busy_workers)
3586 send_conn_close_notification(pReq->
m_fd);
3587 lsapi_close_connection(pReq);
3591 if ( (
unsigned int)s_req_processed > s_max_reqs )
3594 if ( s_worker_status )
3596 s_worker_status->m_tmWaitBegin =
time(
NULL );
3602 if ( pReq->
m_fd != -1 )
3617 if (s_req_processed && s_worker_status
3618 && s_worker_status->m_iKillSent)
3620 FD_ZERO( &readfds );
3621 FD_SET(
fd, &readfds );
3623 timeout.tv_usec = 0;
3626 if (s_worker_status)
3627 __atomic_store_n(&s_worker_status->m_state,
3629 if (s_accepting_workers)
3630 __atomic_fetch_add(s_accepting_workers, 1, __ATOMIC_SEQ_CST);
3635 if (s_accepting_workers)
3636 __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST);
3637 if (s_worker_status)
3638 __atomic_store_n(&s_worker_status->m_state,
3644 if ( s_worker_status )
3646 s_worker_status->m_inProcess = 0;
3651 if (s_keep_listener == 1)
3655 wait_time += *s_busy_workers * 10;
3656 if (s_accepting_workers)
3657 wait_time >>= (*s_accepting_workers);
3658 if (wait_secs >= wait_time)
3664 if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
3666 if ( lsapi_parent_dead() )
3669 else if (
ret == -1 )
3671 if (
errno == EINTR )
3676 else if (
ret >= 1 )
3678 if (s_req_processed && s_worker_status
3679 && s_worker_status->m_iKillSent)
3684 if ( pReq->
m_fd != -1 )
3686 if (s_worker_status)
3687 __atomic_store_n(&s_worker_status->m_state,
3691 __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST);
3695 lsapi_set_nblock(
fd, 0 );
3697 if (!s_keep_listener)
3702 if ( s_accept_notify )
3703 if ( notify_req_received( pReq->
m_fd ) == -1 )
3719 if ( !readReq( pReq ) )
3721 if ( s_worker_status )
3723 s_worker_status->m_iKillSent = 0;
3724 s_worker_status->m_inProcess = 1;
3725 ++s_worker_status->m_iReqCounter;
3726 s_worker_status->m_tmReqBegin =
3727 s_worker_status->m_tmLastCheckPoint =
time(
NULL);
3732 lsapi_close_connection(pReq);
3741{ s_max_reqs = reqs - 1; }
3744{ s_max_idle_secs = secs; }
3749 if ( g_prefork_server )
3750 g_prefork_server->m_iMaxChildren = maxChildren;
3756 if (( g_prefork_server )&&( extraChildren >= 0 ))
3757 g_prefork_server->m_iExtraChildren = extraChildren;
3763 if (( g_prefork_server )&&( secs > 0 ))
3764 g_prefork_server->m_iMaxReqProcessTime = secs;
3770 if (( g_prefork_server )&&( maxIdleChld > 0 ))
3771 g_prefork_server->m_iMaxIdleChildren = maxIdleChld;
3777 if ( g_prefork_server )
3778 g_prefork_server->m_iServerMaxIdle = serverMaxIdle;
3784 s_slow_req_msecs = msecs;
3790 return s_slow_req_msecs;
3806#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
3807#include <crt_externs.h>
3811static void unset_lsapi_envs(
void)
3814#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
3815 env = *_NSGetEnviron();
3819 while( env !=
NULL && *env !=
NULL )
3821 if (!
strncmp(*env,
"LSAPI_", 6) || !
strncmp( *env,
"PHP_LSAPI_", 10 )
3822 || (!
strncmp( *env,
"PHPRC=", 6 )&&(!s_uid)))
3835static int lsapi_initSuEXEC(
void)
3843 const char *
p =
getenv(
"LSAPI_DEFAULT_UID" );
3850 p =
getenv(
"LSAPI_DEFAULT_GID" );
3858 if (( !
p )||( readSecret(
p) == -1 ))
3860 if ( g_prefork_server )
3862 if ( g_prefork_server->m_iMaxChildren < 100 )
3863 g_prefork_server->m_iMaxChildren = 100;
3864 if ( g_prefork_server->m_iExtraChildren < 1000 )
3865 g_prefork_server->m_iExtraChildren = 1000;
3868 if ( !s_defaultUid || !s_defaultGid )
3870 pw = getpwnam(
"nobody" );
3873 if ( !s_defaultUid )
3874 s_defaultUid = pw->pw_uid;
3875 if ( !s_defaultGid )
3876 s_defaultGid = pw->pw_gid;
3880 if ( !s_defaultUid )
3881 s_defaultUid = 10000;
3882 if ( !s_defaultGid )
3883 s_defaultGid = 10000;
3890static int lsapi_check_path(
const char *
p,
char *
final,
int max_len)
3892 char resolved_path[PATH_MAX+1];
3900 *(
final +
len) =
'/';
3903 end = memccpy(&
final[
len],
p,
'\0', PATH_MAX -
len);
3913 if (
strncmp(resolved_path,
"/etc/", 5) == 0)
3922static int lsapi_reopen_stderr2(
const char *full_path)
3924 int newfd = open(full_path, O_WRONLY | O_CREAT | O_APPEND, 0644);
3927 LSAPI_perror_r(
NULL,
"Failed to open custom stderr log", full_path);
3936 if (s_stderr_log_path && full_path != s_stderr_log_path)
3938 free(s_stderr_log_path);
3939 s_stderr_log_path =
NULL;
3941 s_stderr_log_path = strdup(full_path);
3946static int lsapi_reopen_stderr(
const char *
p)
3948 char full_path[PATH_MAX];
3951 if (lsapi_check_path(
p, full_path, PATH_MAX) == -1)
3953 LSAPI_perror_r(
NULL,
"Invalid custom stderr log path",
p);
3956 return lsapi_reopen_stderr2(full_path);
3967 p =
getenv(
"LSAPI_STDERR_LOG");
3970 lsapi_reopen_stderr(
p);
3972 if (!s_stderr_log_path)
3975 p =
getenv(
"PHP_LSAPI_MAX_REQUESTS" );
3977 p =
getenv(
"LSAPI_MAX_REQS" );
3985 p =
getenv(
"LSAPI_KEEP_LISTEN" );
3989 s_keep_listener =
n;
3992 p =
getenv(
"LSAPI_AVOID_FORK" );
3995 avoidFork = atoi(
p );
3998 s_keep_listener = 2;
4000 if (
ch ==
'G' ||
ch ==
'g' )
4001 avoidFork *= 1024 * 1024 * 1024;
4002 else if (
ch ==
'M' ||
ch ==
'm' )
4003 avoidFork *= 1024 * 1024;
4004 if (avoidFork >= 1024 * 10240)
4005 s_min_avail_pages = avoidFork / 4096;
4009 p =
getenv(
"LSAPI_ACCEPT_NOTIFY" );
4012 s_accept_notify = atoi(
p );
4015 p =
getenv(
"LSAPI_SLOW_REQ_MSECS" );
4022#if defined( RLIMIT_CORE )
4023 p =
getenv(
"LSAPI_ALLOW_CORE_DUMP" );
4026 struct rlimit limit = { 0, 0 };
4027 setrlimit( RLIMIT_CORE, &limit );
4030 s_enable_core_dump = 1;
4034 p =
getenv(
"LSAPI_MAX_IDLE" );
4044 p =
getenv(
"PHP_LSAPI_CHILDREN" );
4046 p =
getenv(
"LSAPI_CHILDREN" );
4055 p =
getenv(
"LSAPI_EXTRA_CHILDREN" );
4059 p =
getenv(
"LSAPI_MAX_IDLE_CHILDREN" );
4063 p =
getenv(
"LSAPI_PGRP_MAX_IDLE" );
4069 p =
getenv(
"LSAPI_MAX_PROCESS_TIME" );
4073 if (
getenv(
"LSAPI_PPID_NO_CHECK" ) )
4078 p =
getenv(
"LSAPI_MAX_BUSY_WORKER");
4082 s_max_busy_workers =
n;
4088 p =
getenv(
"LSAPI_DUMP_DEBUG_INFO" );
4090 s_dump_debug_info = atoi(
p );
4092 if ( lsapi_initSuEXEC() == -1 )
4094#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
4104 const char * pBody,
int bodyLen )
4106 LSAPI_SetRespStatus_r( pReq, code );
4109 while( *pRespHeaders )
4115 if ( pBody &&( bodyLen > 0 ))
4129static void byteReverse(
unsigned char *
buf,
unsigned longs)
4134 ((unsigned)
buf[1] << 8 |
buf[0]);
4147 ctx->
buf[0] = 0x67452301;
4148 ctx->
buf[1] = 0xefcdab89;
4149 ctx->
buf[2] = 0x98badcfe;
4150 ctx->
buf[3] = 0x10325476;
4171 t = (t >> 3) & 0x3f;
4176 unsigned char *
p = (
unsigned char *) ctx->
in + t;
4184 byteReverse(ctx->
in, 16);
4193 byteReverse(ctx->
in, 16);
4229 byteReverse(ctx->
in, 16);
4238 byteReverse(ctx->
in, 14);
4245 byteReverse((
unsigned char *) ctx->
buf, 4);
4247 memset(ctx, 0,
sizeof(*ctx));
4254#define F1(x, y, z) (z ^ (x & (y ^ z)))
4255#define F2(x, y, z) F1(z, x, y)
4256#define F3(x, y, z) (x ^ y ^ z)
4257#define F4(x, y, z) (y ^ (x | ~z))
4260#define MD5STEP(f, w, x, y, z, data, s) \
4261 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
4277 MD5STEP(
F1,
a, b, c, d, in[0] + 0xd76aa478, 7);
4278 MD5STEP(
F1, d,
a, b, c, in[1] + 0xe8c7b756, 12);
4279 MD5STEP(
F1, c, d,
a, b, in[2] + 0x242070db, 17);
4280 MD5STEP(
F1, b, c, d,
a, in[3] + 0xc1bdceee, 22);
4281 MD5STEP(
F1,
a, b, c, d, in[4] + 0xf57c0faf, 7);
4282 MD5STEP(
F1, d,
a, b, c, in[5] + 0x4787c62a, 12);
4283 MD5STEP(
F1, c, d,
a, b, in[6] + 0xa8304613, 17);
4284 MD5STEP(
F1, b, c, d,
a, in[7] + 0xfd469501, 22);
4285 MD5STEP(
F1,
a, b, c, d, in[8] + 0x698098d8, 7);
4286 MD5STEP(
F1, d,
a, b, c, in[9] + 0x8b44f7af, 12);
4287 MD5STEP(
F1, c, d,
a, b, in[10] + 0xffff5bb1, 17);
4288 MD5STEP(
F1, b, c, d,
a, in[11] + 0x895cd7be, 22);
4289 MD5STEP(
F1,
a, b, c, d, in[12] + 0x6b901122, 7);
4290 MD5STEP(
F1, d,
a, b, c, in[13] + 0xfd987193, 12);
4291 MD5STEP(
F1, c, d,
a, b, in[14] + 0xa679438e, 17);
4292 MD5STEP(
F1, b, c, d,
a, in[15] + 0x49b40821, 22);
4294 MD5STEP(
F2,
a, b, c, d, in[1] + 0xf61e2562, 5);
4295 MD5STEP(
F2, d,
a, b, c, in[6] + 0xc040b340, 9);
4296 MD5STEP(
F2, c, d,
a, b, in[11] + 0x265e5a51, 14);
4297 MD5STEP(
F2, b, c, d,
a, in[0] + 0xe9b6c7aa, 20);
4298 MD5STEP(
F2,
a, b, c, d, in[5] + 0xd62f105d, 5);
4299 MD5STEP(
F2, d,
a, b, c, in[10] + 0x02441453, 9);
4300 MD5STEP(
F2, c, d,
a, b, in[15] + 0xd8a1e681, 14);
4301 MD5STEP(
F2, b, c, d,
a, in[4] + 0xe7d3fbc8, 20);
4302 MD5STEP(
F2,
a, b, c, d, in[9] + 0x21e1cde6, 5);
4303 MD5STEP(
F2, d,
a, b, c, in[14] + 0xc33707d6, 9);
4304 MD5STEP(
F2, c, d,
a, b, in[3] + 0xf4d50d87, 14);
4305 MD5STEP(
F2, b, c, d,
a, in[8] + 0x455a14ed, 20);
4306 MD5STEP(
F2,
a, b, c, d, in[13] + 0xa9e3e905, 5);
4307 MD5STEP(
F2, d,
a, b, c, in[2] + 0xfcefa3f8, 9);
4308 MD5STEP(
F2, c, d,
a, b, in[7] + 0x676f02d9, 14);
4309 MD5STEP(
F2, b, c, d,
a, in[12] + 0x8d2a4c8a, 20);
4311 MD5STEP(
F3,
a, b, c, d, in[5] + 0xfffa3942, 4);
4312 MD5STEP(
F3, d,
a, b, c, in[8] + 0x8771f681, 11);
4313 MD5STEP(
F3, c, d,
a, b, in[11] + 0x6d9d6122, 16);
4314 MD5STEP(
F3, b, c, d,
a, in[14] + 0xfde5380c, 23);
4315 MD5STEP(
F3,
a, b, c, d, in[1] + 0xa4beea44, 4);
4316 MD5STEP(
F3, d,
a, b, c, in[4] + 0x4bdecfa9, 11);
4317 MD5STEP(
F3, c, d,
a, b, in[7] + 0xf6bb4b60, 16);
4318 MD5STEP(
F3, b, c, d,
a, in[10] + 0xbebfbc70, 23);
4319 MD5STEP(
F3,
a, b, c, d, in[13] + 0x289b7ec6, 4);
4320 MD5STEP(
F3, d,
a, b, c, in[0] + 0xeaa127fa, 11);
4321 MD5STEP(
F3, c, d,
a, b, in[3] + 0xd4ef3085, 16);
4322 MD5STEP(
F3, b, c, d,
a, in[6] + 0x04881d05, 23);
4323 MD5STEP(
F3,
a, b, c, d, in[9] + 0xd9d4d039, 4);
4324 MD5STEP(
F3, d,
a, b, c, in[12] + 0xe6db99e5, 11);
4325 MD5STEP(
F3, c, d,
a, b, in[15] + 0x1fa27cf8, 16);
4326 MD5STEP(
F3, b, c, d,
a, in[2] + 0xc4ac5665, 23);
4328 MD5STEP(
F4,
a, b, c, d, in[0] + 0xf4292244, 6);
4329 MD5STEP(
F4, d,
a, b, c, in[7] + 0x432aff97, 10);
4330 MD5STEP(
F4, c, d,
a, b, in[14] + 0xab9423a7, 15);
4331 MD5STEP(
F4, b, c, d,
a, in[5] + 0xfc93a039, 21);
4332 MD5STEP(
F4,
a, b, c, d, in[12] + 0x655b59c3, 6);
4333 MD5STEP(
F4, d,
a, b, c, in[3] + 0x8f0ccc92, 10);
4334 MD5STEP(
F4, c, d,
a, b, in[10] + 0xffeff47d, 15);
4335 MD5STEP(
F4, b, c, d,
a, in[1] + 0x85845dd1, 21);
4336 MD5STEP(
F4,
a, b, c, d, in[8] + 0x6fa87e4f, 6);
4337 MD5STEP(
F4, d,
a, b, c, in[15] + 0xfe2ce6e0, 10);
4338 MD5STEP(
F4, c, d,
a, b, in[6] + 0xa3014314, 15);
4339 MD5STEP(
F4, b, c, d,
a, in[13] + 0x4e0811a1, 21);
4340 MD5STEP(
F4,
a, b, c, d, in[4] + 0xf7537e82, 6);
4341 MD5STEP(
F4, d,
a, b, c, in[11] + 0xbd3af235, 10);
4342 MD5STEP(
F4, c, d,
a, b, in[2] + 0x2ad7d2bb, 15);
4343 MD5STEP(
F4, b, c, d,
a, in[9] + 0xeb86d391, 21);
4354 int old_ppid = s_ppid;
4355 s_restored_ppid = pid;
4362 return __atomic_add_fetch(s_global_counter, cnt, __ATOMIC_SEQ_CST);
chroot(string $directory)
unlink(string $filename, $context=null)
usleep(int $microseconds)
fprintf($stream, string $format, mixed ... $values)
getenv(?string $name=null, bool $local_only=false)
vfprintf($stream, string $format, array $values)
gettimeofday(bool $as_float=false)
header(string $header, bool $replace=true, int $response_code=0)
count(Countable|array $value, int $mode=COUNT_NORMAL)
strchr(string $haystack, string $needle, bool $before_needle=false)
system(string $command, &$result_code=null)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
#define F2(x6, x5, x4, x3, x2, x1, x0)
#define F3(x6, x5, x4, x3, x2, x1, x0)
#define F4(x6, x5, x4, x3, x2, x1, x0)
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
#define LSAPI_PACKET_HEADER_LEN
#define LSAPI_REQ_RECEIVED
#define LSAPI_BEGIN_REQUEST
#define LSAPI_RESP_HEADER
#define LSAPI_MAX_DATA_PACKET_LEN
#define LSAPI_RESP_STREAM
#define LSAPI_STDERR_STREAM
#define LSAPI_SOCK_FILENO
#define LSAPI_MAX_HEADER_LEN
#define LSAPI_RESP_HTTP_HEADER_MAX
ssize_t LSAPI_ReadReqBody_r(LSAPI_Request *pReq, char *pBuf, size_t bufLen)
#define MD5STEP(f, w, x, y, z, data, s)
#define LSAPI_ST_REQ_BODY
int LSAPI_ForeachSpecialEnv_r(LSAPI_Request *pReq, LSAPI_CB_EnvHandler fn, void *arg)
#define LSAPI_ST_RESP_BODY
char * LSAPI_GetEnv_r(LSAPI_Request *pReq, const char *name)
void LSAPI_Set_Extra_Children(int extraChildren)
ssize_t LSAPI_Write_Stderr_r(LSAPI_Request *pReq, const char *pBuf, size_t len)
int LSAPI_ForeachOrgHeader_r(LSAPI_Request *pReq, LSAPI_CB_EnvHandler fn, void *arg)
int LSAPI_CreateListenSock2(const struct sockaddr *pServerAddr, int backlog)
int LSAPI_Accept_r(LSAPI_Request *pReq)
int LSAPI_Release_r(LSAPI_Request *pReq)
int LSAPI_AppendRespHeader_r(LSAPI_Request *pReq, const char *pBuf, int len)
int LSAPI_Is_Listen(void)
void LSAPI_Set_Max_Reqs(int reqs)
int LSAPI_Init_Env_Parameters(fn_select_t fp)
int LSAPI_Set_Restored_Parent_Pid(int pid)
void LSAPI_Set_Server_Max_Idle_Secs(int serverMaxIdle)
int compareValueLocation(const void *v1, const void *v2)
int LSAPI_Init_Prefork_Server(int max_children, fn_select_t fp, int avoidFork)
void lsapi_MD5Init(struct lsapi_MD5Context *context)
int LSAPI_ReqBodyGetLine_r(LSAPI_Request *pReq, char *pBuf, size_t bufLen, int *getLF)
ssize_t LSAPI_sendfile_r(LSAPI_Request *pReq, int fdIn, off_t *off, size_t size)
void LSAPI_Set_Max_Idle_Children(int maxIdleChld)
int LSAPI_IsRunning(void)
struct _lsapi_prefork_server lsapi_prefork_server
int LSAPI_ForeachHeader_r(LSAPI_Request *pReq, LSAPI_CB_EnvHandler fn, void *arg)
int LSAPI_is_suEXEC_Daemon(void)
int LSAPI_Postfork_Child(LSAPI_Request *pReq)
int LSAPI_Finish_r(LSAPI_Request *pReq)
void Flush_RespBuf_r(LSAPI_Request *pReq)
#define LSAPI_ST_RESP_HEADER
void(* sighandler_t)(int)
struct lsapi_MD5Context lsapi_MD5_CTX
int LSAPI_Postfork_Parent(LSAPI_Request *pReq)
int LSAPI_ErrResponse_r(LSAPI_Request *pReq, int code, const char **pRespHeaders, const char *pBody, int bodyLen)
void LSAPI_No_Check_ppid(void)
#define LSAPI_ST_REQ_HEADER
void LSAPI_Set_Max_Children(int maxChildren)
int LSAPI_Inc_Req_Processed(int cnt)
void LSAPI_Set_Slow_Req_Msecs(int msecs)
int LSAPI_ReqBodyGetChar_r(LSAPI_Request *pReq)
void LSAPI_Log(int flag, const char *fmt,...)
void LSAPI_reset_server_state(void)
int LSAPI_FinalizeRespHeaders_r(LSAPI_Request *pReq)
int LSAPI_Is_Listen_r(LSAPI_Request *pReq)
int LSAPI_AppendRespHeader2_r(LSAPI_Request *pReq, const char *pHeaderName, const char *pHeaderValue)
void lsapi_MD5Update(struct lsapi_MD5Context *context, unsigned char const *buf, unsigned len)
void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *context)
int LSAPI_Prefork_Accept_r(LSAPI_Request *pReq)
int LSAPI_CreateListenSock(const char *pBind, int backlog)
int LSAPI_Get_Slow_Req_Msecs(void)
int LSAPI_InitRequest(LSAPI_Request *pReq, int fd)
#define LSAPI_RESP_BUF_SIZE
void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf cb)
void LSAPI_Set_Max_Idle(int secs)
int LSAPI_ParseSockAddr(const char *pBind, struct sockaddr *pAddr)
void LSAPI_Set_Max_Process_Time(int secs)
#define LSAPI_INIT_RESP_HEADER_LEN
void LSAPI_Set_Server_fd(int fd)
int LSAPI_ForeachEnv_r(LSAPI_Request *pReq, LSAPI_CB_EnvHandler fn, void *arg)
char * LSAPI_GetHeader_r(LSAPI_Request *pReq, int headerIndex)
#define LSAPI_ST_BACKGROUND
void lsapi_perror(const char *pMessage, int err_no)
void set_skip_write(void)
ssize_t LSAPI_Write_r(LSAPI_Request *pReq, const char *pBuf, size_t len)
int LSAPI_Flush_r(LSAPI_Request *pReq)
void LSAPI_Reset_r(LSAPI_Request *pReq)
int LSAPI_Accept_Before_Fork(LSAPI_Request *pReq)
int is_enough_free_mem(void)
int LSAPI_End_Response_r(LSAPI_Request *pReq)
#define LSAPI_LOG_TIMESTAMP_HMS
#define LSAPI_MAX_RESP_HEADERS
#define LSAPI_LOG_TIMESTAMP_FULL
int(* LSAPI_CB_EnvHandler)(const char *pKey, int keyLen, const char *pValue, int valLen, void *arg)
#define LSAPI_LOG_TIMESTAMP_BITS
struct lsapi_request LSAPI_Request
#define LSAPI_LOG_LEVEL_BITS
void(* LSAPI_On_Timer_pf)(int *forked_child_pid)
int(* fn_select_t)(int, fd_set *, fd_set *, fd_set *, struct timeval *)
#define LSAPI_LOG_FLAG_FATAL
unsigned const char * end
lsapi_child_status * m_pChildrenStatusCur
int m_iChildrenMaxIdleTime
lsapi_child_status * m_pChildrenStatus
lsapi_child_status * m_pChildrenStatusEnd
volatile char m_inProcess
volatile long m_tmWaitBegin
volatile long m_tmLastCheckPoint
volatile int m_iReqCounter
volatile short m_iKillSent
volatile long m_tmReqBegin
struct lsapi_req_header * m_pHeader
short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS]
struct iovec * m_pIovecCur
struct lsapi_child_status * child_status
struct iovec * m_pIovecToWrite
struct iovec * m_pIovecEnd
char * m_pRespHeaderBufPos
struct lsapi_resp_header m_respHeader
struct lsapi_http_header_index * m_pHeaderIndex
struct lsapi_packet_header * m_respPktHeaderEnd
struct lsapi_packet_header m_respPktHeader[5]
struct LSAPI_key_value_pair * m_pSpecialEnvList
struct LSAPI_key_value_pair * m_pEnvList
char * m_pRespHeaderBufEnd
struct lsapi_header_offset * m_pUnknownHeader
strncmp(string $string1, string $string2, int $length)
exit(string|int $status=0)
strcmp(string $string1, string $string2)
#define strcasecmp(s1, s2)
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
fbc internal_function handler(call, ret)